Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6223 lines
219 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. devdrv.c
  5. Abstract:
  6. Device Installer routines dealing with driver information lists
  7. Author:
  8. Lonny McMichael (lonnym) 5-July-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // Global list containing nodes for each HDEVINFO currently involved in building
  15. // a driver list.
  16. //
  17. DRVSEARCH_INPROGRESS_LIST GlobalDrvSearchInProgressList;
  18. typedef struct _DRVLIST_TO_APPEND {
  19. PDRIVER_NODE DriverHead;
  20. PDRIVER_NODE DriverTail;
  21. UINT DriverCount;
  22. } DRVLIST_TO_APPEND, *PDRVLIST_TO_APPEND;
  23. //
  24. // Private function prototypes
  25. //
  26. BOOL
  27. DrvSearchCallback(
  28. IN PSETUP_LOG_CONTEXT LogContext,
  29. IN PCTSTR InfName,
  30. IN PLOADED_INF pInf,
  31. IN BOOL PnfWasUsed,
  32. IN PVOID Context
  33. );
  34. BOOL
  35. pSetupFillInHardwareAndCompatIds(
  36. PDEVINFO_ELEM DevInfoElem,
  37. HMACHINE hMachine,
  38. PDRVSEARCH_CONTEXT DrvSearchContext,
  39. PSETUP_LOG_CONTEXT LogContext
  40. );
  41. LONG
  42. pSetupGetInstalledDriverInfo(
  43. IN HDEVINFO DeviceInfoSet,
  44. IN PSP_DEVINFO_DATA DeviceInfoData,
  45. PDRVSEARCH_CONTEXT DrvSearchContext
  46. );
  47. BOOL
  48. pSetupTestIsInstalledDriver(
  49. IN PCTSTR Description,
  50. IN PCTSTR MfgName,
  51. IN PCTSTR ProviderName,
  52. IN PCTSTR InfSection,
  53. IN PCTSTR InfSectionExt,
  54. IN PDRVSEARCH_CONTEXT Context
  55. );
  56. UINT
  57. pSetupTestDevCompat(
  58. IN PLOADED_INF Inf,
  59. IN PINF_LINE InfLine,
  60. IN PDRVSEARCH_CONTEXT Context,
  61. OUT PLONG MatchIndex
  62. );
  63. BOOL
  64. pSetupGetDeviceIDs(
  65. IN OUT PDRIVER_NODE DriverNode,
  66. IN PLOADED_INF Inf,
  67. IN PINF_LINE InfLine,
  68. IN OUT PVOID StringTable,
  69. IN PINF_SECTION CtlFlagsSection OPTIONAL
  70. );
  71. BOOL
  72. pSetupShouldDevBeExcluded(
  73. IN PCTSTR DeviceId,
  74. IN PLOADED_INF Inf,
  75. IN PINF_SECTION CtlFlagsSection,
  76. OUT PBOOL ArchitectureSpecificExclude OPTIONAL
  77. );
  78. BOOL
  79. pSetupDoesInfContainDevIds(
  80. IN PLOADED_INF Inf,
  81. IN PDRVSEARCH_CONTEXT Context
  82. );
  83. VOID
  84. pSetupMergeDriverNode(
  85. IN OUT PDRVSEARCH_CONTEXT Context,
  86. IN PDRIVER_NODE NewDriverNode,
  87. OUT PBOOL InsertedAtHead
  88. );
  89. DWORD
  90. BuildCompatListFromClassList(
  91. IN PDRIVER_NODE ClassDriverList,
  92. IN OUT PDRVSEARCH_CONTEXT Context
  93. );
  94. BOOL
  95. pSetupCalculateRankMatch(
  96. IN LONG DriverHwOrCompatId,
  97. IN UINT InfFieldIndex,
  98. IN LONG DevIdList[2][MAX_HCID_COUNT+1], // Must be same dimension as in DRVSEARCH_CONTEXT!!!
  99. OUT PUINT Rank
  100. );
  101. BOOL
  102. pSetupIsSimilarDriver(
  103. IN PCTSTR DriverHwOrCompatId,
  104. IN UINT InfFieldIndex,
  105. IN PDRVSEARCH_CONTEXT Context
  106. );
  107. BOOL
  108. pSetupExcludeId(
  109. IN PSETUP_LOG_CONTEXT LogContext,
  110. IN PLOADED_INF Inf,
  111. IN PCTSTR InfName,
  112. IN PCTSTR InfSection,
  113. IN PDRVSEARCH_CONTEXT Context
  114. );
  115. PDRIVER_NODE
  116. DuplicateDriverNode(
  117. IN PDRIVER_NODE DriverNode
  118. );
  119. BOOL
  120. ExtractDrvSearchInProgressNode(
  121. PDRVSEARCH_INPROGRESS_NODE Node
  122. );
  123. //
  124. // Define Flags(Ex) bitmask that are inherited along with a class driver list.
  125. //
  126. #define INHERITED_FLAGS ( DI_ENUMSINGLEINF \
  127. | DI_DIDCLASS \
  128. | DI_MULTMFGS \
  129. | DI_COMPAT_FROM_CLASS )
  130. #define INHERITED_FLAGSEX ( DI_FLAGSEX_DIDINFOLIST \
  131. | DI_FLAGSEX_FILTERCLASSES \
  132. | DI_FLAGSEX_USEOLDINFSEARCH \
  133. | DI_FLAGSEX_OLDINF_IN_CLASSLIST \
  134. | DI_FLAGSEX_DRIVERLIST_FROM_URL \
  135. | DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS \
  136. | DI_FLAGSEX_FILTERSIMILARDRIVERS \
  137. | DI_FLAGSEX_INSTALLEDDRIVER)
  138. BOOL
  139. WINAPI
  140. SetupDiBuildDriverInfoList(
  141. IN HDEVINFO DeviceInfoSet,
  142. IN OUT PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  143. IN DWORD DriverType
  144. )
  145. /*++
  146. Routine Description:
  147. This routine builds a list of drivers associated with a specified device
  148. instance (or with the device information set's global class driver list).
  149. These drivers may be either class drivers or device drivers.
  150. Arguments:
  151. DeviceInfoSet - Supplies a handle to a device information set that will
  152. contain the driver information list (either globally for all members,
  153. or specifically for a single member).
  154. DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
  155. structure for the device information element to build a driver list
  156. for. If this parameter is NULL, then the list will be associated
  157. with the device information set itself, and not with any particular
  158. device information element. This is only for driver lists of type
  159. SPDIT_CLASSDRIVER.
  160. If the class of this device is updated as a result of building a
  161. compatible driver list, then the ClassGuid field of this structure
  162. will be updated upon return.
  163. DriverType - Specifies what type of driver list should be built. Must be
  164. one of the following values:
  165. SPDIT_CLASSDRIVER -- Build a list of class drivers.
  166. SPDIT_COMPATDRIVER -- Build a list of compatible drivers for this device.
  167. DeviceInfoData must be specified if this value is
  168. used.
  169. Return Value:
  170. If the function succeeds, the return value is TRUE.
  171. If the function fails, the return value is FALSE. To get extended error
  172. information, call GetLastError.
  173. Remarks:
  174. After this API has built the specified driver list, its constituent elements
  175. may be enumerated via SetupDiEnumDriverInfo.
  176. If the driver list is associated with a device instance (i.e., DeviceInfoData
  177. is specified), the resulting list will be composed of drivers that have the
  178. same class as the device instance with which they are associated. If this
  179. is a global class driver list (i.e., DriverType is SPDIT_CLASSDRIVER and
  180. DeviceInfoData is not specified), then the class that will be used in
  181. building the list will be the class associated with the device information
  182. set itself. If there is no associated class, then drivers of all classes
  183. will be used in building the list.
  184. Another thread may abort the building of a driver list by calling
  185. SetupDiCancelDriverInfoSearch().
  186. Building a driver info list invalidates and merging it with an existing list
  187. (e.g., via the DI_FLAGSEX_APPENDDRIVERLIST flag) invalidates the drivernode
  188. enumeration hint for that driver list.
  189. --*/
  190. {
  191. PDEVICE_INFO_SET pDeviceInfoSet;
  192. DWORD Err, i;
  193. PDEVINFO_ELEM DevInfoElem = NULL;
  194. HWND hwndParent;
  195. PDWORD pFlags, pFlagsEx;
  196. PTSTR TempBuffer = NULL; // also holds other strings, but this value is largest
  197. ULONG TempBufferLen;
  198. ULONG TempBufferSize = REGSTR_VAL_MAX_HCID_LEN;
  199. PTSTR InfPath = NULL;
  200. PDRVSEARCH_CONTEXT DrvSearchContext = NULL;
  201. LPGUID ClassGuid;
  202. PDRIVER_NODE DriverNode, NextDriverNode;
  203. LONG MfgNameId, InfPathId = -1;
  204. PDRIVER_LIST_OBJECT ClassDriverListObject = NULL;
  205. BOOL HasDrvSearchInProgressLock = FALSE;
  206. DRVSEARCH_INPROGRESS_NODE DrvSearchInProgressNode;
  207. BOOL PartialDrvListCleanUp = FALSE;
  208. HKEY hKey;
  209. BOOL AppendingDriverLists;
  210. DRVLIST_TO_APPEND DrvListToAppend;
  211. BOOL DriverNodeInsertedAtHead;
  212. PSETUP_LOG_CONTEXT LogContext = NULL;
  213. HINSTANCE hInstanceCDM = NULL;
  214. HANDLE hCDMContext = NULL;
  215. HSPFILEQ UserFileQ;
  216. SPFUSIONINSTANCE spFusionInstance;
  217. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  218. SetLastError(ERROR_INVALID_HANDLE);
  219. return FALSE;
  220. }
  221. DrvSearchInProgressNode.SearchCancelledEvent = NULL;
  222. hKey = INVALID_HANDLE_VALUE;
  223. AppendingDriverLists = FALSE;
  224. TempBuffer = MyMalloc(TempBufferSize*sizeof(TCHAR));
  225. if(!TempBuffer) {
  226. Err = ERROR_NOT_ENOUGH_MEMORY;
  227. goto final;
  228. }
  229. DrvSearchContext = MyMalloc(sizeof(DRVSEARCH_CONTEXT));
  230. if(!DrvSearchContext) {
  231. Err = ERROR_NOT_ENOUGH_MEMORY;
  232. goto final;
  233. }
  234. DrvSearchContext->StringTable = NULL;
  235. DrvSearchContext->Flags = 0;
  236. DrvSearchContext->hCatAdmin = NULL;
  237. Err = NO_ERROR;
  238. try {
  239. //
  240. // Build the driver list using a duplicate of the string table for the
  241. // device information set. That way, if the driver search is cancelled
  242. // part-way through, we can restore the original string table, without
  243. // all the additional (unused) strings hanging around.
  244. //
  245. if(!(DrvSearchContext->StringTable = pStringTableDuplicate(pDeviceInfoSet->StringTable))) {
  246. Err = ERROR_NOT_ENOUGH_MEMORY;
  247. goto clean0;
  248. }
  249. //
  250. // Store the pointer to the devinfo set in the context structure. We
  251. // need this, so that we can add INF class GUIDs to the set's GUID
  252. // table.
  253. //
  254. DrvSearchContext->DeviceInfoSet = pDeviceInfoSet;
  255. if(DeviceInfoData) {
  256. //
  257. // Then we're working with a driver list for a particular device.
  258. //
  259. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  260. DeviceInfoData,
  261. NULL))) {
  262. Err = ERROR_INVALID_PARAMETER;
  263. goto clean0;
  264. }
  265. } else {
  266. //
  267. // If the caller did not pass in a DeviceInfoData then we can't get
  268. // the currently installed driver since we don't know the device.
  269. //
  270. if(pDeviceInfoSet->InstallParamBlock.FlagsEx & DI_FLAGSEX_INSTALLEDDRIVER) {
  271. Err = ERROR_INVALID_FLAGS;
  272. goto clean0;
  273. }
  274. }
  275. LogContext = DevInfoElem ?
  276. DevInfoElem->InstallParamBlock.LogContext :
  277. pDeviceInfoSet->InstallParamBlock.LogContext;
  278. SetLogSectionName(LogContext, TEXT("Driver Install"));
  279. //
  280. // Now, fill in the rest of our context structure based on what type of
  281. // driver list we're creating.
  282. //
  283. switch(DriverType) {
  284. case SPDIT_CLASSDRIVER :
  285. if(DeviceInfoData) {
  286. //
  287. // Retrieve the list for a particular device.
  288. //
  289. if(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDINFOLIST) {
  290. if(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_APPENDDRIVERLIST) {
  291. AppendingDriverLists = TRUE;
  292. //
  293. // Merging a new driver list into an existing list
  294. // invalidates our drivernode enumeration hint.
  295. //
  296. DevInfoElem->ClassDriverEnumHint = NULL;
  297. DevInfoElem->ClassDriverEnumHintIndex = INVALID_ENUM_INDEX;
  298. } else {
  299. //
  300. // We already have a driver list, and we've not
  301. // been asked to append to it, so we're done.
  302. //
  303. goto clean0;
  304. }
  305. } else {
  306. //
  307. // We don't have a class driver list--we'd better not
  308. // have a drivernode enumeration hint.
  309. //
  310. MYASSERT(DevInfoElem->ClassDriverEnumHint == NULL);
  311. MYASSERT(DevInfoElem->ClassDriverEnumHintIndex == INVALID_ENUM_INDEX);
  312. DrvSearchContext->pDriverListHead = &(DevInfoElem->ClassDriverHead);
  313. DrvSearchContext->pDriverListTail = &(DevInfoElem->ClassDriverTail);
  314. DrvSearchContext->pDriverCount = &(DevInfoElem->ClassDriverCount);
  315. }
  316. pFlags = &(DevInfoElem->InstallParamBlock.Flags);
  317. pFlagsEx = &(DevInfoElem->InstallParamBlock.FlagsEx);
  318. UserFileQ = DevInfoElem->InstallParamBlock.UserFileQ;
  319. ClassGuid = &(DevInfoElem->ClassGuid);
  320. InfPathId = DevInfoElem->InstallParamBlock.DriverPath;
  321. //
  322. // Retrieve the list of Hardware IDs (index 0) and
  323. // Compatible IDs (index 1) from the device's registry properties.
  324. //
  325. if (!pSetupFillInHardwareAndCompatIds(DevInfoElem,
  326. pDeviceInfoSet->hMachine,
  327. DrvSearchContext,
  328. LogContext
  329. )) {
  330. goto clean0;
  331. }
  332. //
  333. // Set DRVSRCH_FILTERSIMILARDRIVERS flag if the
  334. // DI_FLAGSEX_FILTERSIMILARDRIVERS FlagsEx is set. This will
  335. // cause us only to add 'similar' drivers to the class list. A
  336. // 'similar' driver is one where one of the hardware or
  337. // compatible Ids in the INF partially match one of the
  338. // hardware or compatible Ids of the hardware.
  339. //
  340. if (*pFlagsEx & DI_FLAGSEX_FILTERSIMILARDRIVERS) {
  341. DrvSearchContext->Flags |= DRVSRCH_FILTERSIMILARDRIVERS;
  342. //
  343. // If no hardware id or compatible ids found, nothing is compatible.
  344. //
  345. if ((DrvSearchContext->IdList[0][0] == -1) &&
  346. (DrvSearchContext->IdList[1][0] == -1)) {
  347. goto clean1;
  348. }
  349. }
  350. } else {
  351. //
  352. // Retrieve the list for the device information set itself (globally)
  353. //
  354. if(pDeviceInfoSet->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDINFOLIST) {
  355. if(pDeviceInfoSet->InstallParamBlock.FlagsEx & DI_FLAGSEX_APPENDDRIVERLIST) {
  356. AppendingDriverLists = TRUE;
  357. //
  358. // Merging a new driver list into an existing list
  359. // invalidates our drivernode enumeration hint.
  360. //
  361. pDeviceInfoSet->ClassDriverEnumHint = NULL;
  362. pDeviceInfoSet->ClassDriverEnumHintIndex = INVALID_ENUM_INDEX;
  363. } else {
  364. //
  365. // We already have a driver list, and we've not been asked to append
  366. // to it, so we're done.
  367. //
  368. goto clean0;
  369. }
  370. } else {
  371. //
  372. // We don't have a class driver list--we'd better not
  373. // have a drivernode enumeration hint.
  374. //
  375. MYASSERT(pDeviceInfoSet->ClassDriverEnumHint == NULL);
  376. MYASSERT(pDeviceInfoSet->ClassDriverEnumHintIndex == INVALID_ENUM_INDEX);
  377. DrvSearchContext->pDriverListHead = &(pDeviceInfoSet->ClassDriverHead);
  378. DrvSearchContext->pDriverListTail = &(pDeviceInfoSet->ClassDriverTail);
  379. DrvSearchContext->pDriverCount = &(pDeviceInfoSet->ClassDriverCount);
  380. }
  381. pFlags = &(pDeviceInfoSet->InstallParamBlock.Flags);
  382. pFlagsEx = &(pDeviceInfoSet->InstallParamBlock.FlagsEx);
  383. UserFileQ = pDeviceInfoSet->InstallParamBlock.UserFileQ;
  384. ClassGuid = &(pDeviceInfoSet->ClassGuid);
  385. InfPathId = pDeviceInfoSet->InstallParamBlock.DriverPath;
  386. }
  387. if(AppendingDriverLists) {
  388. ZeroMemory(&DrvListToAppend, sizeof(DrvListToAppend));
  389. DrvSearchContext->pDriverListHead = &(DrvListToAppend.DriverHead);
  390. DrvSearchContext->pDriverListTail = &(DrvListToAppend.DriverTail);
  391. DrvSearchContext->pDriverCount = &(DrvListToAppend.DriverCount);
  392. }
  393. DrvSearchContext->BuildClassDrvList = TRUE;
  394. //
  395. // Class driver lists are always filtered on class.
  396. //
  397. DrvSearchContext->Flags |= DRVSRCH_FILTERCLASS;
  398. //
  399. // Set the DRVSRCH_NO_CLASSLIST_NODE_MERGE flag in the DrvSearchContext
  400. // if the caller set the DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE. If this
  401. // flag is set then we will not remove/merge identical driver nodes.
  402. //
  403. if (*pFlagsEx & DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE) {
  404. DrvSearchContext->Flags |= DRVSRCH_NO_CLASSLIST_NODE_MERGE;
  405. }
  406. break;
  407. case SPDIT_COMPATDRIVER :
  408. if(DeviceInfoData) {
  409. if(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDCOMPATINFO) {
  410. if(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_APPENDDRIVERLIST) {
  411. AppendingDriverLists = TRUE;
  412. //
  413. // Merging a new driver list into an existing list
  414. // invalidates our drivernode enumeration hint.
  415. //
  416. DevInfoElem->CompatDriverEnumHint = NULL;
  417. DevInfoElem->CompatDriverEnumHintIndex = INVALID_ENUM_INDEX;
  418. } else {
  419. //
  420. // We already have a driver list, and we've not been asked to append
  421. // to it, so we're done.
  422. //
  423. goto clean0;
  424. }
  425. } else {
  426. //
  427. // We don't have a compatible driver list--we'd better
  428. // not have a drivernode enumeration hint.
  429. //
  430. MYASSERT(DevInfoElem->CompatDriverEnumHint == NULL);
  431. MYASSERT(DevInfoElem->CompatDriverEnumHintIndex == INVALID_ENUM_INDEX);
  432. }
  433. //
  434. // NOTE: The following variables must be set before retrieving the
  435. // hardware/compatible ID lists, as execution may transfer to the
  436. // 'clean1' label, that relies on these values.
  437. //
  438. pFlags = &(DevInfoElem->InstallParamBlock.Flags);
  439. pFlagsEx = &(DevInfoElem->InstallParamBlock.FlagsEx);
  440. UserFileQ = DevInfoElem->InstallParamBlock.UserFileQ;
  441. DrvSearchContext->BuildClassDrvList = FALSE;
  442. //
  443. // We're building a compatible driver list--retrieve the list of Hardware IDs
  444. // (index 0) and Compatible IDs (index 1) from the device's registry properties.
  445. //
  446. if (!pSetupFillInHardwareAndCompatIds(DevInfoElem,
  447. pDeviceInfoSet->hMachine,
  448. DrvSearchContext,
  449. LogContext
  450. )) {
  451. goto clean0;
  452. }
  453. //
  454. // If no hardware id or compatible ids found, nothing is compatible.
  455. //
  456. if ((DrvSearchContext->IdList[0][0] == -1) &&
  457. (DrvSearchContext->IdList[1][0] == -1)) {
  458. goto clean1;
  459. }
  460. //
  461. // Compatible driver lists are filtered on class only if the
  462. // DI_FLAGSEX_USECLASSFORCOMPAT flag is set.
  463. //
  464. DrvSearchContext->Flags |= (*pFlagsEx & DI_FLAGSEX_USECLASSFORCOMPAT)
  465. ? DRVSRCH_FILTERCLASS : 0;
  466. ClassGuid = &(DevInfoElem->ClassGuid);
  467. if(AppendingDriverLists) {
  468. ZeroMemory(&DrvListToAppend, sizeof(DrvListToAppend));
  469. DrvSearchContext->pDriverListHead = &(DrvListToAppend.DriverHead);
  470. DrvSearchContext->pDriverListTail = &(DrvListToAppend.DriverTail);
  471. DrvSearchContext->pDriverCount = &(DrvListToAppend.DriverCount);
  472. } else {
  473. DrvSearchContext->pDriverListHead = &(DevInfoElem->CompatDriverHead);
  474. DrvSearchContext->pDriverListTail = &(DevInfoElem->CompatDriverTail);
  475. DrvSearchContext->pDriverCount = &(DevInfoElem->CompatDriverCount);
  476. }
  477. if(*pFlags & DI_COMPAT_FROM_CLASS) {
  478. PDRIVER_LIST_OBJECT TempDriverListObject;
  479. //
  480. // The caller wants to build the compatible driver list based on an
  481. // existing class driver list--first make sure that there _is_ a class
  482. // driver list.
  483. //
  484. if(!(*pFlagsEx & DI_FLAGSEX_DIDINFOLIST)) {
  485. Err = ERROR_NO_CLASS_DRIVER_LIST;
  486. goto clean0;
  487. } else if(!(DevInfoElem->ClassDriverHead)) {
  488. //
  489. // Then the class driver list is empty. There's no need to do
  490. // any more work, just say that we succeeded.
  491. //
  492. Err = NO_ERROR;
  493. goto clean1;
  494. }
  495. //
  496. // When we're building a compatible driver list from an existing class
  497. // driver list, we don't do any checking on INF class (i.e., to update
  498. // the device's class if the most-compatible driver is of a different
  499. // device class). Because of this, we must ensure that (a) the class
  500. // driver list was built for a particular class, and that (b) that class
  501. // matches the current class for this device.
  502. //
  503. TempDriverListObject = GetAssociatedDriverListObject(
  504. pDeviceInfoSet->ClassDrvListObjectList,
  505. DevInfoElem->ClassDriverHead,
  506. NULL
  507. );
  508. MYASSERT(TempDriverListObject);
  509. //
  510. // Everything's in order--go search through the existing
  511. // class driver list for compatible drivers.
  512. //
  513. if((Err = BuildCompatListFromClassList(DevInfoElem->ClassDriverHead,
  514. DrvSearchContext)) == NO_ERROR) {
  515. goto clean2;
  516. } else {
  517. goto clean0;
  518. }
  519. } else {
  520. InfPathId = DevInfoElem->InstallParamBlock.DriverPath;
  521. }
  522. break;
  523. }
  524. //
  525. // If no device instance specified, let fall through to error.
  526. //
  527. default :
  528. Err = ERROR_INVALID_PARAMETER;
  529. goto clean0;
  530. }
  531. if(IsEqualGUID(ClassGuid, &GUID_NULL)) {
  532. //
  533. // If there is no class GUID, then don't try to filter on it.
  534. //
  535. DrvSearchContext->Flags &= ~DRVSRCH_FILTERCLASS;
  536. } else {
  537. //
  538. // Copy the class GUID to the ClassGuid field in our context structure.
  539. //
  540. CopyMemory(&(DrvSearchContext->ClassGuid),
  541. ClassGuid,
  542. sizeof(GUID)
  543. );
  544. DrvSearchContext->Flags |= DRVSRCH_HASCLASSGUID;
  545. //
  546. // If we are building a class list, and filtering is requested,
  547. // then make sure that the class doesn't have NoUseClass value
  548. // entries in its registry key.
  549. //
  550. // Also exclude NoInstallClass unless the
  551. // DI_FLAGSEX_ALLOWEXCLUDEDDRVS flag is set.
  552. //
  553. if(DrvSearchContext->BuildClassDrvList &&
  554. (*pFlagsEx & DI_FLAGSEX_FILTERCLASSES)) {
  555. if(ShouldClassBeExcluded(&(DrvSearchContext->ClassGuid), !(*pFlagsEx & DI_FLAGSEX_ALLOWEXCLUDEDDRVS))) {
  556. //
  557. // If the class has been filtered out, simply return success.
  558. //
  559. goto clean1;
  560. }
  561. }
  562. //
  563. // If we're going to be filtering on this class, then store its
  564. // string representation in the context structure as well, as an
  565. // optimization for PreprocessInf().
  566. //
  567. if(DrvSearchContext->Flags & DRVSRCH_FILTERCLASS) {
  568. pSetupStringFromGuid(ClassGuid,
  569. DrvSearchContext->ClassGuidString,
  570. SIZECHARS(DrvSearchContext->ClassGuidString)
  571. );
  572. }
  573. }
  574. //
  575. // If we're supposed to do our driver search based on an alternate
  576. // (i.e., non-native) platform, then store that information away in our
  577. // context structure.
  578. //
  579. if(*pFlagsEx & DI_FLAGSEX_ALTPLATFORM_DRVSEARCH) {
  580. //
  581. // We must have a user-supplied file queue.
  582. //
  583. MYASSERT(*pFlags & DI_NOVCP);
  584. MYASSERT(UserFileQ && (UserFileQ != INVALID_HANDLE_VALUE));
  585. if((((PSP_FILE_QUEUE)UserFileQ)->Signature != SP_FILE_QUEUE_SIG) ||
  586. !(((PSP_FILE_QUEUE)UserFileQ)->Flags & FQF_USE_ALT_PLATFORM)) {
  587. Err = ERROR_INVALID_PARAMETER;
  588. WriteLogEntry(
  589. LogContext,
  590. DRIVER_LOG_WARNING,
  591. MSG_LOG_NO_QUEUE_FOR_ALTPLATFORM_DRVSEARCH,
  592. NULL
  593. );
  594. goto clean0;
  595. }
  596. DrvSearchContext->AltPlatformInfo =
  597. &(((PSP_FILE_QUEUE)UserFileQ)->AltPlatformInfo);
  598. } else {
  599. //
  600. // We're not doing a non-native driver search...
  601. //
  602. DrvSearchContext->AltPlatformInfo = NULL;
  603. }
  604. if(DrvSearchContext->BuildClassDrvList) {
  605. //
  606. // Allocate a new driver list object to store the class driver list in once
  607. // we've created it. (Don't do this if we're appending driver lists.)
  608. //
  609. if(!AppendingDriverLists) {
  610. if(!(ClassDriverListObject = MyMalloc(sizeof(DRIVER_LIST_OBJECT)))) {
  611. Err = ERROR_NOT_ENOUGH_MEMORY;
  612. goto clean0;
  613. }
  614. }
  615. //
  616. // If the user wants to allow legacy INFs to be searched, then we need to
  617. // figure out what the legacy option name is.
  618. //
  619. if(*pFlagsEx & DI_FLAGSEX_OLDINF_IN_CLASSLIST) {
  620. DWORD RegDataType, RegDataSize;
  621. //
  622. // Don't allow this if we don't know what class we're building the list for.
  623. //
  624. if(!(DrvSearchContext->Flags & DRVSRCH_FILTERCLASS)) {
  625. Err = ERROR_NO_ASSOCIATED_CLASS;
  626. goto clean0;
  627. }
  628. //
  629. // Check to see if there's a legacy INF option name translation stored in
  630. // the class key for this class.
  631. //
  632. *DrvSearchContext->LegacyClassName = TEXT('\0');
  633. if((hKey = SetupDiOpenClassRegKey(ClassGuid, KEY_READ)) != INVALID_HANDLE_VALUE) {
  634. RegDataSize = sizeof(DrvSearchContext->LegacyClassName);
  635. if((RegQueryValueEx(hKey,
  636. pszLegacyInfOption,
  637. NULL,
  638. &RegDataType,
  639. (PBYTE)DrvSearchContext->LegacyClassName,
  640. &RegDataSize) != ERROR_SUCCESS) ||
  641. (RegDataType != REG_SZ) || (RegDataSize < sizeof(TCHAR))) {
  642. //
  643. // No luck finding a legacy option name translation--make sure
  644. // this string is still empty.
  645. //
  646. *DrvSearchContext->LegacyClassName = TEXT('\0');
  647. }
  648. RegCloseKey(hKey);
  649. hKey = INVALID_HANDLE_VALUE;
  650. }
  651. if(!(*DrvSearchContext->LegacyClassName)) {
  652. //
  653. // We didn't find a translation for the option, so assume it's the
  654. // same as its Plug&Play class name.
  655. //
  656. if(!SetupDiClassNameFromGuid(ClassGuid,
  657. DrvSearchContext->LegacyClassName,
  658. SIZECHARS(DrvSearchContext->LegacyClassName),
  659. NULL)) {
  660. //
  661. // We can't get the name of this class--maybe it's not installed. In
  662. // any event, we can't proceed without this information.
  663. //
  664. Err = ERROR_INVALID_CLASS;
  665. goto clean0;
  666. }
  667. }
  668. LoadString(MyDllModuleHandle,
  669. IDS_LEGACYINFLANG,
  670. DrvSearchContext->LegacyClassLang,
  671. SIZECHARS(DrvSearchContext->LegacyClassLang)
  672. );
  673. DrvSearchContext->Flags |= DRVSRCH_USEOLDINFS;
  674. }
  675. }
  676. //
  677. // Only include ExcludeFromSelect devices and NoInstallClass classes
  678. // if the DI_FLAGSEX_ALLOWEXCLUDEDDRVS flag is set.
  679. //
  680. if (*pFlagsEx & DI_FLAGSEX_ALLOWEXCLUDEDDRVS) {
  681. DrvSearchContext->Flags |= DRVSRCH_ALLOWEXCLUDEDDRVS;
  682. }
  683. //
  684. // If the caller just wants us to get the currently installed driver then
  685. // we need to get the INF path of the currently installed driver.
  686. //
  687. if (*pFlagsEx & DI_FLAGSEX_INSTALLEDDRIVER) {
  688. DrvSearchContext->Flags |= DRVSRCH_INSTALLEDDRIVER;
  689. InfPathId = pSetupGetInstalledDriverInfo(DeviceInfoSet,
  690. DeviceInfoData,
  691. DrvSearchContext
  692. );
  693. //
  694. // If the InfPathId is -1 then we were unable to get the InfPath
  695. // for this device. This is most likely because this is a new
  696. // device or the device doesn't currently have a driver installed
  697. // on it. In any case there is nothing to do here so just return
  698. // success.
  699. //
  700. if (InfPathId == -1) {
  701. Err = NO_ERROR;
  702. goto clean1;
  703. }
  704. }
  705. //
  706. // Set up a "Driver Search In-Progress" node in the global list, that will be
  707. // used in case some other thread wants us to abort part-way through.
  708. //
  709. if(LockDrvSearchInProgressList(&GlobalDrvSearchInProgressList)) {
  710. HasDrvSearchInProgressLock = TRUE;
  711. if(DrvSearchInProgressNode.SearchCancelledEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) {
  712. DrvSearchInProgressNode.CancelSearch = FALSE;
  713. DrvSearchInProgressNode.DeviceInfoSet = DeviceInfoSet;
  714. DrvSearchInProgressNode.Next = GlobalDrvSearchInProgressList.DrvSearchHead;
  715. GlobalDrvSearchInProgressList.DrvSearchHead = &DrvSearchInProgressNode;
  716. Err = NO_ERROR;
  717. } else {
  718. Err = GetLastError();
  719. }
  720. UnlockDrvSearchInProgressList(&GlobalDrvSearchInProgressList);
  721. HasDrvSearchInProgressLock = FALSE;
  722. if(Err != NO_ERROR) {
  723. goto clean0;
  724. }
  725. } else {
  726. //
  727. // The only reason this should happen is if we're in the middle of DLL_PROCESS_DETACH,
  728. // and the list has already been destroyed.
  729. //
  730. Err = ERROR_INVALID_DATA;
  731. goto clean0;
  732. }
  733. //
  734. // Now store away a pointer to the 'CancelSearch' flag in our context structure, so that
  735. // we can check it periodically while building the driver list (specifically, we check it
  736. // before examining each INF).
  737. //
  738. DrvSearchContext->CancelSearch = &(DrvSearchInProgressNode.CancelSearch);
  739. PartialDrvListCleanUp = TRUE; // after this point, clean-up is necessary upon exception.
  740. //
  741. // First see if we need to get the driver package from the Internet
  742. //
  743. if (*pFlagsEx & DI_FLAGSEX_DRIVERLIST_FROM_URL) {
  744. #ifdef UNICODE
  745. //
  746. // Currently this is not supported, but in the future we might allow
  747. // alternate Internet servers were users can get driver updates.
  748. //
  749. if (InfPathId != -1) {
  750. //
  751. // No InfPath was specified so we will go to the Microsoft Windows
  752. // Update server.
  753. //
  754. Err = ERROR_INVALID_PARAMETER;
  755. goto clean0;
  756. } else {
  757. OSVERSIONINFOEX info;
  758. DOWNLOADINFO DownloadInfo;
  759. TCHAR CDMPath[MAX_PATH];
  760. TCHAR DeviceInstanceId[MAX_DEVICE_ID_LEN];
  761. ULONG BufferLen;
  762. OPEN_CDM_CONTEXT_PROC pfnOpenCDMContext;
  763. CLOSE_CDM_CONTEXT_PROC pfnCloseCDMContext;
  764. DOWNLOAD_UPDATED_FILES_PROC pfnDownloadUpdatedFiles;
  765. //
  766. // Search Windows Update for all SKUs except datacenter.
  767. //
  768. info.dwOSVersionInfoSize = sizeof(info);
  769. if (GetVersionEx((POSVERSIONINFOW)&info) &&
  770. !(info.wSuiteMask & VER_SUITE_DATACENTER)) {
  771. spFusionEnterContext(NULL,&spFusionInstance);
  772. if(hInstanceCDM = LoadLibrary(TEXT("CDM.DLL"))) {
  773. if((pfnOpenCDMContext =
  774. (OPEN_CDM_CONTEXT_PROC)GetProcAddress(hInstanceCDM, "OpenCDMContext")) &&
  775. (pfnCloseCDMContext =
  776. (CLOSE_CDM_CONTEXT_PROC)GetProcAddress(hInstanceCDM, "CloseCDMContext")) &&
  777. (pfnDownloadUpdatedFiles =
  778. (DOWNLOAD_UPDATED_FILES_PROC)GetProcAddress(hInstanceCDM, "DownloadUpdatedFiles"))) {
  779. if (hCDMContext = pfnOpenCDMContext(DevInfoElem->InstallParamBlock.hwndParent)) {
  780. //
  781. // Fill In the DOWNLOADINFO structure to pass to CDM.DLL
  782. //
  783. ZeroMemory(&DownloadInfo, sizeof(DOWNLOADINFO));
  784. DownloadInfo.dwDownloadInfoSize = sizeof(DOWNLOADINFO);
  785. DownloadInfo.lpFile = NULL;
  786. if(CM_Get_Device_ID_Ex(DevInfoElem->DevInst,
  787. DeviceInstanceId,
  788. sizeof(DeviceInstanceId)/sizeof(TCHAR),
  789. 0,
  790. pDeviceInfoSet->hMachine
  791. ) != CR_SUCCESS) {
  792. //
  793. // This should never happen!
  794. //
  795. Err = ERROR_NO_SUCH_DEVINST;
  796. } else {
  797. DownloadInfo.lpDeviceInstanceID = (LPCWSTR)DeviceInstanceId;
  798. GetVersionEx((OSVERSIONINFOW *)&DownloadInfo.OSVersionInfo);
  799. //
  800. // Set dwArchitecture to PROCESSOR_ARCHITECTURE_UNKNOWN, this
  801. // causes Windows Update to check get the architecture of the
  802. // machine itself. You only need to explictly set the value if
  803. // you want to download drivers for a different architecture then
  804. // the machine this is running on.
  805. //
  806. DownloadInfo.dwArchitecture = PROCESSOR_ARCHITECTURE_UNKNOWN;
  807. DownloadInfo.dwFlags = 0;
  808. DownloadInfo.dwClientID = 0;
  809. DownloadInfo.localid = 0;
  810. CDMPath[0] = TEXT('\0');
  811. //
  812. // Tell CDM.DLL to download any driver packages it has that match the
  813. // Hardware or Compatible IDs for this device.
  814. //
  815. if ((pfnDownloadUpdatedFiles(hCDMContext,
  816. DevInfoElem->InstallParamBlock.hwndParent,
  817. &DownloadInfo,
  818. CDMPath,
  819. sizeof(CDMPath),
  820. &BufferLen)) &&
  821. (CDMPath[0] != TEXT('\0'))) {
  822. //
  823. // Windows Update found a driver package so enumerate all of
  824. // the INFs in the specified directory
  825. //
  826. DrvSearchContext->Flags |= (DRVSRCH_FROM_INET | DRVSRCH_CLEANUP_SOURCE_PATH);
  827. spFusionLeaveContext(&spFusionInstance);
  828. Err = EnumDrvInfsInDirPathList(CDMPath,
  829. INFINFO_INF_PATH_LIST_SEARCH,
  830. DrvSearchCallback,
  831. TRUE,
  832. LogContext,
  833. (PVOID)DrvSearchContext
  834. );
  835. spFusionEnterContext(NULL,&spFusionInstance);
  836. }
  837. }
  838. pfnCloseCDMContext(hCDMContext);
  839. hCDMContext = NULL;
  840. }
  841. }
  842. FreeLibrary(hInstanceCDM);
  843. hInstanceCDM = NULL;
  844. }
  845. spFusionLeaveContext(&spFusionInstance);
  846. }
  847. }
  848. #else
  849. Err = ERROR_INVALID_PARAMETER;
  850. goto clean0;
  851. #endif
  852. }
  853. //
  854. // Now, retrieve the driver list.
  855. //
  856. else if((*pFlagsEx & DI_FLAGSEX_USEOLDINFSEARCH) || (InfPathId != -1)) {
  857. //
  858. // If this driver came from the Internet then set the
  859. // DRVSRCH_FROM_INET flag
  860. //
  861. if (*pFlagsEx & DI_FLAGSEX_INET_DRIVER) {
  862. DrvSearchContext->Flags |= DRVSRCH_FROM_INET;
  863. }
  864. InfPath = pStringTableStringFromId(DrvSearchContext->StringTable,
  865. InfPathId
  866. );
  867. if((*pFlags & DI_ENUMSINGLEINF) ||
  868. (*pFlagsEx & DI_FLAGSEX_INSTALLEDDRIVER)) {
  869. if(InfPath) {
  870. Err = NO_ERROR;
  871. if(InfPath == pSetupGetFileTitle(InfPath)) {
  872. //
  873. // The specified INF path is a simple filename.
  874. // Search for it in the directories listed in the
  875. // DevicePath search list. The most likely scenario
  876. // here is that the caller is trying to build a driver
  877. // list based on the INF used previously to install
  878. // the device. In that case, they would've retrieved
  879. // the InfPath value from the device's driver key, and
  880. // this value is a simple filename. INFs are always
  881. // placed into the Inf directory when they're used to
  882. // install a device, so the only valid place to look for
  883. // this INF is in %windir%\Inf.
  884. //
  885. lstrcpyn(TempBuffer, InfDirectory,TempBufferSize);
  886. pSetupConcatenatePaths(TempBuffer,
  887. InfPath,
  888. TempBufferSize,
  889. NULL
  890. );
  891. DrvSearchContext->Flags |= DRVSRCH_TRY_PNF;
  892. } else {
  893. PTSTR DontCare;
  894. //
  895. // The specified INF filename contains more than just
  896. // a filename. Assume it's an absolute path.
  897. //
  898. // (We need to get the fully-qualified form of this path,
  899. // because that's what EnumSingleDrvInf expects.)
  900. //
  901. TempBufferLen = GetFullPathName(InfPath,
  902. TempBufferSize,
  903. TempBuffer,
  904. &DontCare
  905. );
  906. if(!TempBufferLen) {
  907. Err = GetLastError();
  908. } else if(TempBufferLen >= TempBufferSize) {
  909. MYASSERT(0);
  910. Err = ERROR_BUFFER_OVERFLOW;
  911. }
  912. }
  913. if(Err == NO_ERROR) {
  914. WIN32_FIND_DATA InfFileData;
  915. if (FileExists(TempBuffer, &InfFileData)) {
  916. Err = EnumSingleDrvInf(TempBuffer,
  917. &InfFileData,
  918. INFINFO_INF_NAME_IS_ABSOLUTE,
  919. DrvSearchCallback,
  920. LogContext,
  921. (PVOID)DrvSearchContext
  922. );
  923. } else {
  924. Err = GetLastError();
  925. }
  926. }
  927. } else {
  928. Err = ERROR_NO_INF;
  929. }
  930. } else {
  931. Err = EnumDrvInfsInDirPathList(InfPath,
  932. INFINFO_INF_PATH_LIST_SEARCH,
  933. DrvSearchCallback,
  934. TRUE,
  935. LogContext,
  936. (PVOID)DrvSearchContext
  937. );
  938. }
  939. } else {
  940. //
  941. // On Win95, this code path uses an INF index scheme. Since the Setup APIs
  942. // utilize precompiled INFs instead, this 'else' clause is really no different
  943. // than the 'if' part. However, if in the future we decide to do indexing a`la
  944. // Win95, then this is the place where we'd put a call such as:
  945. //
  946. // Err = BuildDrvListFromInfIndex();
  947. //
  948. DrvSearchContext->Flags |= DRVSRCH_TRY_PNF;
  949. //
  950. // If the caller wants to exclude existing (old) Internet
  951. // drivers then set the DRVSRCH_EXCLUDE_OLD_INET_DRIVERS flag.
  952. //
  953. if (*pFlagsEx & DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS) {
  954. DrvSearchContext->Flags |= DRVSRCH_EXCLUDE_OLD_INET_DRIVERS;
  955. }
  956. Err = EnumDrvInfsInDirPathList(NULL,
  957. INFINFO_INF_PATH_LIST_SEARCH,
  958. DrvSearchCallback,
  959. TRUE,
  960. LogContext,
  961. (PVOID)DrvSearchContext
  962. );
  963. }
  964. //
  965. // Extract our node from the "Driver Search In-Progress" list, and signal the waiting
  966. // threads if an abort is pending.
  967. //
  968. if(ExtractDrvSearchInProgressNode(&DrvSearchInProgressNode)) {
  969. Err = ERROR_CANCELLED;
  970. }
  971. if(Err != NO_ERROR) {
  972. if(Err == ERROR_CANCELLED) {
  973. //
  974. // Clean up the partial list we built.
  975. //
  976. DestroyDriverNodes(*(DrvSearchContext->pDriverListHead), pDeviceInfoSet);
  977. *(DrvSearchContext->pDriverListHead) = *(DrvSearchContext->pDriverListTail) = NULL;
  978. *(DrvSearchContext->pDriverCount) = 0;
  979. }
  980. goto clean0;
  981. }
  982. clean2:
  983. if(DrvSearchContext->BuildClassDrvList) {
  984. if(AppendingDriverLists) {
  985. DriverNode = *(DrvSearchContext->pDriverListHead);
  986. //
  987. // Now 'fix up' the driver search context so that it points to the
  988. // real class list fields. That way when we merge the new driver nodes
  989. // into the list, everything will be updated properly.
  990. //
  991. if(DevInfoElem) {
  992. DrvSearchContext->pDriverListHead = &(DevInfoElem->ClassDriverHead);
  993. DrvSearchContext->pDriverListTail = &(DevInfoElem->ClassDriverTail);
  994. DrvSearchContext->pDriverCount = &(DevInfoElem->ClassDriverCount);
  995. } else {
  996. DrvSearchContext->pDriverListHead = &(pDeviceInfoSet->ClassDriverHead);
  997. DrvSearchContext->pDriverListTail = &(pDeviceInfoSet->ClassDriverTail);
  998. DrvSearchContext->pDriverCount = &(pDeviceInfoSet->ClassDriverCount);
  999. }
  1000. //
  1001. // Merge our newly-built driver list with the already-existing one.
  1002. //
  1003. while(DriverNode) {
  1004. //
  1005. // Store a pointer to the next driver node before merging, because
  1006. // the driver node we're working with may be destroyed because it's
  1007. // a duplicate of a driver node already in the list.
  1008. //
  1009. NextDriverNode = DriverNode->Next;
  1010. pSetupMergeDriverNode(DrvSearchContext, DriverNode, &DriverNodeInsertedAtHead);
  1011. DriverNode = NextDriverNode;
  1012. }
  1013. }
  1014. if(DriverNode = *(DrvSearchContext->pDriverListHead)) {
  1015. //
  1016. // Look through the class driver list we just built, and see if
  1017. // all drivers are from the same manufacturer. If not, set the
  1018. // DI_MULTMFGS flag.
  1019. //
  1020. MfgNameId = DriverNode->MfgName;
  1021. for(DriverNode = DriverNode->Next;
  1022. DriverNode;
  1023. DriverNode = DriverNode->Next) {
  1024. if(DriverNode->MfgName != MfgNameId) {
  1025. *pFlags |= DI_MULTMFGS;
  1026. break;
  1027. }
  1028. }
  1029. }
  1030. } else {
  1031. if(AppendingDriverLists) {
  1032. DriverNode = *(DrvSearchContext->pDriverListHead);
  1033. //
  1034. // Now 'fix up' the driver search context so that it points to the
  1035. // real compatible list fields.
  1036. //
  1037. DrvSearchContext->pDriverListHead = &(DevInfoElem->CompatDriverHead);
  1038. DrvSearchContext->pDriverListTail = &(DevInfoElem->CompatDriverTail);
  1039. DrvSearchContext->pDriverCount = &(DevInfoElem->CompatDriverCount);
  1040. //
  1041. // Check the rank of the best-matching driver node in our new list, and see
  1042. // if it's better than the one at the front of the previously-existing list.
  1043. // If so, then we'll want to update the class of this devinfo element to reflect
  1044. // this new class.
  1045. //
  1046. if(DriverNode && DrvSearchContext->Flags & DRVSRCH_HASCLASSGUID) {
  1047. if(DevInfoElem->CompatDriverHead &&
  1048. (DriverNode->Rank >= DevInfoElem->CompatDriverHead->Rank)) {
  1049. //
  1050. // There was already a compatible driver with a better rank match
  1051. // in the list, so don't update the class.
  1052. //
  1053. DrvSearchContext->Flags &= ~DRVSRCH_HASCLASSGUID;
  1054. } else {
  1055. //
  1056. // The head of the new driver list is a better match than any of the
  1057. // entries in the existing list. Make sure that the class of this new
  1058. // driver node 'fits' into the devinfo set/element. (We do this before
  1059. // the actual list merging, so that we don't mess up the original list
  1060. // in case of error).
  1061. //
  1062. if(pDeviceInfoSet->HasClassGuid &&
  1063. !IsEqualGUID(ClassGuid, &(DrvSearchContext->ClassGuid))) {
  1064. Err = ERROR_CLASS_MISMATCH;
  1065. //
  1066. // Clean up the partial list we built.
  1067. //
  1068. DestroyDriverNodes(DriverNode, pDeviceInfoSet);
  1069. goto clean0;
  1070. }
  1071. }
  1072. }
  1073. //
  1074. // OK, if we get to here, then it's safe to go ahead and merge the new compatible
  1075. // driver list in with our existing one.
  1076. //
  1077. while(DriverNode) {
  1078. //
  1079. // Store a pointer to the next driver node before merging, because
  1080. // the driver node we're working with may be destroyed because it's
  1081. // a duplicate of a driver node already in the list.
  1082. //
  1083. NextDriverNode = DriverNode->Next;
  1084. pSetupMergeDriverNode(DrvSearchContext, DriverNode, &DriverNodeInsertedAtHead);
  1085. DriverNode = NextDriverNode;
  1086. }
  1087. }
  1088. //
  1089. // Update the class of the device information element based on the
  1090. // class of the most-compatible driver node we retrieved. Don't do
  1091. // this, however, if the device already has a selected driver.
  1092. //
  1093. if(!DevInfoElem->SelectedDriver &&
  1094. (DrvSearchContext->Flags & DRVSRCH_HASCLASSGUID) &&
  1095. !IsEqualGUID(ClassGuid, &(DrvSearchContext->ClassGuid))) {
  1096. //
  1097. // The class GUID for this device has changed. We need to make sure
  1098. // that the devinfo set doesn't have an associated class. Otherwise,
  1099. // we will introduce an inconsistency into the set, where a device
  1100. // contained in the set is of a different class than the set itself.
  1101. //
  1102. if(pDeviceInfoSet->HasClassGuid) {
  1103. Err = ERROR_CLASS_MISMATCH;
  1104. } else {
  1105. Err = InvalidateHelperModules(DeviceInfoSet, DeviceInfoData, 0);
  1106. }
  1107. if(Err != NO_ERROR) {
  1108. //
  1109. // Clean up the partial list we built.
  1110. //
  1111. DestroyDriverNodes(*(DrvSearchContext->pDriverListHead), pDeviceInfoSet);
  1112. *(DrvSearchContext->pDriverListHead) = *(DrvSearchContext->pDriverListTail) = NULL;
  1113. *(DrvSearchContext->pDriverCount) = 0;
  1114. goto clean0;
  1115. }
  1116. //
  1117. // We need to clean up any existing software keys associated with this
  1118. // device instance before changing its class, or otherwise we'll have
  1119. // orphaned registry keys.
  1120. //
  1121. pSetupDeleteDevRegKeys(DevInfoElem->DevInst,
  1122. DICS_FLAG_GLOBAL | DICS_FLAG_CONFIGSPECIFIC,
  1123. (DWORD)-1,
  1124. DIREG_DRV,
  1125. TRUE
  1126. );
  1127. //
  1128. // Now delete the Driver property for this device.
  1129. //
  1130. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  1131. CM_DRP_DRIVER,
  1132. NULL,
  1133. 0,
  1134. 0,
  1135. pDeviceInfoSet->hMachine);
  1136. //
  1137. // Update the device's class GUID, and also update the caller-supplied
  1138. // SP_DEVINFO_DATA structure to reflect the device's new class.
  1139. //
  1140. CopyMemory(ClassGuid,
  1141. &(DrvSearchContext->ClassGuid),
  1142. sizeof(GUID)
  1143. );
  1144. CopyMemory(&(DeviceInfoData->ClassGuid),
  1145. &(DrvSearchContext->ClassGuid),
  1146. sizeof(GUID)
  1147. );
  1148. //
  1149. // Finally, update the device's ClassGUID registry property. Also, if the
  1150. // INF specified a class name, update that too, since this may be a class
  1151. // that hasn't yet been installed, thus no class name would be known.
  1152. //
  1153. pSetupStringFromGuid(ClassGuid, TempBuffer, TempBufferSize);
  1154. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  1155. CM_DRP_CLASSGUID,
  1156. (PVOID)TempBuffer,
  1157. GUID_STRING_LEN * sizeof(TCHAR),
  1158. 0,
  1159. pDeviceInfoSet->hMachine);
  1160. if(*DrvSearchContext->ClassName) {
  1161. CM_Set_DevInst_Registry_Property_Ex(DevInfoElem->DevInst,
  1162. CM_DRP_CLASS,
  1163. (PBYTE)DrvSearchContext->ClassName,
  1164. (lstrlen(DrvSearchContext->ClassName) + 1) * sizeof(TCHAR),
  1165. 0,
  1166. pDeviceInfoSet->hMachine);
  1167. }
  1168. }
  1169. }
  1170. clean1:
  1171. //
  1172. // Replace our existing string table with the new one containing the additional strings
  1173. // used by the new driver nodes.
  1174. //
  1175. pStringTableDestroy(pDeviceInfoSet->StringTable);
  1176. pDeviceInfoSet->StringTable = DrvSearchContext->StringTable;
  1177. DrvSearchContext->StringTable = NULL;
  1178. //
  1179. // Set the flags to indicate that the driver list was built successfully.
  1180. //
  1181. *pFlagsEx |= (DriverType == SPDIT_CLASSDRIVER) ? DI_FLAGSEX_DIDINFOLIST
  1182. : DI_FLAGSEX_DIDCOMPATINFO;
  1183. //
  1184. // Since we aren't using partial information via a separate index, we build
  1185. // the driver list with both basic and detailed information.
  1186. //
  1187. // NOTE: If we ever use indexing like Win95, then the following flags should
  1188. // no longer be set here, and should only be set when the detailed
  1189. // driver information is actually retrieved from the INF.
  1190. //
  1191. *pFlags |= (DriverType == SPDIT_CLASSDRIVER) ? DI_DIDCLASS
  1192. : DI_DIDCOMPAT;
  1193. //
  1194. // If we built a non-empty class driver list, then create a driver list object
  1195. // for it, and store it in the device information set's list of class driver lists.
  1196. // (Don't worry that we're ignoring this if the list is empty--the memory allocated
  1197. // for ClassDriverListObject will get cleaned up later.)
  1198. //
  1199. // (If we're merely appending to an existing class driver list, then don't create
  1200. // a new driver list object.)
  1201. //
  1202. if(DrvSearchContext->BuildClassDrvList && !AppendingDriverLists &&
  1203. (DriverNode = *(DrvSearchContext->pDriverListHead))) {
  1204. ClassDriverListObject->RefCount = 1;
  1205. ClassDriverListObject->ListCreationFlags = *pFlags & INHERITED_FLAGS;
  1206. ClassDriverListObject->ListCreationFlagsEx = *pFlagsEx & INHERITED_FLAGSEX;
  1207. ClassDriverListObject->ListCreationDriverPath = InfPathId;
  1208. ClassDriverListObject->DriverListHead = DriverNode;
  1209. CopyMemory(&(ClassDriverListObject->ClassGuid), ClassGuid, sizeof(GUID));
  1210. //
  1211. // Now add this to the devinfo set's list, and clear the pointer, so that we won't
  1212. // try to free it.
  1213. //
  1214. ClassDriverListObject->Next = pDeviceInfoSet->ClassDrvListObjectList;
  1215. pDeviceInfoSet->ClassDrvListObjectList = ClassDriverListObject;
  1216. ClassDriverListObject = NULL;
  1217. }
  1218. clean0: ; // nothing to do
  1219. } except(EXCEPTION_EXECUTE_HANDLER) {
  1220. Err = ERROR_INVALID_PARAMETER;
  1221. if(HasDrvSearchInProgressLock) {
  1222. UnlockDrvSearchInProgressList(&GlobalDrvSearchInProgressList);
  1223. }
  1224. ExtractDrvSearchInProgressNode(&DrvSearchInProgressNode);
  1225. //
  1226. // Clean up any driver nodes we may have created.
  1227. //
  1228. if(PartialDrvListCleanUp) {
  1229. DestroyDriverNodes(*(DrvSearchContext->pDriverListHead), pDeviceInfoSet);
  1230. *(DrvSearchContext->pDriverListHead) = *(DrvSearchContext->pDriverListTail) = NULL;
  1231. *(DrvSearchContext->pDriverCount) = 0;
  1232. //
  1233. // Clean up any flags that may have been set.
  1234. //
  1235. if(!AppendingDriverLists && pFlags && pFlagsEx) {
  1236. if(DriverType == SPDIT_CLASSDRIVER) {
  1237. *pFlags &= ~(DI_DIDCLASS | DI_MULTMFGS);
  1238. *pFlagsEx &= ~DI_FLAGSEX_DIDINFOLIST;
  1239. } else {
  1240. *pFlags &= ~DI_DIDCOMPAT;
  1241. *pFlagsEx &= ~DI_FLAGSEX_DIDCOMPATINFO;
  1242. }
  1243. }
  1244. }
  1245. if(hKey != INVALID_HANDLE_VALUE) {
  1246. RegCloseKey(hKey);
  1247. }
  1248. //
  1249. // Access the following variables so that the compiler will respect our statement ordering
  1250. // w.r.t. these values.
  1251. //
  1252. ClassDriverListObject = ClassDriverListObject;
  1253. DrvSearchContext->StringTable = DrvSearchContext->StringTable;
  1254. }
  1255. final:
  1256. UnlockDeviceInfoSet(pDeviceInfoSet);
  1257. if(ClassDriverListObject) {
  1258. MyFree(ClassDriverListObject);
  1259. }
  1260. if(DrvSearchInProgressNode.SearchCancelledEvent) {
  1261. CloseHandle(DrvSearchInProgressNode.SearchCancelledEvent);
  1262. }
  1263. //
  1264. // Close the CDM context and free cdm.dll if we haven't already.
  1265. //
  1266. if (hInstanceCDM) {
  1267. spFusionEnterContext(NULL,&spFusionInstance);
  1268. if (hCDMContext) {
  1269. CLOSE_CDM_CONTEXT_PROC pfnCloseCDMContext;
  1270. if (pfnCloseCDMContext = (CLOSE_CDM_CONTEXT_PROC)GetProcAddress(hInstanceCDM,
  1271. "CloseCDMContext")) {
  1272. pfnCloseCDMContext(hCDMContext);
  1273. }
  1274. }
  1275. FreeLibrary(hInstanceCDM);
  1276. spFusionLeaveContext(&spFusionInstance);
  1277. }
  1278. if(TempBuffer) {
  1279. MyFree(TempBuffer);
  1280. }
  1281. if(DrvSearchContext) {
  1282. if(DrvSearchContext->StringTable) {
  1283. pStringTableDestroy(DrvSearchContext->StringTable);
  1284. }
  1285. if(DrvSearchContext->hCatAdmin) {
  1286. CryptCATAdminReleaseContext(DrvSearchContext->hCatAdmin, 0);
  1287. }
  1288. MyFree(DrvSearchContext);
  1289. }
  1290. SetLastError(Err);
  1291. return(Err == NO_ERROR);
  1292. }
  1293. BOOL
  1294. DrvSearchCallback(
  1295. IN PSETUP_LOG_CONTEXT LogContext,
  1296. IN PCTSTR InfName,
  1297. IN PLOADED_INF Inf,
  1298. IN BOOL PnfWasUsed,
  1299. IN PVOID pContext
  1300. )
  1301. /*++
  1302. Routine Description:
  1303. This routine is a callback function for the INF enumeration routines
  1304. (EnumSingleDrvInf, EnumDrvInfsInSearchPath). It performs
  1305. some action on the INF it's called for, then returns TRUE to continue
  1306. enumeration, or FALSE to abort it.
  1307. Arguments:
  1308. LogContext - Supplies information for logging purposes
  1309. InfName - Supplies the fully-qualified pathname of the INF.
  1310. pInf - Supplies pointer to the already loaded INF
  1311. pContext - Supplies a pointer to an input/output storage buffer for use
  1312. by the callback. For this callback, this pointer supplies the address
  1313. of a DRVSEARCH_CONTEXT structure.
  1314. Return Value:
  1315. To continue enumeration, the function should return TRUE, otherwise, it
  1316. should return FALSE.
  1317. Remarks:
  1318. We never abort enumeration in case of failure, even if that
  1319. failure is due to an out-of-memory condition!
  1320. --*/
  1321. {
  1322. PDRVSEARCH_CONTEXT Context = (PDRVSEARCH_CONTEXT)pContext;
  1323. PCTSTR Provider, ClassName;
  1324. PTSTR CurMfgName, CurMfgSecName, DevDesc, InstallSecName, DrvDesc, MatchedHwID;
  1325. PINF_SECTION MfgListSection, CurMfgSection, OptionsTextOrCtlFlagsSection;
  1326. PINF_LINE MfgListLine, CurMfgLine, DrvDescLine;
  1327. UINT MfgListIndex, CurMfgIndex, TempUint;
  1328. TCHAR TempStringBuffer[MAX_SECT_NAME_LEN + MAX_INFSTR_STRKEY_LEN];
  1329. UINT Rank;
  1330. PDRIVER_NODE NewDriverNode;
  1331. GUID InfClassGuid;
  1332. BOOL InsertedAtHead;
  1333. TCHAR OptionsTextSectionName[64];
  1334. PCTSTR LanguageName;
  1335. LONG MatchIndex;
  1336. LONG InfClassGuidIndex;
  1337. TCHAR InfSectionWithExt[MAX_SECT_NAME_LEN];
  1338. DWORD InfSectionWithExtLength;
  1339. PTSTR InfSectionExtension;
  1340. BOOL InfIsDigitallySigned = FALSE;
  1341. BOOL InfWasVerified = FALSE;
  1342. BOOL CurMfgSecIsDecorated;
  1343. TCHAR CurMfgSecWithExt[MAX_SECT_NAME_LEN];
  1344. SYSTEMTIME SysTime; // we use this for logging
  1345. //
  1346. // caller must pass in valid data
  1347. //
  1348. MYASSERT(InfName);
  1349. MYASSERT(Inf);
  1350. MYASSERT(Context);
  1351. //
  1352. // Before we do anything else, check to see whether some other thread has told us
  1353. // to abort.
  1354. //
  1355. if(*(Context->CancelSearch)) {
  1356. SetLastError(ERROR_CANCELLED);
  1357. return FALSE;
  1358. }
  1359. NewDriverNode = NULL;
  1360. try {
  1361. //
  1362. // Skip this INF if it was from the Internet and we don't want Internet INFs
  1363. //
  1364. if ((Context->Flags & DRVSRCH_EXCLUDE_OLD_INET_DRIVERS) &&
  1365. (Inf->InfSourceMediaType == SPOST_URL)) {
  1366. goto clean0;
  1367. }
  1368. //
  1369. // Process the INF differently depending on whether it's a Win95-style or a legacy INF.
  1370. //
  1371. if(Inf->Style & INF_STYLE_WIN4) {
  1372. //
  1373. // If we're building a compatible driver list, then we only care about this INF
  1374. // if it contains the hardware/compatible IDs we're searching for.
  1375. // Generally we wont get called unless we have any such ID's
  1376. // sometimes we may, so an easy check to make up-front is to determine whether
  1377. // any of the IDs exist in the loaded INF's string table. If not, then we can
  1378. // skip this file right now, and save a lot of time.
  1379. //
  1380. if((!Context->BuildClassDrvList) && (!pSetupDoesInfContainDevIds(Inf, Context))) {
  1381. goto clean0;
  1382. }
  1383. //
  1384. // Get the class GUID for this INF.
  1385. //
  1386. if(!ClassGuidFromInfVersionNode(&(Inf->VersionBlock), &InfClassGuid)) {
  1387. goto clean0;
  1388. }
  1389. //
  1390. // If we are building a class driver list, and there is an associated
  1391. // class GUID, then check to see if this INF is of the same class.
  1392. //
  1393. if(Context->BuildClassDrvList && (Context->Flags & DRVSRCH_HASCLASSGUID)) {
  1394. if(!IsEqualGUID(&(Context->ClassGuid), &InfClassGuid)) {
  1395. goto clean0;
  1396. }
  1397. }
  1398. //
  1399. // Don't allow a class that should be excluded (NoUseClass or NoDisplayClass) and the
  1400. // DRVSRCH_ALLOWEXCLUDEDDRVS flag is not set.
  1401. //
  1402. if (Context->BuildClassDrvList && ShouldClassBeExcluded(&InfClassGuid, !(Context->Flags & DRVSRCH_ALLOWEXCLUDEDDRVS))) {
  1403. goto clean0;
  1404. }
  1405. //
  1406. // Retrieve the name of the provider for this INF file.
  1407. //
  1408. Provider = pSetupGetVersionDatum(&(Inf->VersionBlock), pszProvider);
  1409. if(!(MfgListSection = InfLocateSection(Inf, pszManufacturer, NULL))) {
  1410. //
  1411. // No [Manufacturer] section--skip this INF.
  1412. //
  1413. WriteLogEntry(
  1414. LogContext,
  1415. DRIVER_LOG_VERBOSE, // VERBOSE since otherwise it will always log GUID-0 inf's for full iteration
  1416. MSG_LOG_NO_MANUFACTURER_SECTION,
  1417. NULL,
  1418. InfName);
  1419. goto clean0;
  1420. }
  1421. //
  1422. // OK, we are likely going to add some driver nodes to our list in the code below.
  1423. // Add this INF's class GUID to our GUID table.
  1424. //
  1425. InfClassGuidIndex = AddOrGetGuidTableIndex(Context->DeviceInfoSet, &InfClassGuid, TRUE);
  1426. if(InfClassGuidIndex == -1) {
  1427. goto clean0;
  1428. }
  1429. //
  1430. // Find the [ControlFlags] section (if there is one), so that we can use it
  1431. // later to determine whether particular devices should be excluded (via
  1432. // 'ExcludeFromSelect').
  1433. //
  1434. OptionsTextOrCtlFlagsSection = InfLocateSection(Inf, pszControlFlags, NULL);
  1435. Rank = 0; // Initialize this value for case where we're building a class driver list.
  1436. for(MfgListIndex = 0;
  1437. InfLocateLine(Inf, MfgListSection, NULL, &MfgListIndex, &MfgListLine);
  1438. MfgListIndex++) {
  1439. //
  1440. // Initially, assume the current manufacturer has no
  1441. // per-os-version TargetDecoration entries
  1442. //
  1443. CurMfgSecIsDecorated = FALSE;
  1444. if(!(CurMfgName = InfGetField(Inf, MfgListLine, 0, NULL))) {
  1445. continue;
  1446. }
  1447. if(!(CurMfgSecName = InfGetField(Inf, MfgListLine, 1, NULL))) {
  1448. //
  1449. // Lines with a single entry are considered to contain both
  1450. // a field 0 and a field 1 (i.e., both key and single
  1451. // value). As such, this test should never fire. If we
  1452. // have a line with no key and multiple values, we
  1453. // should've failed above when we tried to retrieve field
  1454. // zero. Note that the code that builds the INF cache
  1455. // relies on this observation (i.e., it doesn't care about
  1456. // the manufacturer's name, so it always just retrieves
  1457. // field 1).
  1458. //
  1459. MYASSERT(CurMfgSecName);
  1460. continue;
  1461. } else {
  1462. //
  1463. // Check to see if there is an applicable TargetDecoration
  1464. // entry for this manufacturer's models section (if so, the
  1465. // models section name will be appended with that
  1466. // decoration).
  1467. //
  1468. if(GetDecoratedModelsSection(LogContext,
  1469. Inf,
  1470. MfgListLine,
  1471. Context->AltPlatformInfo,
  1472. CurMfgSecWithExt)) {
  1473. //
  1474. // From here on, use the decorated models section...
  1475. //
  1476. CurMfgSecName = CurMfgSecWithExt;
  1477. CurMfgSecIsDecorated = TRUE;
  1478. }
  1479. }
  1480. if(!(CurMfgSection = InfLocateSection(Inf, CurMfgSecName, NULL))) {
  1481. continue;
  1482. }
  1483. //
  1484. // We have the manufacturer's section--now process all entries in it.
  1485. //
  1486. for(CurMfgIndex = 0;
  1487. InfLocateLine(Inf, CurMfgSection, NULL, &CurMfgIndex, &CurMfgLine);
  1488. CurMfgIndex++) {
  1489. MatchIndex = -1; // initialized for case when BuildClassDrvList is TRUE, to help with logging
  1490. if((Context->BuildClassDrvList && !(Context->Flags & DRVSRCH_FILTERSIMILARDRIVERS)) ||
  1491. (Rank = pSetupTestDevCompat(Inf, CurMfgLine, Context, &MatchIndex)) != RANK_NO_MATCH) {
  1492. //
  1493. // Get the device description.
  1494. //
  1495. if(!(DevDesc = InfGetField(Inf, CurMfgLine, 0, NULL))) {
  1496. continue;
  1497. }
  1498. //
  1499. // Get the install section name.
  1500. //
  1501. if(!(InstallSecName = InfGetField(Inf, CurMfgLine, 1, NULL))) {
  1502. continue;
  1503. }
  1504. //
  1505. // Get the actual (i.e., potentially decorated) install
  1506. // section name.
  1507. //
  1508. if(!SetupDiGetActualSectionToInstallEx(
  1509. Inf,
  1510. InstallSecName,
  1511. Context->AltPlatformInfo,
  1512. InfSectionWithExt,
  1513. SIZECHARS(InfSectionWithExt),
  1514. NULL,
  1515. &InfSectionExtension,
  1516. NULL)) {
  1517. //
  1518. // Should never fail, but...
  1519. //
  1520. continue;
  1521. }
  1522. //
  1523. // Check to see if we only want the installed driver.
  1524. //
  1525. if ((Context->Flags & DRVSRCH_INSTALLEDDRIVER) &&
  1526. (!pSetupTestIsInstalledDriver(DevDesc,
  1527. CurMfgName,
  1528. Provider,
  1529. InstallSecName,
  1530. InfSectionExtension,
  1531. Context))) {
  1532. //
  1533. // If we are looking only for the currently installed
  1534. // driver and this is not it, then skip this driver
  1535. // node.
  1536. //
  1537. continue;
  1538. }
  1539. //
  1540. // Check to see if this hardware is excluded by being
  1541. // in a ExcludeId field.
  1542. //
  1543. if (pSetupExcludeId(LogContext,
  1544. Inf,
  1545. InfName,
  1546. InfSectionWithExt,
  1547. Context)) {
  1548. //
  1549. // Don't create a driver node for this INF match
  1550. // because this hardware is excluded from this match.
  1551. //
  1552. continue;
  1553. }
  1554. //
  1555. // Check to see if the INF is digitally signed (if we
  1556. // haven't already)
  1557. //
  1558. if(!InfWasVerified) {
  1559. //
  1560. // We only want to check each INF once
  1561. //
  1562. InfWasVerified = TRUE;
  1563. if(PnfWasUsed && !Context->AltPlatformInfo) {
  1564. //
  1565. // Check the Inf Flags to see if this was
  1566. // digitally signed.
  1567. //
  1568. if(Inf->Flags & LIF_INF_DIGITALLY_SIGNED) {
  1569. InfIsDigitallySigned = TRUE;
  1570. }
  1571. } else {
  1572. //
  1573. // Either:
  1574. //
  1575. // (a) This INF is in a 3rd-party location
  1576. // (hence it has no PNF), or
  1577. // (b) We've been supplied with alternate
  1578. // platform information, thus we must
  1579. // disregard the cached "INF is signed"
  1580. // flag in the PNF
  1581. //
  1582. // In either case, we must now call
  1583. // WinVerifyTrust (potentially with the
  1584. // appropriate alternate platform parameters)
  1585. // to ascertain whether the INF should be
  1586. // considered signed.
  1587. //
  1588. // (Woe be unto those who wouldst call this for
  1589. // every INF in %windir%\Inf, for great would
  1590. // be the delay therein.)
  1591. //
  1592. if(VerifyDeviceInfFile(
  1593. LogContext,
  1594. &(Context->hCatAdmin),
  1595. InfName,
  1596. Inf,
  1597. Context->AltPlatformInfo,
  1598. NULL,
  1599. NULL,
  1600. NULL
  1601. )) {
  1602. InfIsDigitallySigned = TRUE;
  1603. }
  1604. }
  1605. }
  1606. //
  1607. // If we're building a compatible driver list (hence
  1608. // ranking is important), then we need to adjust the
  1609. // rank values if the INF is (a) unsigned and (b)
  1610. // undecorated (hence calling into question whether or
  1611. // not the INF was even meant to be used on NT)...
  1612. //
  1613. if(!Context->BuildClassDrvList) {
  1614. if(!InfIsDigitallySigned) {
  1615. //
  1616. // INF isn't signed, thus the match is untrusted
  1617. //
  1618. Rank |= DRIVER_UNTRUSTED_RANK;
  1619. if(!CurMfgSecIsDecorated && !InfSectionExtension) {
  1620. //
  1621. // Not only is the INF unsigned, but there
  1622. // are also no NT-specific decorations that
  1623. // give us a hint that this INF was intended
  1624. // for use on NT. Thus, we have reason to
  1625. // be suspicious that this INF is for
  1626. // Windows 9x platforms only...
  1627. //
  1628. Rank |= DRIVER_W9X_SUSPECT_RANK;
  1629. }
  1630. }
  1631. }
  1632. //
  1633. // Form the driver description. It is of the form,
  1634. // "<InstallSection>.DriverDesc", and appears in the
  1635. // [strings] section (if present). (NOTE: We don't have
  1636. // to search for this section, since it's always the
  1637. // first section in the INF's SectionBlock list.
  1638. //
  1639. // If no driver description is present, use the device
  1640. // description.
  1641. //
  1642. wsprintf(TempStringBuffer, pszDrvDescFormat, InstallSecName);
  1643. TempUint = 0;
  1644. if(!Inf->HasStrings ||
  1645. !InfLocateLine(Inf, Inf->SectionBlock, TempStringBuffer,
  1646. &TempUint, &DrvDescLine) ||
  1647. !(DrvDesc = InfGetField(Inf, DrvDescLine, 1, NULL))) {
  1648. DrvDesc = DevDesc;
  1649. }
  1650. if(CreateDriverNode(Rank,
  1651. DevDesc,
  1652. DrvDesc,
  1653. Provider,
  1654. CurMfgName,
  1655. &(Inf->VersionBlock.LastWriteTime),
  1656. Inf->VersionBlock.Filename,
  1657. InstallSecName,
  1658. Context->StringTable,
  1659. InfClassGuidIndex,
  1660. &NewDriverNode) != NO_ERROR) {
  1661. continue;
  1662. }
  1663. //
  1664. // Get which hardware ID we matched with.
  1665. //
  1666. if(!(MatchedHwID = InfGetField(Inf, CurMfgLine, MatchIndex+3, NULL))) {
  1667. MatchedHwID = TEXT("");
  1668. }
  1669. //
  1670. // Log that a driver node was created.
  1671. //
  1672. WriteLogEntry(
  1673. LogContext,
  1674. Context->BuildClassDrvList ? DRIVER_LOG_INFO1 : DRIVER_LOG_INFO,
  1675. MSG_LOG_FOUND_1,
  1676. NULL,
  1677. MatchedHwID, // hardware ID
  1678. InfName, // filename
  1679. DevDesc, // Device description
  1680. DrvDesc, // Driver description
  1681. Provider, // Provider name
  1682. CurMfgName, // Manufacturer name
  1683. InstallSecName // Install section name
  1684. );
  1685. //
  1686. // If this is an untrusted compatible driver node, make
  1687. // an additional log entry about that
  1688. //
  1689. if(!Context->BuildClassDrvList
  1690. && (Rank & DRIVER_UNTRUSTED_RANK)) {
  1691. WriteLogEntry(LogContext,
  1692. DRIVER_LOG_INFO,
  1693. MSG_LOG_RANK_UNTRUSTED,
  1694. NULL,
  1695. Rank & ~DRIVER_W9X_SUSPECT_RANK,
  1696. Rank
  1697. );
  1698. }
  1699. if(pSetupGetDeviceIDs(NewDriverNode,
  1700. Inf,
  1701. CurMfgLine,
  1702. Context->StringTable,
  1703. OptionsTextOrCtlFlagsSection)) {
  1704. //
  1705. // If we're doing a non-native driver search, then
  1706. // we want to disregard any ExcludeFromSelect
  1707. // entries in the [ControlFlags] section, as they
  1708. // won't be relevant to our non-native driver node
  1709. // anyway.
  1710. //
  1711. if(Context->AltPlatformInfo) {
  1712. NewDriverNode->Flags &= ~DNF_EXCLUDEFROMLIST;
  1713. }
  1714. } else {
  1715. //
  1716. // We must've encountered an out-of-memory
  1717. // condition--time to bail!
  1718. //
  1719. DestroyDriverNodes(NewDriverNode, Context->DeviceInfoSet);
  1720. continue;
  1721. }
  1722. if(InfIsDigitallySigned) {
  1723. NewDriverNode->Flags |= DNF_INF_IS_SIGNED;
  1724. }
  1725. //
  1726. // Look for the DriverVer date and version in the
  1727. // install section and if it is not there then look
  1728. // in the Version section
  1729. //
  1730. if (!pSetupGetDriverDate(Inf,
  1731. InfSectionWithExt,
  1732. &(NewDriverNode->DriverDate))) {
  1733. pSetupGetDriverDate(Inf,
  1734. INFSTR_SECT_VERSION,
  1735. &(NewDriverNode->DriverDate));
  1736. }
  1737. //
  1738. // Mark the driver node as coming from a user doing an
  1739. // F6 during textmode setup if that is where the INF is
  1740. // from.
  1741. //
  1742. if (Inf->Flags & LIF_OEM_F6_INF) {
  1743. NewDriverNode->Flags |= DNF_OEM_F6_INF;
  1744. }
  1745. if(!FileTimeToSystemTime(&NewDriverNode->DriverDate,&SysTime)) {
  1746. ZeroMemory(&SysTime, sizeof(SysTime));
  1747. }
  1748. WriteLogEntry(
  1749. LogContext,
  1750. Context->BuildClassDrvList ? DRIVER_LOG_INFO1 : DRIVER_LOG_INFO,
  1751. MSG_LOG_FOUND_2,
  1752. NULL,
  1753. InfSectionWithExt,
  1754. Rank,
  1755. SysTime.wMonth,
  1756. SysTime.wDay,
  1757. SysTime.wYear);
  1758. //
  1759. // Get the DriverVersion from the INF.
  1760. //
  1761. if (!pSetupGetDriverVersion(Inf,
  1762. InfSectionWithExt,
  1763. &(NewDriverNode->DriverVersion))) {
  1764. pSetupGetDriverVersion(Inf,
  1765. INFSTR_SECT_VERSION,
  1766. &(NewDriverNode->DriverVersion));
  1767. }
  1768. if(!(Context->BuildClassDrvList)) {
  1769. //
  1770. // Store away the index of the matching device ID in this compatible
  1771. // driver node.
  1772. //
  1773. NewDriverNode->MatchingDeviceId = MatchIndex;
  1774. }
  1775. //
  1776. // If the INF from which this driver node was built has
  1777. // a corresponding PNF, then mark the driver node with
  1778. // the Win98-compatible DNF_INDEXED_DRIVER flag.
  1779. //
  1780. if(PnfWasUsed) {
  1781. NewDriverNode->Flags |= DNF_INDEXED_DRIVER;
  1782. }
  1783. //
  1784. // If the INF is from Windows Update (the Internet) then
  1785. // set the DNF_INET_DRIVER bit.
  1786. //
  1787. if (Context->Flags & DRVSRCH_FROM_INET) {
  1788. NewDriverNode->Flags |= DNF_INET_DRIVER;
  1789. }
  1790. //
  1791. // If we just downloade this driver from the Internet then we need to
  1792. // clean it up when we destroy the driver node
  1793. //
  1794. if (Context->Flags & DRVSRCH_CLEANUP_SOURCE_PATH) {
  1795. NewDriverNode->Flags |= PDNF_CLEANUP_SOURCE_PATH;
  1796. }
  1797. //
  1798. // If the InfSourceMediaType is SPOST_URL then the
  1799. // Inf that this driver came from came from the Internet
  1800. // but now lives in the INF directory. You should never
  1801. // install a driver with the DNF_OLD_INET_DRIVER flag set
  1802. // because we no longer have access to the sources files.
  1803. //
  1804. if (Inf->InfSourceMediaType == SPOST_URL) {
  1805. NewDriverNode->Flags |= DNF_OLD_INET_DRIVER;
  1806. }
  1807. //
  1808. // Merge the new driver node into our existing list.
  1809. // NOTE: Do not dereference NewDriverNode after this call,
  1810. // since it may have been a duplicate, in which case it
  1811. // will be destroyed by this routine.
  1812. //
  1813. pSetupMergeDriverNode(Context, NewDriverNode, &InsertedAtHead);
  1814. NewDriverNode = NULL;
  1815. if(!Context->BuildClassDrvList && InsertedAtHead) {
  1816. //
  1817. // Update the device instance class to that of the new
  1818. // lowest-rank driver.
  1819. //
  1820. CopyMemory(&(Context->ClassGuid),
  1821. &InfClassGuid,
  1822. sizeof(GUID)
  1823. );
  1824. Context->Flags |= DRVSRCH_HASCLASSGUID;
  1825. if(ClassName = pSetupGetVersionDatum(&(Inf->VersionBlock), pszClass)) {
  1826. lstrcpy(Context->ClassName, ClassName);
  1827. } else {
  1828. *(Context->ClassName) = TEXT('\0');
  1829. }
  1830. }
  1831. }
  1832. }
  1833. }
  1834. } else {
  1835. //
  1836. // caller may have given us an OLDNT Inf when we only want WIN4 style
  1837. // if this is the case, skip the Inf
  1838. //
  1839. if (!(Context->Flags & DRVSRCH_USEOLDINFS)) {
  1840. goto clean0;
  1841. }
  1842. MYASSERT(Context->BuildClassDrvList && (Context->Flags & DRVSRCH_HASCLASSGUID));
  1843. //
  1844. // We're dealing with a legacy INF. First, check to see if this is the INF
  1845. // class we're looking for.
  1846. //
  1847. if(lstrcmpi(pSetupGetVersionDatum(&(Inf->VersionBlock), pszClass),
  1848. Context->LegacyClassName)) {
  1849. goto clean0;
  1850. }
  1851. //
  1852. // Now, retrieve the name of the provider for this INF file, and the standard
  1853. // (localized) manufacturer name we assign to legacy driver nodes.
  1854. //
  1855. Provider = pSetupGetVersionDatum(&(Inf->VersionBlock), pszProvider);
  1856. LoadString(MyDllModuleHandle,
  1857. IDS_ADDITIONALMODELS,
  1858. TempStringBuffer,
  1859. SIZECHARS(TempStringBuffer)
  1860. );
  1861. CurMfgName = TempStringBuffer;
  1862. //
  1863. // Now, retrieve the options from the [Options] section, and convert each one
  1864. // into a driver node.
  1865. //
  1866. if(!(CurMfgSection = InfLocateSection(Inf, pszOptions, NULL))) {
  1867. goto clean0;
  1868. }
  1869. //
  1870. // Attempt to find the corresponding OptionsText section, based on the language
  1871. // identifier contained in the search context.
  1872. //
  1873. OptionsTextOrCtlFlagsSection = NULL;
  1874. CopyMemory(OptionsTextSectionName, pszOptionsText, sizeof(pszOptionsText) - sizeof(TCHAR));
  1875. lstrcpy((PTSTR)((PBYTE)OptionsTextSectionName + (sizeof(pszOptionsText) - sizeof(TCHAR))),
  1876. LanguageName = Context->LegacyClassLang
  1877. );
  1878. OptionsTextOrCtlFlagsSection = InfLocateSection(Inf, OptionsTextSectionName, NULL);
  1879. if(!OptionsTextOrCtlFlagsSection) {
  1880. //
  1881. // Then we couldn't retrieve the 'best' language. Revert to picking the first
  1882. // language listed in the [LanguagesSupported] section. (Recycle 'MfgList*' variables
  1883. // here.)
  1884. //
  1885. if(!(MfgListSection = InfLocateSection(Inf, pszLanguagesSupported, NULL))) {
  1886. //
  1887. // No such section--give up on this INF.
  1888. //
  1889. goto clean0;
  1890. }
  1891. MfgListIndex = 0;
  1892. if(!InfLocateLine(Inf, MfgListSection, NULL, &MfgListIndex, &MfgListLine)) {
  1893. goto clean0;
  1894. }
  1895. lstrcpy((PTSTR)((PBYTE)OptionsTextSectionName + (sizeof(pszOptionsText) - sizeof(TCHAR))),
  1896. LanguageName = InfGetField(Inf, MfgListLine, 0, NULL)
  1897. );
  1898. if(!(OptionsTextOrCtlFlagsSection = InfLocateSection(Inf,
  1899. OptionsTextSectionName,
  1900. NULL))) {
  1901. goto clean0;
  1902. }
  1903. }
  1904. //
  1905. // We are about to add some driver nodes to our list in the code below.
  1906. // Add the class GUID corresponding to this legacy INF's class name to our GUID table.
  1907. //
  1908. InfClassGuidIndex = AddOrGetGuidTableIndex(Context->DeviceInfoSet, &(Context->ClassGuid), TRUE);
  1909. if(InfClassGuidIndex == -1) {
  1910. goto clean0;
  1911. }
  1912. //
  1913. // OK, now we have pointers to both the [Options] and [OptionsText<lang>] sections.
  1914. // Now, enumerate the options.
  1915. //
  1916. for(CurMfgIndex = 0;
  1917. InfLocateLine(Inf, CurMfgSection, NULL, &CurMfgIndex, &CurMfgLine);
  1918. CurMfgIndex++) {
  1919. //
  1920. // Get the Option name (used as the install section name).
  1921. //
  1922. if(!(InstallSecName = InfGetField(Inf, CurMfgLine, 0, NULL))) {
  1923. continue;
  1924. }
  1925. //
  1926. // Now get the driver/device description (i.e., the corresponding option entry in the
  1927. // OptionsText section).
  1928. //
  1929. TempUint = 0;
  1930. if(!InfLocateLine(Inf,
  1931. OptionsTextOrCtlFlagsSection,
  1932. InstallSecName,
  1933. &TempUint,
  1934. &DrvDescLine) ||
  1935. !(DrvDesc = InfGetField(Inf, DrvDescLine, 1, NULL))) {
  1936. //
  1937. // Couldn't find the driver description.
  1938. //
  1939. continue;
  1940. }
  1941. //
  1942. // We now have all the information we need to create a driver node.
  1943. //
  1944. if(CreateDriverNode(RANK_NO_MATCH,
  1945. DrvDesc,
  1946. DrvDesc,
  1947. Provider,
  1948. CurMfgName,
  1949. &(Inf->VersionBlock.LastWriteTime),
  1950. Inf->VersionBlock.Filename,
  1951. InstallSecName,
  1952. Context->StringTable,
  1953. InfClassGuidIndex,
  1954. &NewDriverNode) != NO_ERROR) {
  1955. continue;
  1956. }
  1957. //
  1958. // Now, add the string ID representing the language to be used for installing
  1959. // this driver node.
  1960. //
  1961. if((NewDriverNode->LegacyInfLang = pStringTableAddString(
  1962. Context->StringTable,
  1963. (PTSTR)LanguageName,
  1964. STRTAB_CASE_SENSITIVE,
  1965. NULL,0)) == -1) {
  1966. //
  1967. // Out-of-memory, can't use this driver node after all.
  1968. //
  1969. DestroyDriverNodes(NewDriverNode, Context->DeviceInfoSet);
  1970. NewDriverNode = NULL;
  1971. continue;
  1972. }
  1973. //
  1974. // Mark this driver node as being a legacy driver node.
  1975. //
  1976. NewDriverNode->Flags |= DNF_LEGACYINF;
  1977. //
  1978. // Merge the new driver node into our existing list.
  1979. // NOTE: Do not dereference NewDriverNode after this call,
  1980. // since it may have been a duplicate, in which case it
  1981. // will be destroyed by this routine.
  1982. //
  1983. pSetupMergeDriverNode(Context, NewDriverNode, &InsertedAtHead);
  1984. NewDriverNode = NULL;
  1985. }
  1986. }
  1987. clean0:
  1988. ; // Nothing to do.
  1989. } except(EXCEPTION_EXECUTE_HANDLER) {
  1990. if(NewDriverNode) {
  1991. //
  1992. // Make sure it didn't get partially linked into a list.
  1993. //
  1994. NewDriverNode->Next = NULL;
  1995. DestroyDriverNodes(NewDriverNode, Context->DeviceInfoSet);
  1996. }
  1997. }
  1998. return TRUE;
  1999. }
  2000. BOOL
  2001. pSetupFillInHardwareAndCompatIds(
  2002. PDEVINFO_ELEM DevInfoElem,
  2003. HMACHINE hMachine,
  2004. PDRVSEARCH_CONTEXT DrvSearchContext,
  2005. PSETUP_LOG_CONTEXT LogContext
  2006. )
  2007. /*++
  2008. Routine Description:
  2009. This routine fills in the PDRVSEARCH_CONTEXT->IdList with the string
  2010. table Ids for all of the hardware and compatible Ids for the specified
  2011. device.
  2012. Arguments:
  2013. DevInfoElem - Supplies the address of a devinfo element.
  2014. hMachine - Handle to the machine where the device resides that this
  2015. API will get the hardware and compatbile Ids for.
  2016. Context - Supplies a pointer to a DRVSEARCH_CONTEXT structure
  2017. containing information on the device instance with which
  2018. the specified INF line must be compatible.
  2019. LogContext - Supplies information for logging purposes
  2020. Return Value:
  2021. TRUE if no error is encountered, FALSE otherwise.
  2022. --*/
  2023. {
  2024. DWORD Err, i;
  2025. CONFIGRET cr;
  2026. LONG NumIds[2];
  2027. TCHAR TempBuffer[REGSTR_VAL_MAX_HCID_LEN]; // also holds other strings, but this value is largest
  2028. LPTSTR TempBufferPos; // for character parsing
  2029. ULONG TempBufferLen;
  2030. Err = ERROR_SUCCESS;
  2031. //
  2032. // We're building a class driver list for similar drivers only--retrieve the list
  2033. // of Hardware IDs (index 0) and Compatible IDs (index 1) from the device's
  2034. // registry properties.
  2035. //
  2036. for(i = 0; i < 2; i++) {
  2037. DWORD slot = AllocLogInfoSlot(LogContext,TRUE);
  2038. TempBufferLen = sizeof(TempBuffer);
  2039. cr = CM_Get_DevInst_Registry_Property_Ex(
  2040. DevInfoElem->DevInst,
  2041. (i ? CM_DRP_COMPATIBLEIDS : CM_DRP_HARDWAREID),
  2042. NULL,
  2043. TempBuffer,
  2044. &TempBufferLen,
  2045. 0,
  2046. hMachine);
  2047. switch(cr) {
  2048. case CR_BUFFER_SMALL :
  2049. Err = ERROR_INVALID_DATA;
  2050. goto clean0;
  2051. case CR_INVALID_DEVINST :
  2052. Err = ERROR_NO_SUCH_DEVINST;
  2053. goto clean0;
  2054. default : ; // Ignore any other return code.
  2055. }
  2056. //
  2057. // If we retrieved a REG_MULTI_SZ buffer, add all the strings in it
  2058. // to the device information set's string table.
  2059. //
  2060. if((cr == CR_SUCCESS) && (TempBufferLen > 2 * sizeof(TCHAR))) {
  2061. if((NumIds[i] = AddMultiSzToStringTable(DrvSearchContext->StringTable,
  2062. TempBuffer,
  2063. DrvSearchContext->IdList[i],
  2064. MAX_HCID_COUNT,
  2065. FALSE,
  2066. NULL)) == -1) {
  2067. Err = ERROR_NOT_ENOUGH_MEMORY;
  2068. goto clean0;
  2069. }
  2070. //
  2071. // Use a -1 end-of-list marker so that we don't have to store
  2072. // the count in the context structure.
  2073. //
  2074. DrvSearchContext->IdList[i][ NumIds[i] ] = -1;
  2075. //
  2076. // Now that the data has been stored, it can be munged for
  2077. // easy logging. In this, the NULLs between strings are
  2078. // turned into commas.
  2079. //
  2080. for (TempBufferPos = TempBuffer; *TempBufferPos != 0; TempBufferPos = CharNext(TempBufferPos)) {
  2081. //
  2082. // we have a string, look for string terminator
  2083. //
  2084. while (*TempBufferPos != 0) {
  2085. TempBufferPos = CharNext(TempBufferPos);
  2086. }
  2087. //
  2088. // peek to see if a non-Null character follows terminating NULL
  2089. // can't use CharNext here, as it wont go past end of string
  2090. // however terminating NULL always only takes up 1 TCHAR
  2091. //
  2092. if(*(TempBufferPos+1) != 0) {
  2093. //
  2094. // convert terminator into a comma unless last string
  2095. //
  2096. *TempBufferPos = TEXT(',');
  2097. }
  2098. //
  2099. // onto next string
  2100. //
  2101. }
  2102. WriteLogEntry(LogContext,
  2103. slot,
  2104. (i ? MSG_LOG_SEARCH_COMPATIBLE_IDS
  2105. : MSG_LOG_SEARCH_HARDWARE_IDS),
  2106. NULL,
  2107. TempBuffer);
  2108. } else {
  2109. NumIds[i] = 0;
  2110. DrvSearchContext->IdList[i][0] = -1;
  2111. }
  2112. }
  2113. clean0:
  2114. SetLastError(Err);
  2115. return (Err == ERROR_SUCCESS);
  2116. }
  2117. LONG
  2118. pSetupGetInstalledDriverInfo(
  2119. IN HDEVINFO DeviceInfoSet,
  2120. IN PSP_DEVINFO_DATA DeviceInfoData,
  2121. PDRVSEARCH_CONTEXT DrvSearchContext
  2122. )
  2123. /*++
  2124. Routine Description:
  2125. This routine determins the currently installed INF file for this device
  2126. and adds it to the string table. It will also retrieve the Description,
  2127. MfgName, ProviderName of the currently installed driver and add those to
  2128. the string table as well. It will store these string table Ids in the
  2129. appropriate entries in the DrvSearchContext parameter. It will return the
  2130. StringTableId of the InfPath or -1 if there was an error or there wasn't
  2131. an InfPat for this device.
  2132. Arguments:
  2133. DeviceInfoSet - Supplies a handle to a device information set.
  2134. DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure that
  2135. this routine will get the Infpath for.
  2136. Context - Supplies a pointer to a DRVSEARCH_CONTEXT structure
  2137. containing information on the device instance with which
  2138. the specified INF line must be compatible.
  2139. Return Value:
  2140. This function returns the StringTableId of the InfPath that was added to the
  2141. string table or -1 if there was an error.
  2142. --*/
  2143. {
  2144. HKEY hKey;
  2145. DWORD Err;
  2146. DWORD RegDataType, RegDataLength;
  2147. TCHAR TempBuffer[MAX_PATH];
  2148. LONG InfPathId = -1;
  2149. LONG StringTableId;
  2150. //
  2151. // Open the device's driver key and retrieve the INF from which the device was installed.
  2152. //
  2153. hKey = SetupDiOpenDevRegKey(DeviceInfoSet,
  2154. DeviceInfoData,
  2155. DICS_FLAG_GLOBAL,
  2156. 0,
  2157. DIREG_DRV,
  2158. KEY_READ
  2159. );
  2160. if(hKey == INVALID_HANDLE_VALUE) {
  2161. return -1;
  2162. }
  2163. RegDataLength = sizeof(TempBuffer); // want in bytes, not chars
  2164. Err = RegQueryValueEx(hKey,
  2165. REGSTR_VAL_INFPATH,
  2166. NULL,
  2167. &RegDataType,
  2168. (PBYTE)TempBuffer,
  2169. &RegDataLength
  2170. );
  2171. if((Err == ERROR_SUCCESS) && (RegDataType != REG_SZ)) {
  2172. goto clean0;
  2173. }
  2174. if(Err != ERROR_SUCCESS) {
  2175. goto clean0;
  2176. }
  2177. //
  2178. // We got the InfPath so add it to the string table
  2179. //
  2180. InfPathId = pStringTableAddString(DrvSearchContext->StringTable,
  2181. TempBuffer,
  2182. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  2183. NULL,
  2184. 0
  2185. );
  2186. //
  2187. // Now lets get the Provider from the driver key
  2188. //
  2189. RegDataLength = sizeof(TempBuffer); // want in bytes, not chars
  2190. Err = RegQueryValueEx(hKey,
  2191. REGSTR_VAL_PROVIDER_NAME,
  2192. NULL,
  2193. &RegDataType,
  2194. (PBYTE)TempBuffer,
  2195. &RegDataLength
  2196. );
  2197. if ((Err == ERROR_SUCCESS) &&
  2198. (RegDataType == REG_SZ)) {
  2199. //
  2200. // Add the provider to the string table.
  2201. //
  2202. DrvSearchContext->InstalledProviderName =
  2203. pStringTableAddString(DrvSearchContext->StringTable,
  2204. TempBuffer,
  2205. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  2206. NULL,
  2207. 0
  2208. );
  2209. } else {
  2210. //
  2211. // Assume there is no provider specified. If it turns out that the registry query
  2212. // really failed for some other reason, then this will fail later on when we
  2213. // compare this NULL provider to the real provider.
  2214. //
  2215. DrvSearchContext->InstalledProviderName = -1;
  2216. }
  2217. //
  2218. // Now lets get the InfSection from the driver key
  2219. //
  2220. RegDataLength = sizeof(TempBuffer); // want in bytes, not chars
  2221. Err = RegQueryValueEx(hKey,
  2222. REGSTR_VAL_INFSECTION,
  2223. NULL,
  2224. &RegDataType,
  2225. (PBYTE)TempBuffer,
  2226. &RegDataLength
  2227. );
  2228. if ((Err == ERROR_SUCCESS) &&
  2229. (RegDataType == REG_SZ)) {
  2230. //
  2231. // Add the InfSection to the string table.
  2232. //
  2233. DrvSearchContext->InstalledInfSection =
  2234. pStringTableAddString(DrvSearchContext->StringTable,
  2235. TempBuffer,
  2236. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  2237. NULL,
  2238. 0
  2239. );
  2240. } else {
  2241. //
  2242. // Assume there is no InfSection specified. If it turns out that the registry query
  2243. // really failed for some other reason, then this will fail later on when we
  2244. // compare this NULL InfSection to the real InfSection.
  2245. //
  2246. DrvSearchContext->InstalledInfSection = -1;
  2247. }
  2248. //
  2249. // Now lets get the InfSectionExt from the driver key
  2250. //
  2251. RegDataLength = sizeof(TempBuffer); // want in bytes, not chars
  2252. Err = RegQueryValueEx(hKey,
  2253. REGSTR_VAL_INFSECTIONEXT,
  2254. NULL,
  2255. &RegDataType,
  2256. (PBYTE)TempBuffer,
  2257. &RegDataLength
  2258. );
  2259. if ((Err == ERROR_SUCCESS) &&
  2260. (RegDataType == REG_SZ)) {
  2261. //
  2262. // Add the InfSection to the string table.
  2263. //
  2264. DrvSearchContext->InstalledInfSectionExt =
  2265. pStringTableAddString(DrvSearchContext->StringTable,
  2266. TempBuffer,
  2267. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  2268. NULL,
  2269. 0
  2270. );
  2271. } else {
  2272. //
  2273. // Assume there is no InfSectionExt specified. If it turns out that the registry query
  2274. // really failed for some other reason, then this will fail later on when we
  2275. // compare this NULL InfSectionExt to the real InfSectionExt.
  2276. //
  2277. DrvSearchContext->InstalledInfSectionExt = -1;
  2278. }
  2279. //
  2280. // Next, retrieve the manufacturer (stored in the Mfg device property).
  2281. //
  2282. if(SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  2283. DeviceInfoData,
  2284. SPDRP_MFG,
  2285. NULL, // datatype is guaranteed to always be REG_SZ.
  2286. (PBYTE)TempBuffer,
  2287. sizeof(TempBuffer), // in bytes
  2288. NULL)) {
  2289. //
  2290. // Add the manufacturer to the string table.
  2291. //
  2292. DrvSearchContext->InstalledMfgName =
  2293. pStringTableAddString(DrvSearchContext->StringTable,
  2294. TempBuffer,
  2295. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  2296. NULL,
  2297. 0
  2298. );
  2299. } else {
  2300. //
  2301. // Assume there is no manufacturer specified. If it turns out that the registry query
  2302. // really failed for some other reason, then this will fail later on when we
  2303. // compare this NULL manufacturer to the real manufacturer.
  2304. //
  2305. DrvSearchContext->InstalledMfgName = -1;
  2306. }
  2307. //
  2308. // Finally, retrieve the device description (stored in the DeviceDesc device property).
  2309. //
  2310. if(SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  2311. DeviceInfoData,
  2312. SPDRP_DEVICEDESC,
  2313. NULL, // datatype is guaranteed to always be REG_SZ.
  2314. (PBYTE)TempBuffer,
  2315. sizeof(TempBuffer), // in bytes
  2316. NULL)) {
  2317. //
  2318. // Add the device description to the string table.
  2319. //
  2320. DrvSearchContext->InstalledDescription =
  2321. pStringTableAddString(DrvSearchContext->StringTable,
  2322. TempBuffer,
  2323. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  2324. NULL,
  2325. 0
  2326. );
  2327. } else {
  2328. //
  2329. // Assume there is no device description specified. If it turns out that the
  2330. // registry query really failed for some other reason, then this will fail later
  2331. // on when we compare this NULL device description to the real device description.
  2332. //
  2333. DrvSearchContext->InstalledDescription = -1;
  2334. }
  2335. clean0:
  2336. RegCloseKey(hKey);
  2337. return InfPathId;
  2338. }
  2339. BOOL
  2340. pSetupTestIsInstalledDriver(
  2341. IN PCTSTR Description,
  2342. IN PCTSTR MfgName,
  2343. IN PCTSTR ProviderName,
  2344. IN PCTSTR InfSection,
  2345. IN PCTSTR InfSectionExt,
  2346. IN PDRVSEARCH_CONTEXT Context
  2347. )
  2348. {
  2349. LONG StringId;
  2350. BOOL bIsInstalledDriver = FALSE;
  2351. PTSTR String;
  2352. //
  2353. // First test the Description:
  2354. // Make sure we have both Descriptions or that both are NULL.
  2355. //
  2356. if (((Context->InstalledDescription == -1) && Description) ||
  2357. ((Context->InstalledDescription != -1) && !Description)) {
  2358. goto clean0;
  2359. }
  2360. if (Context->InstalledDescription != -1) {
  2361. String = pStringTableStringFromId(Context->StringTable, Context->InstalledDescription);
  2362. if (!String || lstrcmpi(String, Description)) {
  2363. //
  2364. // Descriptions don't match
  2365. //
  2366. goto clean0;
  2367. }
  2368. }
  2369. //
  2370. // Next test the MfgName:
  2371. // Make sure we have two MfgNames or that both are NULL.
  2372. //
  2373. if (((Context->InstalledMfgName == -1) && MfgName) ||
  2374. ((Context->InstalledMfgName != -1) && !MfgName)) {
  2375. goto clean0;
  2376. }
  2377. if (Context->InstalledMfgName != -1) {
  2378. String = pStringTableStringFromId(Context->StringTable, Context->InstalledMfgName);
  2379. if (!String || lstrcmpi(String, MfgName)) {
  2380. //
  2381. // MfgNames don't match
  2382. //
  2383. goto clean0;
  2384. }
  2385. }
  2386. //
  2387. // Next test the ProviderName:
  2388. // Make sure we have two ProviderNames or that both are NULL.
  2389. //
  2390. if (((Context->InstalledProviderName == -1) && ProviderName) ||
  2391. ((Context->InstalledProviderName != -1) && !ProviderName)) {
  2392. goto clean0;
  2393. }
  2394. if (Context->InstalledProviderName != -1) {
  2395. String = pStringTableStringFromId(Context->StringTable, Context->InstalledProviderName);
  2396. if (!String || lstrcmpi(String, ProviderName)) {
  2397. //
  2398. // ProviderNames don't match
  2399. //
  2400. goto clean0;
  2401. }
  2402. }
  2403. //
  2404. // Next, test the InfSection:
  2405. // Make sure we have two InfSections or that both are NULL.
  2406. //
  2407. if (((Context->InstalledInfSection == -1) && InfSection) ||
  2408. ((Context->InstalledInfSection != -1) && !InfSection)) {
  2409. goto clean0;
  2410. }
  2411. if (Context->InstalledInfSection != -1) {
  2412. String = pStringTableStringFromId(Context->StringTable, Context->InstalledInfSection);
  2413. if (!String || lstrcmpi(String, InfSection)) {
  2414. //
  2415. // InfSections don't match
  2416. //
  2417. goto clean0;
  2418. }
  2419. }
  2420. //
  2421. // Finally, test the InfSectionExt:
  2422. // Make sure we have two InfSections or that both are NULL.
  2423. //
  2424. if (((Context->InstalledInfSectionExt == -1) && InfSectionExt) ||
  2425. ((Context->InstalledInfSectionExt != -1) && !InfSectionExt)) {
  2426. goto clean0;
  2427. }
  2428. if (Context->InstalledInfSectionExt != -1) {
  2429. String = pStringTableStringFromId(Context->StringTable, Context->InstalledInfSectionExt);
  2430. if (!String || lstrcmpi(String, InfSectionExt)) {
  2431. //
  2432. // InfSectionExts don't match
  2433. //
  2434. goto clean0;
  2435. }
  2436. }
  2437. //
  2438. // Everything matches so this must be the currently installed driver.
  2439. //
  2440. bIsInstalledDriver = TRUE;
  2441. clean0:
  2442. return bIsInstalledDriver;
  2443. }
  2444. UINT
  2445. pSetupTestDevCompat(
  2446. IN PLOADED_INF Inf,
  2447. IN PINF_LINE InfLine,
  2448. IN PDRVSEARCH_CONTEXT Context,
  2449. OUT PLONG MatchIndex
  2450. )
  2451. /*++
  2452. Routine Description:
  2453. This routine tests a device entry in an INF to see if it is
  2454. compatible with the information supplied in the Context parameter.
  2455. Arguments:
  2456. Inf - Supplies a pointer to the INF containing the device entry
  2457. to be checked for compatibility.
  2458. InfLine - Supplies a pointer to the line within the INF containing
  2459. the device information to be checked for compatibility.
  2460. Context - Supplies a pointer to a DRVSEARCH_CONTEXT structure
  2461. containing information on the device instance with which
  2462. the specified INF line must be compatible.
  2463. MatchIndex - Supplies the address of a variable that receives the
  2464. index of the driver node device ID that a match was found for
  2465. (if this routine returns RANK_NO_MATCH, then this variable is
  2466. not filled in).
  2467. If a match was found for the INF's hardware ID, the index is -1,
  2468. otherwise, it is the (zero-based) index into the compatible ID
  2469. list that will be stored for this driver node.
  2470. Return Value:
  2471. The return value is the rank of the match (0 is best, with rank
  2472. increasing for each successive compatible ID and/or INF line string
  2473. field searched). If the specified entry is not a match, then the
  2474. routine returns RANK_NO_MATCH.
  2475. --*/
  2476. {
  2477. UINT Rank = RANK_NO_MATCH, CurrentRank, FieldIndex;
  2478. UINT LastMatchFieldIndex = 0; // shut up preFast
  2479. PCTSTR DeviceIdString;
  2480. LONG DeviceIdVal;
  2481. DWORD DeviceIdStringLength;
  2482. TCHAR TempString[MAX_DEVICE_ID_LEN];
  2483. for(FieldIndex = 2;
  2484. DeviceIdString = InfGetField(Inf, InfLine, FieldIndex, NULL);
  2485. FieldIndex++) {
  2486. //
  2487. // It's OK to hit an empty string for the hardware ID, but we need to
  2488. // bail the first time we see an empty compat ID string.
  2489. //
  2490. if(!(*DeviceIdString) && (FieldIndex > 2)) {
  2491. break;
  2492. }
  2493. if (Context->Flags & DRVSRCH_FILTERSIMILARDRIVERS) {
  2494. if (pSetupIsSimilarDriver(DeviceIdString,
  2495. FieldIndex,
  2496. Context
  2497. )) {
  2498. return 0;
  2499. }
  2500. } else {
  2501. //
  2502. // First, retrieve the string ID corresponding to this device
  2503. // ID in our string table. If it's not in there, then there's
  2504. // no need to waste any time on this ID.
  2505. //
  2506. lstrcpyn(TempString, DeviceIdString, SIZECHARS(TempString));
  2507. if((DeviceIdVal = pStringTableLookUpString(Context->StringTable,
  2508. TempString,
  2509. &DeviceIdStringLength,
  2510. NULL,
  2511. NULL,
  2512. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  2513. NULL,0)) == -1) {
  2514. continue;
  2515. }
  2516. //
  2517. // The device ID is in our string table, so it _may_ be in
  2518. // either our hardware id or compatible id list.
  2519. //
  2520. if(!pSetupCalculateRankMatch(DeviceIdVal,
  2521. FieldIndex,
  2522. Context->IdList,
  2523. &CurrentRank)) {
  2524. //
  2525. // Then we had a match on a hardware ID--that's the best we're gonna get.
  2526. //
  2527. *MatchIndex = (LONG)FieldIndex - 3;
  2528. return CurrentRank;
  2529. } else if(CurrentRank < Rank) {
  2530. //
  2531. // This new rank is better than our current rank.
  2532. //
  2533. LastMatchFieldIndex = (LONG)FieldIndex - 3;
  2534. Rank = CurrentRank;
  2535. }
  2536. }
  2537. }
  2538. if(Rank != RANK_NO_MATCH) {
  2539. *MatchIndex = LastMatchFieldIndex;
  2540. }
  2541. return Rank;
  2542. }
  2543. BOOL
  2544. pSetupCalculateRankMatch(
  2545. IN LONG DriverHwOrCompatId,
  2546. IN UINT InfFieldIndex,
  2547. IN LONG DevIdList[2][MAX_HCID_COUNT+1],
  2548. OUT PUINT Rank
  2549. )
  2550. /*++
  2551. Routine Description:
  2552. This routine calculates the rank match ordinal for the specified driver
  2553. hardware or compatible ID, if it matches one of the hardware or compatible
  2554. IDs for a device.
  2555. Arguments:
  2556. DriverHwOrCompatId - Supplies the string table ID for the ID we're trying to
  2557. find a match for.
  2558. InfFieldIndex - Supplies the index within the INF line where this ID was
  2559. located (2 is hardware ID, 3 and greater is compatible ID).
  2560. DevIdList - Supplies the address of a 2-dimensional array with 2 rows, each
  2561. row containing a list of device IDs that the device has. Each list is
  2562. terminated by an entry containing -1.
  2563. THIS MUST BE DIMENSIONED THE SAME AS THE 'IdList' FIELD OF THE DRVSEARCH_CONTEXT
  2564. STRUCTURE!!!
  2565. Rank - Supplies the address of a variable that receives the rank of the match,
  2566. or RANK_NO_MATCH if there is no match.
  2567. Return Value:
  2568. If there was a match on a hardware ID, then the return value is FALSE (i.e. no
  2569. further searching is needed), otherwise it is TRUE.
  2570. --*/
  2571. {
  2572. int i, j;
  2573. MYASSERT(InfFieldIndex >= 2);
  2574. for(i = 0; i < 2; i++) {
  2575. for(j = 0; DevIdList[i][j] != -1; j++) {
  2576. if(DevIdList[i][j] == DriverHwOrCompatId) {
  2577. //
  2578. // We have a match.
  2579. //
  2580. // The ranks are as follows:
  2581. //
  2582. // Device = HardwareID, INF = HardwareID => 0x0000 - 0x0999
  2583. // Device = HardwareID, INF = CompatID => 0x1000 - 0x1999
  2584. // Device = CompatID, INF = HardwareID => 0x2000 - 0x2999
  2585. // Device = CompatID, INF = CompatID => 0x3000 - 0x????
  2586. //
  2587. if (i == 0) {
  2588. //
  2589. //We matched one of the device's HardwareIDs.
  2590. //
  2591. *Rank = ((InfFieldIndex == 2) ? RANK_HWID_INF_HWID_BASE : RANK_HWID_INF_CID_BASE) + j;
  2592. } else {
  2593. //
  2594. //We matched one of the device's CompatibleIDs.
  2595. //
  2596. *Rank = ((InfFieldIndex == 2) ? RANK_CID_INF_HWID_BASE : RANK_CID_INF_CID_BASE + (RANK_CID_INF_CID_INC * (InfFieldIndex - 3))) + j;
  2597. }
  2598. return (BOOL)i;
  2599. }
  2600. }
  2601. }
  2602. //
  2603. // No match was found.
  2604. //
  2605. *Rank = RANK_NO_MATCH;
  2606. return TRUE;
  2607. }
  2608. BOOL
  2609. pSetupIsSimilarDriver(
  2610. IN PCTSTR DriverHwOrCompatId,
  2611. IN UINT InfFieldIndex,
  2612. IN PDRVSEARCH_CONTEXT Context
  2613. )
  2614. /*++
  2615. Routine Description:
  2616. This routine calculates the rank match ordinal for the specified driver
  2617. hardware or compatible ID, if it matches one of the hardware or compatible
  2618. IDs for a device.
  2619. Arguments:
  2620. DriverHwOrCompatId - Supplies the Hardware or Compatible ID we're trying to
  2621. find a match for.
  2622. InfFieldIndex - Supplies the index within the INF line where this ID was
  2623. located (2 is hardware ID, 3 and greater is compatible ID).
  2624. Context - Supplies a pointer to a DRVSEARCH_CONTEXT structure
  2625. containing information on the device instance with which
  2626. the specified INF line must be compatible.
  2627. Return Value:
  2628. If there is a similar Hardware or Compatible Id match then return TRUE, otherwise
  2629. return FALSE.
  2630. --*/
  2631. {
  2632. int i, j;
  2633. PTSTR String;
  2634. MYASSERT(InfFieldIndex >= 2);
  2635. for(i = 0; i < 2; i++) {
  2636. for(j = 0; Context->IdList[i][j] != -1; j++) {
  2637. String = pStringTableStringFromId(Context->StringTable, Context->IdList[i][j]);
  2638. if (String &&
  2639. _tcsnicmp(String, DriverHwOrCompatId, min(lstrlen(String), lstrlen(DriverHwOrCompatId))) == 0) {
  2640. //
  2641. // We have a match.
  2642. //
  2643. return TRUE;
  2644. }
  2645. }
  2646. }
  2647. //
  2648. // No match was found.
  2649. //
  2650. return FALSE;
  2651. }
  2652. BOOL
  2653. pSetupExcludeId(
  2654. IN PSETUP_LOG_CONTEXT LogContext,
  2655. IN PLOADED_INF Inf,
  2656. IN PCTSTR InfName,
  2657. IN PCTSTR InfSection,
  2658. IN PDRVSEARCH_CONTEXT Context
  2659. )
  2660. /*++
  2661. Routine Description:
  2662. This routine looks in the decorated DDInstall section for ExcludeId values.
  2663. If one of the ExcludeId values match one of the hardware or compatible Ids
  2664. of this hardware then this API will return TRUE indicating that a driver
  2665. node should not be created for this DDInstall section.
  2666. Arguments:
  2667. LogContext - logging context
  2668. Inf - Supplies the PLOADED_INF handle.
  2669. InfName - name of the Inf file, used in logging.
  2670. InfSection - Supplies the fully decorated DDInstall section.
  2671. Context - Supplies a pointer to a DRVSEARCH_CONTEXT structure
  2672. containing information on the device instance with which
  2673. the specified INF line must be compatible.
  2674. Return Value:
  2675. If this inf section should be excluded based on the hardware/compatible Ids
  2676. then return TRUE, otherwise return FALSE.
  2677. --*/
  2678. {
  2679. BOOL bExcludeId = FALSE;
  2680. INFCONTEXT ExcludeIdLineContext;
  2681. DWORD FieldCount, FieldIndex;
  2682. INT i, j;
  2683. PCTSTR ExclDevId, DeviceId;
  2684. //
  2685. // If no hardware id or compatible ids then there is nothing to Exclude.
  2686. //
  2687. if ((Context->IdList[0][0] == -1) &&
  2688. (Context->IdList[1][0] == -1)) {
  2689. return FALSE;
  2690. }
  2691. if (SetupFindFirstLine(Inf,
  2692. InfSection,
  2693. SZ_KEY_EXCLUDEID,
  2694. &ExcludeIdLineContext
  2695. )) {
  2696. do {
  2697. FieldCount = SetupGetFieldCount(&ExcludeIdLineContext);
  2698. for (FieldIndex = 1;
  2699. !bExcludeId && (FieldIndex <= FieldCount);
  2700. FieldIndex++) {
  2701. ExclDevId = pSetupGetField(&ExcludeIdLineContext, FieldIndex);
  2702. //
  2703. // If the Id is NULL then don't bother going through the list
  2704. // of IDs.
  2705. //
  2706. if (!ExclDevId) {
  2707. continue;
  2708. }
  2709. //
  2710. // Enumerate through all of the hardware and compatible Ids for
  2711. // this device and comapre them to the exclude id.
  2712. //
  2713. for(i = 0; !bExcludeId && (i < 2); i++) {
  2714. for(j = 0; Context->IdList[i][j] != -1; j++) {
  2715. DeviceId = pStringTableStringFromId(Context->StringTable,
  2716. Context->IdList[i][j]);
  2717. if(!lstrcmpi(ExclDevId, DeviceId)) {
  2718. //
  2719. // This Hardware/Compatible Id is an ExcludeId, so
  2720. // we will have the API return TRUE so we know
  2721. // to not create a driver node for this Id.
  2722. //
  2723. bExcludeId = TRUE;
  2724. WriteLogEntry(
  2725. LogContext,
  2726. DRIVER_LOG_WARNING,
  2727. MSG_LOG_INF_EXCLUDEID,
  2728. NULL,
  2729. InfName,
  2730. InfSection,
  2731. ExclDevId);
  2732. break;
  2733. }
  2734. }
  2735. }
  2736. }
  2737. } while (!bExcludeId && SetupFindNextMatchLine(&ExcludeIdLineContext,
  2738. SZ_KEY_EXCLUDEID,
  2739. &ExcludeIdLineContext));
  2740. }
  2741. return bExcludeId;
  2742. }
  2743. BOOL
  2744. pSetupGetDeviceIDs(
  2745. IN OUT PDRIVER_NODE DriverNode,
  2746. IN PLOADED_INF Inf,
  2747. IN PINF_LINE InfLine,
  2748. IN OUT PVOID StringTable,
  2749. IN PINF_SECTION CtlFlagsSection OPTIONAL
  2750. )
  2751. /*++
  2752. Routine Description:
  2753. This routine adds INF-defined hardware device ID and compatible
  2754. device IDs to specified DRIVER_NODE.
  2755. Arguments:
  2756. DriverNode - Supplies a pointer to the driver node to update.
  2757. Inf - Supplies a pointer to the INF to retrieve the device IDs from.
  2758. InfLine - Supplies a pointer to the INF line containing the device IDs.
  2759. StringTable - Supplies the handle of a string table to be used for
  2760. storing the device IDs.
  2761. CtlFlagsSection - Optionally, supplies a pointer to the INF's [ControlFlags]
  2762. section, that should be checked to determine whether this device is in
  2763. an 'ExcludeFromSelect' list.
  2764. Return Value:
  2765. If the function succeeds, the return value is TRUE.
  2766. If the function fails, the return value is FALSE (this will fail only if
  2767. an out-of-memory condition is encountered).
  2768. --*/
  2769. {
  2770. PCTSTR DeviceId;
  2771. LONG i, NumCompatIds;
  2772. TCHAR TempString[MAX_DEVICE_ID_LEN];
  2773. PLONG TempIdList;
  2774. //
  2775. // If we already had a compatible ID list, free it now.
  2776. //
  2777. if(DriverNode->CompatIdList) {
  2778. MyFree(DriverNode->CompatIdList);
  2779. DriverNode->CompatIdList = NULL;
  2780. DriverNode->NumCompatIds = 0;
  2781. }
  2782. //
  2783. // Get the hardware ID.
  2784. //
  2785. if(!(DeviceId = InfGetField(Inf, InfLine, 2, NULL))) {
  2786. DriverNode->HardwareId = -1;
  2787. return TRUE;
  2788. } else {
  2789. lstrcpyn(TempString, DeviceId, SIZECHARS(TempString));
  2790. if((DriverNode->HardwareId = pStringTableAddString(StringTable,
  2791. TempString,
  2792. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  2793. NULL,0)) == -1) {
  2794. return FALSE;
  2795. } else {
  2796. //
  2797. // If this INF has a [ControlFlags] section, then check to see if this
  2798. // hardware ID is marked for exclusion
  2799. //
  2800. if(CtlFlagsSection && pSetupShouldDevBeExcluded(DeviceId, Inf, CtlFlagsSection, NULL)) {
  2801. DriverNode->Flags |= DNF_EXCLUDEFROMLIST;
  2802. }
  2803. }
  2804. }
  2805. //
  2806. // Now get the compatible IDs.
  2807. //
  2808. MYASSERT(HASKEY(InfLine));
  2809. NumCompatIds = InfLine->ValueCount - 4;
  2810. if(NumCompatIds > 0) {
  2811. if(!(DriverNode->CompatIdList = MyMalloc(NumCompatIds * sizeof(LONG)))) {
  2812. return FALSE;
  2813. }
  2814. DriverNode->NumCompatIds = (DWORD)NumCompatIds;
  2815. for(i = 0; i < NumCompatIds; i++) {
  2816. if(!(DeviceId = InfGetField(Inf, InfLine, i + 3, NULL)) || !(*DeviceId)) {
  2817. //
  2818. // Just cut the list off here, and return.
  2819. //
  2820. DriverNode->NumCompatIds = i;
  2821. if(i) {
  2822. //
  2823. // Resize the buffer (since we're sizing this down, it should never fail,
  2824. // but it's no big deal if it does).
  2825. //
  2826. if(TempIdList = MyRealloc(DriverNode->CompatIdList, i * sizeof(LONG))) {
  2827. DriverNode->CompatIdList = TempIdList;
  2828. }
  2829. } else {
  2830. MyFree(DriverNode->CompatIdList);
  2831. DriverNode->CompatIdList = NULL;
  2832. }
  2833. return TRUE;
  2834. } else {
  2835. lstrcpyn(TempString, DeviceId, SIZECHARS(TempString));
  2836. if((DriverNode->CompatIdList[i] = pStringTableAddString(
  2837. StringTable,
  2838. TempString,
  2839. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  2840. NULL,0)) == -1) {
  2841. MyFree(DriverNode->CompatIdList);
  2842. DriverNode->CompatIdList = NULL;
  2843. DriverNode->NumCompatIds = 0;
  2844. return FALSE;
  2845. }
  2846. }
  2847. }
  2848. }
  2849. return TRUE;
  2850. }
  2851. BOOL
  2852. pSetupShouldDeviceBeExcluded(
  2853. IN PCTSTR DeviceId,
  2854. IN HINF hInf,
  2855. OUT PBOOL ArchitectureSpecificExclude OPTIONAL
  2856. )
  2857. /*++
  2858. Routine Description:
  2859. This routine is a public wrapper to our private API, pSetupShouldDevBeExcluded.
  2860. Refer to the documentation for that routine for a description of this API's
  2861. behavior.
  2862. WARNING!! THIS ROUTINE DOES NOT HANDLE APPEND-LOADED INFS!!!
  2863. Arguments:
  2864. DeviceId - Supplies the device ID to check for. This string may
  2865. be empty, in which case the device is excluded only if a wildcard
  2866. ('*') is found.
  2867. Inf - Supplies the handle of the INF to check in.
  2868. ArchitectureSpecificExclude - Optionally, supplies the address of a variable
  2869. that receives a boolean value indicating whether or not the exclusion was
  2870. architecture-specific (e.g., ExcludeFromSelect.NT<Platform>). If this
  2871. routine returns FALSE, then the contents of this variable are undefined.
  2872. Return Value:
  2873. Returns TRUE if the ID is in the list (i.e., it should be excluded),
  2874. FALSE if it is not.
  2875. --*/
  2876. {
  2877. BOOL IsExcluded;
  2878. PINF_SECTION CtlFlagsSection;
  2879. if(!LockInf((PLOADED_INF)hInf)) {
  2880. return FALSE;
  2881. }
  2882. IsExcluded = FALSE;
  2883. //
  2884. // Now attempt to locate a [ControlFlags] section in this INF.
  2885. //
  2886. if(CtlFlagsSection = InfLocateSection((PLOADED_INF)hInf, pszControlFlags, NULL)) {
  2887. //
  2888. // This section is present--check to see if the specified device ID is marked
  2889. // for exclusion.
  2890. //
  2891. IsExcluded = pSetupShouldDevBeExcluded(DeviceId,
  2892. (PLOADED_INF)hInf,
  2893. CtlFlagsSection,
  2894. ArchitectureSpecificExclude
  2895. );
  2896. }
  2897. UnlockInf((PLOADED_INF)hInf);
  2898. return IsExcluded;
  2899. }
  2900. BOOL
  2901. pSetupShouldDevBeExcluded(
  2902. IN PCTSTR DeviceId,
  2903. IN PLOADED_INF Inf,
  2904. IN PINF_SECTION CtlFlagsSection,
  2905. OUT PBOOL ArchitectureSpecificExclude OPTIONAL
  2906. )
  2907. /*++
  2908. Routine Description:
  2909. This routine determines if a passed-in Device ID is in an
  2910. 'ExludeFromSelect' line in the specified INF's [ControlFlags] section.
  2911. It also checks any lines of the form "ExcludeFromSelect.<OS>", where
  2912. <OS> is either "Win" or "NT", depending on which OS we're running on
  2913. (determined dynamically). Finally, if we're running on NT, we append
  2914. the platform type, and look for lines of the form
  2915. "ExcludeFromSelect.NT<Platform>", where <Platform> is either "X86",
  2916. "MIPS", "Alpha", or "PPC".
  2917. Arguments:
  2918. DeviceId - Supplies the device ID to check for. This string may
  2919. be empty, in which case the device is excluded only if a wildcard
  2920. ('*') is found.
  2921. Inf - Supplies a pointer to the INF to check in.
  2922. CtlFlagsSection - Supplies a pointer to the INF's [ControlFlags] section.
  2923. ArchitectureSpecificExclude - Optionally, supplies the address of a variable
  2924. that receives a boolean value indicating whether or not the exclusion was
  2925. architecture-specific (e.g., ExcludeFromSelect.NT<Platform>). If this
  2926. routine returns FALSE, then the contents of this variable are undefined.
  2927. Return Value:
  2928. Returns TRUE if the ID is in the list (i.e., it should be excluded),
  2929. FALSE if it is not.
  2930. --*/
  2931. {
  2932. PINF_LINE CtlFlagsLine;
  2933. UINT CtlFlagsIndex, i, j, StringIdUb, PlatformSpecificIndex;
  2934. PCTSTR ExclDevId;
  2935. LONG StringIdList[3];
  2936. LONG KeyStringId;
  2937. DWORD StringLength;
  2938. //
  2939. // Retrieve the list of string IDs for the keys we should be looking for in the
  2940. // [ControlFlags] section.
  2941. //
  2942. StringIdUb = 0;
  2943. PlatformSpecificIndex = (UINT)-1; // initially, assume no "ExcludeFromSelect.NT<Platform>"
  2944. for(i = 0; i < ExcludeFromSelectListUb; i++) {
  2945. if((StringIdList[StringIdUb] = pStringTableLookUpString(
  2946. Inf->StringTable,
  2947. pszExcludeFromSelectList[i],
  2948. &StringLength,
  2949. NULL,
  2950. NULL,
  2951. STRTAB_CASE_INSENSITIVE | STRTAB_ALREADY_LOWERCASE,
  2952. NULL,0)) != -1) {
  2953. //
  2954. // If the index is 2, then we've found architecture-specific exlude lines.
  2955. // Record the resulting index of this element, so we can determine later
  2956. // whether we were excluded because of what platform we're on.
  2957. //
  2958. if(i == 2) {
  2959. PlatformSpecificIndex = StringIdUb;
  2960. }
  2961. StringIdUb++;
  2962. }
  2963. }
  2964. if(StringIdUb) {
  2965. //
  2966. // There are some ExcludeFromSelect* lines--examine each line.
  2967. //
  2968. for(CtlFlagsIndex = 0;
  2969. InfLocateLine(Inf, CtlFlagsSection, NULL, &CtlFlagsIndex, &CtlFlagsLine);
  2970. CtlFlagsIndex++) {
  2971. //
  2972. // We can't use InfGetField() to retrieve the string ID of the line's key,
  2973. // since it will give us the case-sensitive form, and we must use the
  2974. // case-insensitive (i.e., lowercase) version for our fast matching scheme.
  2975. //
  2976. if((KeyStringId = pInfGetLineKeyId(Inf, CtlFlagsLine)) != -1) {
  2977. //
  2978. // Check the string ID of this line's key against the string IDs we're
  2979. // interested in.
  2980. //
  2981. for(i = 0; i < StringIdUb; i++) {
  2982. if(KeyStringId == StringIdList[i]) {
  2983. break;
  2984. }
  2985. }
  2986. //
  2987. // If we looked at all entries, and didn't find a match, then skip this
  2988. // line and continue with the next one.
  2989. //
  2990. if(i >= StringIdUb) {
  2991. continue;
  2992. }
  2993. for(j = 1;
  2994. ExclDevId = InfGetField(Inf, CtlFlagsLine, j, NULL);
  2995. j++) {
  2996. //
  2997. // If we find a lone asterisk, treat it as a wildcard, and
  2998. // return TRUE. Otherwise return TRUE only if the device IDs match.
  2999. //
  3000. if(((*ExclDevId == TEXT('*')) && (ExclDevId[1] == TEXT('\0'))) ||
  3001. !lstrcmpi(ExclDevId, DeviceId)) {
  3002. //
  3003. // This device ID is to be excluded. If the caller requested it,
  3004. // store a boolean in their output variable indicating whether this
  3005. // was an architecture-specific exclusion.
  3006. //
  3007. if(ArchitectureSpecificExclude) {
  3008. *ArchitectureSpecificExclude = (i == PlatformSpecificIndex);
  3009. }
  3010. return TRUE;
  3011. }
  3012. }
  3013. }
  3014. }
  3015. }
  3016. return FALSE;
  3017. }
  3018. VOID
  3019. pSetupMergeDriverNode(
  3020. IN OUT PDRVSEARCH_CONTEXT Context,
  3021. IN PDRIVER_NODE NewDriverNode,
  3022. OUT PBOOL InsertedAtHead
  3023. )
  3024. /*++
  3025. Routine Description:
  3026. This routine merges a driver node into a driver node linked list.
  3027. If the list is empty the passed in DRIVER_NODE will be inserted at the
  3028. head of the list. If the list contains any DRIVER_NODEs, new node will
  3029. be merged as follows: The new node will be inserted in front of any
  3030. nodes with a higher rank. If the rank is the same, the new node will be
  3031. grouped with other nodes having the same manufacturer. The new node will
  3032. be inserted at the end of the group. If the node is an exact duplicate
  3033. of an existing node, meaning that its rank, description, manufacturer,
  3034. and provider are all the same, then the node will be deleted (unless the
  3035. existing node is marked as excluded and the new node is not, in which case
  3036. the existing node will be discarded instead).
  3037. Arguments:
  3038. Context - Supplies a pointer to a DRVSEARCH_CONTEXT structure containing
  3039. the list head, list tail, and list node count.
  3040. NewDriverNode - Supplies a pointer to the driver node to be inserted.
  3041. InsertedAtHead - Supplies a pointer to a variable that receives a flag
  3042. indicating if the new driver was inserted at the head of the list.
  3043. Return Value:
  3044. None.
  3045. --*/
  3046. {
  3047. PDRIVER_NODE PrevDrvNode, CurDrvNode, DrvNodeToDelete;
  3048. DWORD MatchFlags = 0;
  3049. BOOL bDeleteNewDriverNode;
  3050. PTSTR CurDrvNodeInfFile = NULL, NewDrvNodeInfFile = NULL;
  3051. for(CurDrvNode = *(Context->pDriverListHead), PrevDrvNode = NULL;
  3052. CurDrvNode;
  3053. PrevDrvNode = CurDrvNode, CurDrvNode = CurDrvNode->Next) {
  3054. if(NewDriverNode->MfgName != CurDrvNode->MfgName) {
  3055. if(MatchFlags & 0x2) {
  3056. break;
  3057. }
  3058. } else {
  3059. MatchFlags |= 0x2;
  3060. if(NewDriverNode->DevDescription != CurDrvNode->DevDescription) {
  3061. if(MatchFlags & 0x4) {
  3062. break;
  3063. }
  3064. } else {
  3065. MatchFlags |= 0x4;
  3066. if(NewDriverNode->ProviderName != CurDrvNode->ProviderName) {
  3067. //
  3068. // We will only set the DNF_DUPDESC flags if both drivers do not
  3069. // have either the DNF_OLD_INET_DRIVER or the DNF_BAD_DRIVER
  3070. // flags set.
  3071. //
  3072. if (!(CurDrvNode->Flags & DNF_OLD_INET_DRIVER) &&
  3073. !(CurDrvNode->Flags & DNF_BAD_DRIVER) &&
  3074. !(NewDriverNode->Flags & DNF_OLD_INET_DRIVER) &&
  3075. !(NewDriverNode->Flags & DNF_BAD_DRIVER)) {
  3076. NewDriverNode->Flags |= DNF_DUPDESC;
  3077. CurDrvNode->Flags |= DNF_DUPDESC;
  3078. }
  3079. if (MatchFlags & 0x8) {
  3080. break;
  3081. }
  3082. } else {
  3083. MatchFlags |=0x8;
  3084. if ((NewDriverNode->DriverDate.dwLowDateTime != CurDrvNode->DriverDate.dwLowDateTime) ||
  3085. (NewDriverNode->DriverDate.dwHighDateTime != CurDrvNode->DriverDate.dwHighDateTime) ||
  3086. (NewDriverNode->DriverVersion != CurDrvNode->DriverVersion)) {
  3087. //
  3088. // We will only set the DNF_DUPPROVIDER flags if both drivers do not
  3089. // have either the DNF_OLD_INET_DRIVER or the DNF_BAD_DRIVER
  3090. // flags set.
  3091. //
  3092. if (!(CurDrvNode->Flags & DNF_OLD_INET_DRIVER) &&
  3093. !(CurDrvNode->Flags & DNF_BAD_DRIVER) &&
  3094. !(NewDriverNode->Flags & DNF_OLD_INET_DRIVER) &&
  3095. !(NewDriverNode->Flags & DNF_BAD_DRIVER)) {
  3096. NewDriverNode->Flags |= DNF_DUPPROVIDER;
  3097. CurDrvNode->Flags |= DNF_DUPPROVIDER;
  3098. }
  3099. if (MatchFlags & 0x10) {
  3100. break;
  3101. }
  3102. } else {
  3103. MatchFlags |=0x10;
  3104. bDeleteNewDriverNode = TRUE;
  3105. if ((NewDriverNode->Rank != CurDrvNode->Rank) ||
  3106. (Context->Flags & DRVSRCH_NO_CLASSLIST_NODE_MERGE)) {
  3107. //
  3108. // The ranks are different, or the caller wants to
  3109. // include all INFs in the class list, so don't
  3110. // delete the new driver node.
  3111. //
  3112. bDeleteNewDriverNode = FALSE;
  3113. } else {
  3114. //
  3115. // In order to see if the INFs are identical first
  3116. // check if both INFs live in the same locations
  3117. // (meaning both live in the INF directory or both
  3118. // live in an Oem location). If so then we will just
  3119. // compare the filenames to see if the INFs are the
  3120. // same. If one INF lives in the INF directory and
  3121. // the other lives in an Oem location then do a
  3122. // binary compare on the INF files to see if they
  3123. // are identical.
  3124. //
  3125. BOOL bCurDrvNodeInOemDir, bNewDrvNodeInOemDir;
  3126. CurDrvNodeInfFile = pStringTableStringFromId(Context->StringTable,
  3127. CurDrvNode->InfFileName
  3128. );
  3129. bCurDrvNodeInOemDir = pSetupInfIsFromOemLocation(CurDrvNodeInfFile, TRUE);
  3130. NewDrvNodeInfFile = pStringTableStringFromId(Context->StringTable,
  3131. NewDriverNode->InfFileName
  3132. );
  3133. bNewDrvNodeInOemDir = pSetupInfIsFromOemLocation(NewDrvNodeInfFile, TRUE);
  3134. if ((bCurDrvNodeInOemDir && bNewDrvNodeInOemDir) ||
  3135. (!bCurDrvNodeInOemDir && !bNewDrvNodeInOemDir)) {
  3136. //
  3137. // Since both these INFs live in the same location
  3138. // the new INF will get deleted only the two
  3139. // INF paths are identical.
  3140. //
  3141. bDeleteNewDriverNode = (CurDrvNode->InfFileName ==
  3142. NewDriverNode->InfFileName);
  3143. } else {
  3144. //
  3145. // At least one of the INFs lives in the INF
  3146. // directory and the other lives in an Oem
  3147. // location so the new INF will get deleted only
  3148. // if the two INFs are identical.
  3149. //
  3150. bDeleteNewDriverNode = pCompareFilesExact(CurDrvNodeInfFile,
  3151. NewDrvNodeInfFile);
  3152. }
  3153. }
  3154. if (bDeleteNewDriverNode) {
  3155. //
  3156. // This is an exact match of description, rank,
  3157. // provider, DriverVer date, DriverVer version, and
  3158. // the Infs files. Delete the node, unless
  3159. // the existing node is excluded, and this one is not,
  3160. // or the existing node is a bad driver and the new
  3161. // one is not.
  3162. //
  3163. if (((CurDrvNode->Flags & DNF_EXCLUDEFROMLIST) &&
  3164. !(NewDriverNode->Flags & DNF_EXCLUDEFROMLIST)) ||
  3165. ((CurDrvNode->Flags & DNF_BAD_DRIVER) &&
  3166. !(NewDriverNode->Flags & DNF_BAD_DRIVER))) {
  3167. //
  3168. // Remove the old driver node so we can replace it with
  3169. // the new one. (Don't worry about updating the tail
  3170. // pointer--it will get fixed up later.)
  3171. //
  3172. // If this current node is from the Internet then do not
  3173. // delete it now because when we delete a driver node from
  3174. // the Internet we remove all of the files in the temp path
  3175. // and some other driver node might still need thos files.
  3176. //
  3177. if (!(CurDrvNode->Flags & DNF_INET_DRIVER)) {
  3178. DrvNodeToDelete = CurDrvNode;
  3179. CurDrvNode = CurDrvNode->Next;
  3180. if(PrevDrvNode) {
  3181. PrevDrvNode->Next = CurDrvNode;
  3182. } else {
  3183. *(Context->pDriverListHead) = CurDrvNode;
  3184. }
  3185. DrvNodeToDelete->Next = NULL; // just want to delete this one.
  3186. DestroyDriverNodes(DrvNodeToDelete, Context->DeviceInfoSet);
  3187. (*(Context->pDriverCount))--;
  3188. }
  3189. break;
  3190. } else {
  3191. //
  3192. // Don't delete this new driver node, even though it is a dup,
  3193. // if if it is from the Internet
  3194. //
  3195. if (!(NewDriverNode->Flags & DNF_INET_DRIVER)) {
  3196. NewDriverNode->Next = NULL; // just want to delete this one.
  3197. DestroyDriverNodes(NewDriverNode, Context->DeviceInfoSet);
  3198. *InsertedAtHead = FALSE;
  3199. return;
  3200. }
  3201. }
  3202. } else {
  3203. //
  3204. // We will only set the DNF_DUPDRIVERVER flag if the other driver
  3205. // node does not have either the DNF_OLD_INET_DRIVER or the
  3206. // DNF_BAD_DRIVER flag set.
  3207. //
  3208. if (!(CurDrvNode->Flags & DNF_OLD_INET_DRIVER) &&
  3209. !(CurDrvNode->Flags & DNF_BAD_DRIVER) &&
  3210. !(NewDriverNode->Flags & DNF_OLD_INET_DRIVER) &&
  3211. !(NewDriverNode->Flags & DNF_BAD_DRIVER)) {
  3212. NewDriverNode->Flags |= DNF_DUPDRIVERVER;
  3213. CurDrvNode->Flags |= DNF_DUPDRIVERVER;
  3214. }
  3215. }
  3216. }
  3217. }
  3218. }
  3219. }
  3220. }
  3221. if(!(NewDriverNode->Next = CurDrvNode)) {
  3222. *(Context->pDriverListTail) = NewDriverNode;
  3223. }
  3224. if(PrevDrvNode) {
  3225. PrevDrvNode->Next = NewDriverNode;
  3226. *InsertedAtHead = FALSE;
  3227. } else {
  3228. *(Context->pDriverListHead) = NewDriverNode;
  3229. *InsertedAtHead = TRUE;
  3230. }
  3231. (*(Context->pDriverCount))++;
  3232. }
  3233. #ifdef UNICODE
  3234. //
  3235. // ANSI version
  3236. //
  3237. BOOL
  3238. WINAPI
  3239. SetupDiEnumDriverInfoA(
  3240. IN HDEVINFO DeviceInfoSet,
  3241. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  3242. IN DWORD DriverType,
  3243. IN DWORD MemberIndex,
  3244. OUT PSP_DRVINFO_DATA_A DriverInfoData
  3245. )
  3246. {
  3247. BOOL b;
  3248. DWORD rc;
  3249. SP_DRVINFO_DATA_W driverInfoData;
  3250. driverInfoData.cbSize = sizeof(SP_DRVINFO_DATA_W);
  3251. b = SetupDiEnumDriverInfoW(
  3252. DeviceInfoSet,
  3253. DeviceInfoData,
  3254. DriverType,
  3255. MemberIndex,
  3256. &driverInfoData
  3257. );
  3258. rc = GetLastError();
  3259. if(b) {
  3260. rc = pSetupDiDrvInfoDataUnicodeToAnsi(&driverInfoData,DriverInfoData);
  3261. if(rc != NO_ERROR) {
  3262. b = FALSE;
  3263. }
  3264. }
  3265. SetLastError(rc);
  3266. return(b);
  3267. }
  3268. #else
  3269. //
  3270. // Unicode stub
  3271. //
  3272. BOOL
  3273. WINAPI
  3274. SetupDiEnumDriverInfoW(
  3275. IN HDEVINFO DeviceInfoSet,
  3276. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  3277. IN DWORD DriverType,
  3278. IN DWORD MemberIndex,
  3279. OUT PSP_DRVINFO_DATA_W DriverInfoData
  3280. )
  3281. {
  3282. UNREFERENCED_PARAMETER(DeviceInfoSet);
  3283. UNREFERENCED_PARAMETER(DeviceInfoData);
  3284. UNREFERENCED_PARAMETER(DriverType);
  3285. UNREFERENCED_PARAMETER(MemberIndex);
  3286. UNREFERENCED_PARAMETER(DriverInfoData);
  3287. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  3288. return(FALSE);
  3289. }
  3290. #endif
  3291. BOOL
  3292. WINAPI
  3293. SetupDiEnumDriverInfo(
  3294. IN HDEVINFO DeviceInfoSet,
  3295. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  3296. IN DWORD DriverType,
  3297. IN DWORD MemberIndex,
  3298. OUT PSP_DRVINFO_DATA DriverInfoData
  3299. )
  3300. /*++
  3301. Routine Description:
  3302. This routine enumerates the members of a driver information list.
  3303. Arguments:
  3304. DeviceInfoSet - Supplies a handle to a device information set containing
  3305. a driver info list to be enumerated.
  3306. DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
  3307. structure that contains a driver info list to be enumerated. If this
  3308. parameter is not specified, then the 'global' driver list owned by the
  3309. device information set is used (this list will be of type
  3310. SPDIT_CLASSDRIVER).
  3311. DriverType - Specifies what type of driver list to enumerate. Must be
  3312. one of the following values:
  3313. SPDIT_CLASSDRIVER -- Enumerate a class driver list.
  3314. SPDIT_COMPATDRIVER -- Enumerate a list of drivers for the specified
  3315. device. DeviceInfoData must be specified if
  3316. this value is used.
  3317. MemberIndex - Supplies the zero-based index of the driver information member
  3318. to be retrieved.
  3319. DriverInfoData - Supplies the address of a SP_DRVINFO_DATA structure that will
  3320. receive information about the enumerated driver.
  3321. Return Value:
  3322. If the function succeeds, the return value is TRUE.
  3323. If the function fails, the return value is FALSE. To get extended error
  3324. information, call GetLastError.
  3325. Remarks:
  3326. To enumerate driver information members, an application should initialy call
  3327. the SetupDiEnumDriverInfo function with the MemberIndex parameter set to zero.
  3328. The application should then increment MemberIndex and call the SetupDiEnumDriverInfo
  3329. function until there are no more values (i.e., the function fails, and GetLastError
  3330. returns ERROR_NO_MORE_ITEMS).
  3331. --*/
  3332. {
  3333. PDEVICE_INFO_SET pDeviceInfoSet;
  3334. DWORD Err;
  3335. PDEVINFO_ELEM DevInfoElem;
  3336. UINT DriverCount, i;
  3337. PDRIVER_NODE DriverNode;
  3338. PDRIVER_NODE *DriverEnumHint;
  3339. DWORD *DriverEnumHintIndex;
  3340. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  3341. SetLastError(ERROR_INVALID_HANDLE);
  3342. return FALSE;
  3343. }
  3344. Err = NO_ERROR;
  3345. try {
  3346. if(DeviceInfoData) {
  3347. //
  3348. // Then we are to enumerate a driver list for a particular
  3349. // device.
  3350. //
  3351. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  3352. DeviceInfoData,
  3353. NULL))) {
  3354. Err = ERROR_INVALID_PARAMETER;
  3355. goto clean0;
  3356. }
  3357. }
  3358. switch(DriverType) {
  3359. case SPDIT_CLASSDRIVER :
  3360. if(DeviceInfoData) {
  3361. //
  3362. // Enumerate class driver list for a particular device.
  3363. //
  3364. DriverCount = DevInfoElem->ClassDriverCount;
  3365. DriverNode = DevInfoElem->ClassDriverHead;
  3366. DriverEnumHint = &(DevInfoElem->ClassDriverEnumHint);
  3367. DriverEnumHintIndex = &(DevInfoElem->ClassDriverEnumHintIndex);
  3368. } else {
  3369. //
  3370. // Enumerate the global class driver list.
  3371. //
  3372. DriverCount = pDeviceInfoSet->ClassDriverCount;
  3373. DriverNode = pDeviceInfoSet->ClassDriverHead;
  3374. DriverEnumHint = &(pDeviceInfoSet->ClassDriverEnumHint);
  3375. DriverEnumHintIndex = &(pDeviceInfoSet->ClassDriverEnumHintIndex);
  3376. }
  3377. break;
  3378. case SPDIT_COMPATDRIVER :
  3379. if(DeviceInfoData) {
  3380. DriverCount = DevInfoElem->CompatDriverCount;
  3381. DriverNode = DevInfoElem->CompatDriverHead;
  3382. DriverEnumHint = &(DevInfoElem->CompatDriverEnumHint);
  3383. DriverEnumHintIndex = &(DevInfoElem->CompatDriverEnumHintIndex);
  3384. break;
  3385. }
  3386. //
  3387. // otherwise, let fall through for error condition.
  3388. //
  3389. default :
  3390. Err = ERROR_INVALID_PARAMETER;
  3391. goto clean0;
  3392. }
  3393. if(MemberIndex >= DriverCount) {
  3394. Err = ERROR_NO_MORE_ITEMS;
  3395. goto clean0;
  3396. }
  3397. //
  3398. // Find the element corresponding to the specified index (using our
  3399. // enumeration hint optimization, if possible)
  3400. //
  3401. if(*DriverEnumHintIndex <= MemberIndex) {
  3402. MYASSERT(*DriverEnumHint);
  3403. DriverNode = *DriverEnumHint;
  3404. i = *DriverEnumHintIndex;
  3405. } else {
  3406. i = 0;
  3407. }
  3408. for(; i < MemberIndex; i++) {
  3409. DriverNode = DriverNode->Next;
  3410. }
  3411. if(!DrvInfoDataFromDriverNode(pDeviceInfoSet,
  3412. DriverNode,
  3413. DriverType,
  3414. DriverInfoData)) {
  3415. Err = ERROR_INVALID_USER_BUFFER;
  3416. }
  3417. //
  3418. // Remember this element as our new enumeration hint.
  3419. //
  3420. *DriverEnumHintIndex = MemberIndex;
  3421. *DriverEnumHint = DriverNode;
  3422. clean0: ; // Nothing to do.
  3423. } except(EXCEPTION_EXECUTE_HANDLER) {
  3424. Err = ERROR_INVALID_PARAMETER;
  3425. }
  3426. UnlockDeviceInfoSet(pDeviceInfoSet);
  3427. SetLastError(Err);
  3428. return(Err == NO_ERROR);
  3429. }
  3430. #ifdef UNICODE
  3431. //
  3432. // ANSI version
  3433. //
  3434. BOOL
  3435. WINAPI
  3436. SetupDiGetSelectedDriverA(
  3437. IN HDEVINFO DeviceInfoSet,
  3438. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  3439. OUT PSP_DRVINFO_DATA_A DriverInfoData
  3440. )
  3441. {
  3442. DWORD rc;
  3443. BOOL b;
  3444. SP_DRVINFO_DATA_W driverInfoData;
  3445. driverInfoData.cbSize = sizeof(SP_DRVINFO_DATA_W);
  3446. b = SetupDiGetSelectedDriverW(DeviceInfoSet,DeviceInfoData,&driverInfoData);
  3447. rc = GetLastError();
  3448. if(b) {
  3449. rc = pSetupDiDrvInfoDataUnicodeToAnsi(&driverInfoData,DriverInfoData);
  3450. if(rc != NO_ERROR) {
  3451. b = FALSE;
  3452. }
  3453. }
  3454. SetLastError(rc);
  3455. return(b);
  3456. }
  3457. #else
  3458. //
  3459. // Unicode stub
  3460. //
  3461. BOOL
  3462. WINAPI
  3463. SetupDiGetSelectedDriverW(
  3464. IN HDEVINFO DeviceInfoSet,
  3465. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  3466. OUT PSP_DRVINFO_DATA_W DriverInfoData
  3467. )
  3468. {
  3469. UNREFERENCED_PARAMETER(DeviceInfoSet);
  3470. UNREFERENCED_PARAMETER(DeviceInfoData);
  3471. UNREFERENCED_PARAMETER(DriverInfoData);
  3472. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  3473. return(FALSE);
  3474. }
  3475. #endif
  3476. BOOL
  3477. WINAPI
  3478. SetupDiGetSelectedDriver(
  3479. IN HDEVINFO DeviceInfoSet,
  3480. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  3481. OUT PSP_DRVINFO_DATA DriverInfoData
  3482. )
  3483. /*++
  3484. Routine Description:
  3485. This routine retrieves the member of a driver list that has been selected
  3486. as the controlling driver.
  3487. Arguments:
  3488. DeviceInfoSet - Supplies a handle to the device information set to be queried.
  3489. DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
  3490. structure for the device information element to retrieve the selected
  3491. driver for. If this parameter is NULL, then the selected class driver
  3492. for the global class driver list will be retrieved.
  3493. DriverInfoData - Supplies the address of a SP_DRVINFO_DATA structure that receives
  3494. the currently selected driver.
  3495. Return Value:
  3496. If the function succeeds, the return value is TRUE.
  3497. If the function fails, the return value is FALSE. To get extended error
  3498. information, call GetLastError. If no driver has been selected yet, the
  3499. error will be ERROR_NO_DRIVER_SELECTED.
  3500. --*/
  3501. {
  3502. PDEVICE_INFO_SET pDeviceInfoSet;
  3503. DWORD Err, DriverType;
  3504. PDEVINFO_ELEM DevInfoElem;
  3505. PDRIVER_NODE DriverNode;
  3506. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  3507. SetLastError(ERROR_INVALID_HANDLE);
  3508. return FALSE;
  3509. }
  3510. Err = NO_ERROR;
  3511. try {
  3512. if(DeviceInfoData) {
  3513. //
  3514. // Then we are to retrieve the selected driver for a particular device.
  3515. //
  3516. if(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  3517. DeviceInfoData,
  3518. NULL)) {
  3519. DriverNode = DevInfoElem->SelectedDriver;
  3520. DriverType = DevInfoElem->SelectedDriverType;
  3521. } else {
  3522. Err = ERROR_INVALID_PARAMETER;
  3523. goto clean0;
  3524. }
  3525. } else {
  3526. DriverNode = pDeviceInfoSet->SelectedClassDriver;
  3527. DriverType = SPDIT_CLASSDRIVER;
  3528. }
  3529. if(DriverNode) {
  3530. if(!DrvInfoDataFromDriverNode(pDeviceInfoSet,
  3531. DriverNode,
  3532. DriverType,
  3533. DriverInfoData)) {
  3534. Err = ERROR_INVALID_USER_BUFFER;
  3535. }
  3536. } else {
  3537. Err = ERROR_NO_DRIVER_SELECTED;
  3538. }
  3539. clean0: ; // Nothing to do.
  3540. } except(EXCEPTION_EXECUTE_HANDLER) {
  3541. Err = ERROR_INVALID_PARAMETER;
  3542. }
  3543. UnlockDeviceInfoSet(pDeviceInfoSet);
  3544. SetLastError(Err);
  3545. return(Err == NO_ERROR);
  3546. }
  3547. #ifdef UNICODE
  3548. //
  3549. // ANSI version
  3550. //
  3551. BOOL
  3552. WINAPI
  3553. SetupDiSetSelectedDriverA(
  3554. IN HDEVINFO DeviceInfoSet,
  3555. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  3556. IN OUT PSP_DRVINFO_DATA_A DriverInfoData OPTIONAL
  3557. )
  3558. {
  3559. SP_DRVINFO_DATA_W driverInfoData;
  3560. DWORD rc;
  3561. BOOL b;
  3562. if(DriverInfoData) {
  3563. rc = pSetupDiDrvInfoDataAnsiToUnicode(DriverInfoData,&driverInfoData);
  3564. if(rc != NO_ERROR) {
  3565. SetLastError(rc);
  3566. return(FALSE);
  3567. }
  3568. }
  3569. b = SetupDiSetSelectedDriverW(
  3570. DeviceInfoSet,
  3571. DeviceInfoData,
  3572. DriverInfoData ? &driverInfoData : NULL
  3573. );
  3574. rc = GetLastError();
  3575. if(b && DriverInfoData) {
  3576. rc = pSetupDiDrvInfoDataUnicodeToAnsi(&driverInfoData,DriverInfoData);
  3577. if(rc != NO_ERROR) {
  3578. b = FALSE;
  3579. }
  3580. }
  3581. SetLastError(rc);
  3582. return(b);
  3583. }
  3584. #else
  3585. //
  3586. // Unicode stub
  3587. //
  3588. BOOL
  3589. WINAPI
  3590. SetupDiSetSelectedDriverW(
  3591. IN HDEVINFO DeviceInfoSet,
  3592. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  3593. IN OUT PSP_DRVINFO_DATA_W DriverInfoData OPTIONAL
  3594. )
  3595. {
  3596. UNREFERENCED_PARAMETER(DeviceInfoSet);
  3597. UNREFERENCED_PARAMETER(DeviceInfoData);
  3598. UNREFERENCED_PARAMETER(DriverInfoData);
  3599. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  3600. return(FALSE);
  3601. }
  3602. #endif
  3603. BOOL
  3604. WINAPI
  3605. SetupDiSetSelectedDriver(
  3606. IN HDEVINFO DeviceInfoSet,
  3607. IN OUT PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  3608. IN OUT PSP_DRVINFO_DATA DriverInfoData OPTIONAL
  3609. )
  3610. /*++
  3611. Routine Description:
  3612. This routine sets the specified member of a driver list to be the currently
  3613. selected driver. It also allows the driver list to be reset, so that no
  3614. driver is currently selected.
  3615. Arguments:
  3616. DeviceInfoSet - Supplies a handle to the device information set for which a
  3617. driver is to be selected.
  3618. DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
  3619. structure for the device information element to select a driver for.
  3620. If this parameter is NULL, then a class driver for the global class
  3621. driver list will be selected.
  3622. This is an IN OUT parameter because the class GUID for the device will be
  3623. updated to reflect the class of the driver selected.
  3624. DriverInfoData - If this parameter is specified, then it supplies the address
  3625. of a driver information structure indicating the driver to be selected.
  3626. If this parameter is NULL, then the driver list is to be reset (i.e., no
  3627. driver selected).
  3628. If the 'Reserved' field of this structure is 0, then this signifies that
  3629. the caller is requesting a search for a driver node with the specified
  3630. parameters (DriverType, Description, MfgName, and ProviderName). If a
  3631. match is found, then that driver node will be selected, otherwise, the API
  3632. will fail, with GetLastError() returning ERROR_INVALID_PARAMETER.
  3633. If the 'Reserved' field is 0, and a match is found, then the 'Reserved' field
  3634. will be updated on output to reflect the actual driver node where the match
  3635. was found.
  3636. Return Value:
  3637. If the function succeeds, the return value is TRUE.
  3638. If the function fails, the return value is FALSE. To get extended error
  3639. information, call GetLastError.
  3640. --*/
  3641. {
  3642. PDEVICE_INFO_SET pDeviceInfoSet;
  3643. DWORD Err;
  3644. PDEVINFO_ELEM DevInfoElem;
  3645. PDRIVER_NODE DriverListHead, DriverNode;
  3646. PDRIVER_NODE *pSelectedDriver;
  3647. PDWORD pSelectedDriverType;
  3648. DWORD DriverType;
  3649. TCHAR ClassGuidString[GUID_STRING_LEN];
  3650. TCHAR OldClassGuidString[GUID_STRING_LEN];
  3651. BOOL NoGuidUpdate = FALSE;
  3652. DWORD PropType;
  3653. PSETUP_LOG_CONTEXT LogContext = NULL;
  3654. DWORD slot_section = 0;
  3655. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  3656. Err = ERROR_INVALID_HANDLE;
  3657. goto clean1;
  3658. }
  3659. LogContext = pDeviceInfoSet->InstallParamBlock.LogContext;
  3660. Err = NO_ERROR;
  3661. try {
  3662. if(DeviceInfoData) {
  3663. //
  3664. // Then we are to select a driver for a particular device.
  3665. //
  3666. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  3667. DeviceInfoData,
  3668. NULL))) {
  3669. Err = ERROR_INVALID_PARAMETER;
  3670. goto clean0;
  3671. }
  3672. LogContext = DevInfoElem->InstallParamBlock.LogContext;
  3673. pSelectedDriver = &(DevInfoElem->SelectedDriver);
  3674. pSelectedDriverType = &(DevInfoElem->SelectedDriverType);
  3675. } else {
  3676. pSelectedDriver = &(pDeviceInfoSet->SelectedClassDriver);
  3677. pSelectedDriverType = NULL;
  3678. }
  3679. if(!DriverInfoData) {
  3680. //
  3681. // Then the driver list selection is to be reset.
  3682. //
  3683. *pSelectedDriver = NULL;
  3684. if(pSelectedDriverType) {
  3685. *pSelectedDriverType = SPDIT_NODRIVER;
  3686. }
  3687. } else {
  3688. //
  3689. // Retrieve the driver type from the SP_DRVINFO_DATA structure
  3690. // so we know which linked list to search.
  3691. //
  3692. if((DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA)) ||
  3693. (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V1))) {
  3694. DriverType = DriverInfoData->DriverType;
  3695. } else {
  3696. Err = ERROR_INVALID_PARAMETER;
  3697. goto clean0;
  3698. }
  3699. switch(DriverType) {
  3700. case SPDIT_CLASSDRIVER :
  3701. if(DeviceInfoData) {
  3702. DriverListHead = DevInfoElem->ClassDriverHead;
  3703. } else {
  3704. DriverListHead = pDeviceInfoSet->ClassDriverHead;
  3705. }
  3706. break;
  3707. case SPDIT_COMPATDRIVER :
  3708. if(DeviceInfoData) {
  3709. DriverListHead = DevInfoElem->CompatDriverHead;
  3710. break;
  3711. }
  3712. //
  3713. // otherwise, let fall through for error condition.
  3714. //
  3715. default :
  3716. Err = ERROR_INVALID_PARAMETER;
  3717. goto clean0;
  3718. }
  3719. //
  3720. // Find the referenced driver node in the appropriate list.
  3721. //
  3722. if(DriverInfoData->Reserved) {
  3723. if(!(DriverNode = FindAssociatedDriverNode(DriverListHead,
  3724. DriverInfoData,
  3725. NULL))) {
  3726. Err = ERROR_INVALID_PARAMETER;
  3727. goto clean0;
  3728. }
  3729. } else {
  3730. //
  3731. // The caller has requested that we search for a driver node
  3732. // matching the criteria specified in this DriverInfoData.
  3733. //
  3734. if(!(DriverNode = SearchForDriverNode(pDeviceInfoSet->StringTable,
  3735. DriverListHead,
  3736. DriverInfoData,
  3737. NULL))) {
  3738. Err = ERROR_INVALID_PARAMETER;
  3739. goto clean0;
  3740. }
  3741. }
  3742. //
  3743. // If we're selecting a driver for a device information element, then update
  3744. // that device's class to reflect the class of this new driver node.
  3745. //
  3746. if(DeviceInfoData) {
  3747. if(slot_section == 0) {
  3748. //
  3749. // To aid in debugging, log inf/section for the newly selected node
  3750. //
  3751. PTSTR szInfFileName, szInfSectionName;
  3752. szInfFileName = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  3753. DriverNode->InfFileName
  3754. );
  3755. szInfSectionName = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  3756. DriverNode->InfSectionName
  3757. );
  3758. slot_section = AllocLogInfoSlotOrLevel(LogContext,DRIVER_LOG_INFO,FALSE);
  3759. //
  3760. // Say what section is about to be installed.
  3761. //
  3762. WriteLogEntry(LogContext,
  3763. slot_section,
  3764. MSG_LOG_SETSELECTED_SECTION,
  3765. NULL,
  3766. szInfSectionName,
  3767. szInfFileName);
  3768. }
  3769. //
  3770. // Get the INF class GUID for this driver node in string form, because
  3771. // this property is stored as a REG_SZ.
  3772. //
  3773. pSetupStringFromGuid(&(pDeviceInfoSet->GuidTable[DriverNode->GuidIndex]),
  3774. ClassGuidString,
  3775. SIZECHARS(ClassGuidString)
  3776. );
  3777. if(SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  3778. DeviceInfoData,
  3779. SPDRP_CLASSGUID,
  3780. &PropType,
  3781. (PBYTE)OldClassGuidString,
  3782. sizeof(OldClassGuidString),
  3783. NULL)) {
  3784. if(_tcscmp(ClassGuidString,OldClassGuidString)==0) {
  3785. NoGuidUpdate = TRUE;
  3786. WriteLogEntry(
  3787. LogContext,
  3788. DRIVER_LOG_INFO,
  3789. MSG_LOG_KEEPSELECTED_GUID,
  3790. NULL,
  3791. ClassGuidString);
  3792. }
  3793. }
  3794. if(!NoGuidUpdate) {
  3795. WriteLogEntry(
  3796. LogContext,
  3797. DRIVER_LOG_INFO,
  3798. MSG_LOG_SETSELECTED_GUID,
  3799. NULL,
  3800. ClassGuidString);
  3801. }
  3802. if(!SetupDiSetDeviceRegistryProperty(DeviceInfoSet,
  3803. DeviceInfoData,
  3804. SPDRP_CLASSGUID,
  3805. (PBYTE)ClassGuidString,
  3806. sizeof(ClassGuidString))) {
  3807. Err = GetLastError();
  3808. goto clean0;
  3809. }
  3810. }
  3811. *pSelectedDriver = DriverNode;
  3812. if(pSelectedDriverType) {
  3813. *pSelectedDriverType = DriverType;
  3814. }
  3815. if(!DriverInfoData->Reserved) {
  3816. //
  3817. // Update the caller-supplied DriverInfoData to reflect the driver node
  3818. // where the match was found.
  3819. //
  3820. DriverInfoData->Reserved = (ULONG_PTR)DriverNode;
  3821. }
  3822. }
  3823. clean0: ; // Nothing to do.
  3824. } except(EXCEPTION_EXECUTE_HANDLER) {
  3825. Err = ERROR_INVALID_PARAMETER;
  3826. }
  3827. UnlockDeviceInfoSet(pDeviceInfoSet);
  3828. clean1:
  3829. if (Err == NO_ERROR) {
  3830. //
  3831. // give a +ve affirmation of install
  3832. //
  3833. WriteLogEntry(
  3834. LogContext,
  3835. DRIVER_LOG_INFO,
  3836. MSG_LOG_SETSELECTED,
  3837. NULL);
  3838. } else {
  3839. //
  3840. // indicate remove failed, display error
  3841. //
  3842. WriteLogEntry(
  3843. LogContext,
  3844. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  3845. MSG_LOG_SETSELECTED_ERROR,
  3846. NULL);
  3847. WriteLogError(
  3848. LogContext,
  3849. DRIVER_LOG_ERROR,
  3850. Err);
  3851. }
  3852. if (slot_section) {
  3853. ReleaseLogInfoSlot(LogContext,slot_section);
  3854. }
  3855. SetLastError(Err);
  3856. return(Err == NO_ERROR);
  3857. }
  3858. #ifdef UNICODE
  3859. //
  3860. // ANSI version
  3861. //
  3862. BOOL
  3863. WINAPI
  3864. SetupDiGetDriverInfoDetailA(
  3865. IN HDEVINFO DeviceInfoSet,
  3866. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  3867. IN PSP_DRVINFO_DATA_A DriverInfoData,
  3868. OUT PSP_DRVINFO_DETAIL_DATA_A DriverInfoDetailData, OPTIONAL
  3869. IN DWORD DriverInfoDetailDataSize,
  3870. OUT PDWORD RequiredSize OPTIONAL
  3871. )
  3872. {
  3873. BOOL b;
  3874. DWORD rc;
  3875. DWORD requiredSize;
  3876. SP_DRVINFO_DATA_W driverInfoData;
  3877. PSP_DRVINFO_DETAIL_DATA_W Details;
  3878. PSTR AnsiMultiSz;
  3879. int i;
  3880. int CharCount;
  3881. unsigned StringCount;
  3882. UCHAR SectionName[2*LINE_LEN];
  3883. UCHAR InfFileName[2*MAX_PATH];
  3884. UCHAR DrvDescription[2*LINE_LEN];
  3885. PUCHAR p;
  3886. //
  3887. // Check parameters.
  3888. //
  3889. rc = NO_ERROR;
  3890. try {
  3891. if(DriverInfoDetailData) {
  3892. //
  3893. // Check signature and make sure buffer is large enough
  3894. // to hold fixed part and at least a valid empty multi_sz.
  3895. //
  3896. if((DriverInfoDetailData->cbSize != sizeof(SP_DRVINFO_DETAIL_DATA_A))
  3897. || (DriverInfoDetailDataSize < (offsetof(SP_DRVINFO_DETAIL_DATA_A,HardwareID)+sizeof(CHAR)))) {
  3898. rc = ERROR_INVALID_USER_BUFFER;
  3899. }
  3900. } else {
  3901. //
  3902. // Doesn't want data, size has to be 0.
  3903. //
  3904. if(DriverInfoDetailDataSize) {
  3905. rc = ERROR_INVALID_USER_BUFFER;
  3906. }
  3907. }
  3908. } except(EXCEPTION_EXECUTE_HANDLER) {
  3909. rc = ERROR_INVALID_USER_BUFFER;
  3910. }
  3911. //
  3912. // Convert the driver info data to unicode.
  3913. //
  3914. if(rc == NO_ERROR) {
  3915. rc = pSetupDiDrvInfoDataAnsiToUnicode(DriverInfoData,&driverInfoData);
  3916. }
  3917. if(rc != NO_ERROR) {
  3918. SetLastError(rc);
  3919. return(FALSE);
  3920. }
  3921. //
  3922. // The hardware id field in the DRVINFO_DETAIL_DATA is
  3923. // variable length and has no maximum length.
  3924. // We call SetupDiGetDriverInfoDetailW once to get the required
  3925. // size and then again to actually get the data. Because
  3926. // we're not calling CM APIs and thus not doing any really
  3927. // slow RPC operations, etc, we hope this will be satisfactory.
  3928. //
  3929. b = SetupDiGetDriverInfoDetailW(
  3930. DeviceInfoSet,
  3931. DeviceInfoData,
  3932. &driverInfoData,
  3933. NULL,
  3934. 0,
  3935. &requiredSize
  3936. );
  3937. //
  3938. // If it failed for a reason besides an insufficient buffer,
  3939. // bail now. Last error remains set.
  3940. //
  3941. MYASSERT(!b);
  3942. if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  3943. return(FALSE);
  3944. }
  3945. //
  3946. // Allocate a buffer to hold the details data and call the API
  3947. // again.
  3948. //
  3949. Details = MyMalloc(requiredSize);
  3950. if(!Details) {
  3951. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3952. return(FALSE);
  3953. }
  3954. Details->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_W);
  3955. b = SetupDiGetDriverInfoDetail(
  3956. DeviceInfoSet,
  3957. DeviceInfoData,
  3958. &driverInfoData,
  3959. Details,
  3960. requiredSize,
  3961. NULL
  3962. );
  3963. if(!b) {
  3964. rc = GetLastError();
  3965. MyFree(Details);
  3966. SetLastError(rc);
  3967. return(FALSE);
  3968. }
  3969. //
  3970. // Now allocate a buffer that allows us to convert the unicode
  3971. // hardware id multi_sz to ansi, assuming every unicode character would
  3972. // translate into a double-byte char -- this is the worst-case scenario.
  3973. //
  3974. CharCount = (requiredSize - offsetof(SP_DRVINFO_DETAIL_DATA_W,HardwareID)) / sizeof(WCHAR);
  3975. AnsiMultiSz = MyMalloc(2*CharCount);
  3976. if(!AnsiMultiSz) {
  3977. MyFree(Details);
  3978. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  3979. return(FALSE);
  3980. }
  3981. //
  3982. // Convert the chars in the multi_sz.
  3983. //
  3984. i = WideCharToMultiByte(
  3985. CP_ACP,
  3986. 0,
  3987. Details->HardwareID,
  3988. CharCount,
  3989. AnsiMultiSz,
  3990. CharCount*2,
  3991. NULL,
  3992. NULL
  3993. );
  3994. if(!i) {
  3995. rc = GetLastError();
  3996. MyFree(Details);
  3997. MyFree(AnsiMultiSz);
  3998. SetLastError(rc);
  3999. return(FALSE);
  4000. }
  4001. //
  4002. // Now we finally know exactly how large we need the ansi structure to be
  4003. // because we have the number of bytes in the ansi representation
  4004. // of the multi_sz.
  4005. //
  4006. requiredSize = offsetof(SP_DRVINFO_DETAIL_DATA_A,HardwareID) + i;
  4007. rc = NO_ERROR;
  4008. try {
  4009. if(RequiredSize) {
  4010. *RequiredSize = requiredSize;
  4011. }
  4012. if(DriverInfoDetailData) {
  4013. //
  4014. // We know the buffer is large enough to hold the fixed part
  4015. // because we checked this at the start of the routine.
  4016. //
  4017. MYASSERT(offsetof(SP_DRVINFO_DETAIL_DATA_A,SectionName) == offsetof(SP_DRVINFO_DETAIL_DATA_W,SectionName));
  4018. CopyMemory(DriverInfoDetailData,Details,offsetof(SP_DRVINFO_DETAIL_DATA_A,SectionName));
  4019. DriverInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA_A);
  4020. DriverInfoDetailData->HardwareID[0] = 0;
  4021. //
  4022. // Convert fixed strings and guard against overflow.
  4023. //
  4024. i = WideCharToMultiByte(
  4025. CP_ACP,0,
  4026. Details->SectionName,
  4027. -1,
  4028. SectionName,
  4029. sizeof(SectionName),
  4030. NULL,
  4031. NULL
  4032. );
  4033. if(i) {
  4034. i = WideCharToMultiByte(
  4035. CP_ACP,0,
  4036. Details->InfFileName,
  4037. -1,
  4038. InfFileName,
  4039. sizeof(InfFileName),
  4040. NULL,
  4041. NULL
  4042. );
  4043. if(i) {
  4044. i = WideCharToMultiByte(
  4045. CP_ACP,0,
  4046. Details->DrvDescription,
  4047. -1,
  4048. DrvDescription,
  4049. sizeof(DrvDescription),
  4050. NULL,
  4051. NULL
  4052. );
  4053. if(!i) {
  4054. rc = GetLastError();
  4055. }
  4056. } else {
  4057. rc = GetLastError();
  4058. }
  4059. } else {
  4060. rc = GetLastError();
  4061. }
  4062. if(rc == NO_ERROR) {
  4063. if(!lstrcpynA(DriverInfoDetailData->SectionName,SectionName,LINE_LEN)
  4064. || !lstrcpynA(DriverInfoDetailData->InfFileName,InfFileName,MAX_PATH)
  4065. || !lstrcpynA(DriverInfoDetailData->DrvDescription,DrvDescription,LINE_LEN)) {
  4066. //
  4067. // lstrcpyn faulted, the buffer went bad
  4068. //
  4069. rc = ERROR_INVALID_USER_BUFFER;
  4070. }
  4071. }
  4072. if(rc == NO_ERROR) {
  4073. //
  4074. // Finally, we need to transfer in as much of the ansi multi_sz
  4075. // as will fit into the caller's buffer.
  4076. //
  4077. CharCount = DriverInfoDetailDataSize - offsetof(SP_DRVINFO_DETAIL_DATA_A,HardwareID);
  4078. StringCount = 0;
  4079. for(p=AnsiMultiSz; *p; p+=i) {
  4080. i = lstrlenA(p) + 1;
  4081. if(CharCount > i) {
  4082. lstrcpyA(DriverInfoDetailData->HardwareID+(p - AnsiMultiSz),p);
  4083. StringCount++;
  4084. CharCount -= i;
  4085. } else {
  4086. rc = ERROR_INSUFFICIENT_BUFFER;
  4087. break;
  4088. }
  4089. }
  4090. DriverInfoDetailData->HardwareID[p-AnsiMultiSz] = 0;
  4091. //
  4092. // Now fix up the compat ids fields in the caller's structure.
  4093. // The first string is the hardware id and any additional ones
  4094. // are compatible ids.
  4095. //
  4096. if(StringCount > 1) {
  4097. DriverInfoDetailData->CompatIDsOffset = lstrlenA(AnsiMultiSz)+1;
  4098. DriverInfoDetailData->CompatIDsLength = (DWORD)(p - AnsiMultiSz) + 1
  4099. - DriverInfoDetailData->CompatIDsOffset;
  4100. } else {
  4101. DriverInfoDetailData->CompatIDsLength = 0;
  4102. DriverInfoDetailData->CompatIDsOffset = 0;
  4103. }
  4104. }
  4105. }
  4106. } except(EXCEPTION_EXECUTE_HANDLER) {
  4107. rc = ERROR_INVALID_USER_BUFFER;
  4108. }
  4109. MyFree(AnsiMultiSz);
  4110. MyFree(Details);
  4111. SetLastError(rc);
  4112. return(rc == NO_ERROR);
  4113. }
  4114. #else
  4115. //
  4116. // Unicode stub
  4117. //
  4118. BOOL
  4119. WINAPI
  4120. SetupDiGetDriverInfoDetailW(
  4121. IN HDEVINFO DeviceInfoSet,
  4122. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  4123. IN PSP_DRVINFO_DATA_W DriverInfoData,
  4124. OUT PSP_DRVINFO_DETAIL_DATA_W DriverInfoDetailData, OPTIONAL
  4125. IN DWORD DriverInfoDetailDataSize,
  4126. OUT PDWORD RequiredSize OPTIONAL
  4127. )
  4128. {
  4129. UNREFERENCED_PARAMETER(DeviceInfoSet);
  4130. UNREFERENCED_PARAMETER(DeviceInfoData);
  4131. UNREFERENCED_PARAMETER(DriverInfoData);
  4132. UNREFERENCED_PARAMETER(DriverInfoDetailData);
  4133. UNREFERENCED_PARAMETER(DriverInfoDetailDataSize);
  4134. UNREFERENCED_PARAMETER(RequiredSize);
  4135. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  4136. return(FALSE);
  4137. }
  4138. #endif
  4139. BOOL
  4140. WINAPI
  4141. SetupDiGetDriverInfoDetail(
  4142. IN HDEVINFO DeviceInfoSet,
  4143. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  4144. IN PSP_DRVINFO_DATA DriverInfoData,
  4145. OUT PSP_DRVINFO_DETAIL_DATA DriverInfoDetailData, OPTIONAL
  4146. IN DWORD DriverInfoDetailDataSize,
  4147. OUT PDWORD RequiredSize OPTIONAL
  4148. )
  4149. /*++
  4150. Routine Description:
  4151. This routine retrieves details about a particular driver.
  4152. Arguments:
  4153. DeviceInfoSet - Supplies a handle to a device information set containing
  4154. a driver information structure to retrieve details about.
  4155. DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
  4156. structure that contains a driver information structure to retrieve
  4157. details about. If this parameter is not specified, then the driver
  4158. referenced will be a member of the 'global' class driver list owned
  4159. by the device information set.
  4160. DriverInfoData - Supplies the address of a SP_DRVINFO_DATA structure
  4161. specifying the driver for whom details are to be retrieved.
  4162. DriverInfoDetailData - Optionally, supplies the address of a
  4163. SP_DRVINFO_DETAIL_DATA structure that will receive detailed information
  4164. about the specified driver. If this parameter is not specified, then
  4165. DriverInfoDetailDataSize must be zero (this would be done if the caller
  4166. was only interested in finding out how large of a buffer is required).
  4167. If this parameter is specified, the cbSize field of this structure must
  4168. be set to the size of the structure before calling this API. NOTE:
  4169. The 'size of the structure' on input means sizeof(SP_DRVINFO_DETAIL_DATA).
  4170. Note that this is essentially just a signature and is entirely separate
  4171. from DriverInfoDetailDataSize. See below.
  4172. DriverInfoDetailDataSize - Supplies the size, in bytes, of the
  4173. DriverInfoDetailData buffer. To be valid this buffer must be at least
  4174. sizeof(SP_DRVINFO_DETAIL_DATA)+sizeof(TCHAR) bytes, which allows
  4175. storage of the fixed part of the structure and a single nul to
  4176. terminate an empty multi_sz. (Depending on structure alignment,
  4177. character width, and the data to be returned, this may actually be
  4178. smaller than sizeof(SP_DRVINFO_DETAIL_DATA)).
  4179. RequiredSize - Optionally, supplies the address of a variable that receives
  4180. the number of bytes required to store the detailed driver information.
  4181. This value includes both the size of the structure itself, and the
  4182. additional number of bytes required for the variable-length character
  4183. buffer at the end of it that holds the hardware ID and compatible IDs
  4184. multi-sz list. (Depending on structure alignment, character width,
  4185. and the data to be returned, this may actually be smaller than
  4186. sizeof(SP_DRVINFO_DETAIL_DATA)).
  4187. Return Value:
  4188. If the function succeeds, the return value is TRUE.
  4189. If the function fails, the return value is FALSE. To get extended error
  4190. information, call GetLastError.
  4191. Remarks:
  4192. If the specified driver information member and the user-supplied buffer are
  4193. both valid, then this function is guaranteed to fill in all static fields in
  4194. the SP_DRVINFO_DETAIL_DATA structure, and as many IDs as possible in the
  4195. variable-length buffer at the end (while still maintaining a multi-sz format).
  4196. The function will return failure (FALSE) in this case, with GetLastError
  4197. returning ERROR_INSUFFICIENT_BUFFER, and RequiredSize (if specified) will
  4198. contain the total number of bytes required for the structure with _all_ IDs.
  4199. --*/
  4200. {
  4201. PDEVICE_INFO_SET pDeviceInfoSet;
  4202. DWORD Err;
  4203. PDEVINFO_ELEM DevInfoElem;
  4204. DWORD DriverType;
  4205. PDRIVER_NODE DriverListHead, DriverNode;
  4206. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  4207. SetLastError(ERROR_INVALID_HANDLE);
  4208. return FALSE;
  4209. }
  4210. Err = NO_ERROR;
  4211. try {
  4212. if(DeviceInfoData) {
  4213. //
  4214. // Then this is a driver for a particular device.
  4215. //
  4216. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  4217. DeviceInfoData,
  4218. NULL))) {
  4219. Err = ERROR_INVALID_PARAMETER;
  4220. goto clean0;
  4221. }
  4222. }
  4223. //
  4224. // Retrieve the driver type from the SP_DRVINFO_DATA structure
  4225. // so we know which linked list to search.
  4226. //
  4227. if((DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA)) ||
  4228. (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V1))) {
  4229. DriverType = DriverInfoData->DriverType;
  4230. } else {
  4231. Err = ERROR_INVALID_PARAMETER;
  4232. goto clean0;
  4233. }
  4234. //
  4235. // NOTE: If we ever decide to do indexed searching like setupx, we
  4236. // will need to be careful here, because we may not always have detailed
  4237. // information around like we do today. The assertions below indicate our
  4238. // current assumption.
  4239. //
  4240. switch(DriverType) {
  4241. case SPDIT_CLASSDRIVER :
  4242. if(DeviceInfoData) {
  4243. MYASSERT(DevInfoElem->InstallParamBlock.Flags & DI_DIDCLASS);
  4244. DriverListHead = DevInfoElem->ClassDriverHead;
  4245. } else {
  4246. MYASSERT(pDeviceInfoSet->InstallParamBlock.Flags & DI_DIDCLASS);
  4247. DriverListHead = pDeviceInfoSet->ClassDriverHead;
  4248. }
  4249. break;
  4250. case SPDIT_COMPATDRIVER :
  4251. if(DeviceInfoData) {
  4252. MYASSERT(DevInfoElem->InstallParamBlock.Flags & DI_DIDCOMPAT);
  4253. DriverListHead = DevInfoElem->CompatDriverHead;
  4254. break;
  4255. }
  4256. //
  4257. // otherwise, let fall through for error condition.
  4258. //
  4259. default :
  4260. Err = ERROR_INVALID_PARAMETER;
  4261. goto clean0;
  4262. }
  4263. //
  4264. // Find the referenced driver node in the appropriate list.
  4265. //
  4266. if(!(DriverNode = FindAssociatedDriverNode(DriverListHead,
  4267. DriverInfoData,
  4268. NULL))) {
  4269. Err = ERROR_INVALID_PARAMETER;
  4270. goto clean0;
  4271. }
  4272. Err = DrvInfoDetailsFromDriverNode(pDeviceInfoSet,
  4273. DriverNode,
  4274. DriverInfoDetailData,
  4275. DriverInfoDetailDataSize,
  4276. RequiredSize
  4277. );
  4278. clean0: ; // Nothing to do.
  4279. } except(EXCEPTION_EXECUTE_HANDLER) {
  4280. Err = ERROR_INVALID_PARAMETER;
  4281. }
  4282. UnlockDeviceInfoSet(pDeviceInfoSet);
  4283. SetLastError(Err);
  4284. return(Err == NO_ERROR);
  4285. }
  4286. BOOL
  4287. WINAPI
  4288. SetupDiDestroyDriverInfoList(
  4289. IN HDEVINFO DeviceInfoSet,
  4290. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  4291. IN DWORD DriverType
  4292. )
  4293. /*++
  4294. Routine Description:
  4295. This routine destroys a driver information list.
  4296. Arguments:
  4297. DeviceInfoSet - Supplies a handle to a device information set containing
  4298. the driver information list to be destroyed.
  4299. DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
  4300. structure that contains the driver information list to be destroyed.
  4301. If this parameter is not specified, then the global class driver list
  4302. will be destroyed.
  4303. DriverType - Specifies what type of driver list to destroy. Must be one of
  4304. the following values:
  4305. SPDIT_CLASSDRIVER - Destroy a class driver list.
  4306. SPDIT_COMPATDRIVER - Destroy a compatible driver list. DeviceInfoData
  4307. must be specified if this value is used.
  4308. Return Value:
  4309. If the function succeeds, the return value is TRUE.
  4310. If the function fails, the return value is FALSE. To get extended error
  4311. information, call GetLastError.
  4312. Remarks:
  4313. If the currently selected driver is a member of the list being destroyed,
  4314. then the selection will be reset.
  4315. If a class driver list is being destroyed, then the DI_FLAGSEX_DIDINFOLIST
  4316. and DI_DIDCLASS flags will be reset for the corresponding device information
  4317. set or device information element. The DI_MULTMFGS flag will also be reset.
  4318. If a compatible driver list is being destroyed, then the DI_FLAGSEX_DIDCOMPATINFO
  4319. and DI_DIDCOMPAT flags will be reset for the corresponding device information
  4320. element.
  4321. --*/
  4322. {
  4323. PDEVICE_INFO_SET pDeviceInfoSet;
  4324. DWORD Err;
  4325. PDEVINFO_ELEM DevInfoElem;
  4326. PDRIVER_NODE DriverNode;
  4327. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  4328. SetLastError(ERROR_INVALID_HANDLE);
  4329. return FALSE;
  4330. }
  4331. Err = NO_ERROR;
  4332. try {
  4333. if(DeviceInfoData) {
  4334. //
  4335. // Then this is a driver for a particular device.
  4336. //
  4337. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  4338. DeviceInfoData,
  4339. NULL))) {
  4340. Err = ERROR_INVALID_PARAMETER;
  4341. goto clean0;
  4342. }
  4343. //
  4344. // If the selected driver is in the list we're deleting, then
  4345. // reset the selection.
  4346. //
  4347. if(DevInfoElem->SelectedDriverType == DriverType) {
  4348. DevInfoElem->SelectedDriverType = SPDIT_NODRIVER;
  4349. DevInfoElem->SelectedDriver = NULL;
  4350. }
  4351. } else {
  4352. pDeviceInfoSet->SelectedClassDriver = NULL;
  4353. }
  4354. switch(DriverType) {
  4355. case SPDIT_CLASSDRIVER :
  4356. if(DeviceInfoData) {
  4357. //
  4358. // Destroy class driver list for a particular device.
  4359. //
  4360. DriverNode = DevInfoElem->ClassDriverHead;
  4361. DevInfoElem->ClassDriverCount = 0;
  4362. DevInfoElem->ClassDriverHead = DevInfoElem->ClassDriverTail = NULL;
  4363. DevInfoElem->ClassDriverEnumHint = NULL;
  4364. DevInfoElem->ClassDriverEnumHintIndex = INVALID_ENUM_INDEX;
  4365. DevInfoElem->InstallParamBlock.Flags &= ~(DI_DIDCLASS | DI_MULTMFGS);
  4366. DevInfoElem->InstallParamBlock.FlagsEx &= ~DI_FLAGSEX_DIDINFOLIST;
  4367. } else {
  4368. //
  4369. // Destroy the global class driver list.
  4370. //
  4371. DriverNode = pDeviceInfoSet->ClassDriverHead;
  4372. pDeviceInfoSet->ClassDriverCount = 0;
  4373. pDeviceInfoSet->ClassDriverHead = pDeviceInfoSet->ClassDriverTail = NULL;
  4374. pDeviceInfoSet->ClassDriverEnumHint = NULL;
  4375. pDeviceInfoSet->ClassDriverEnumHintIndex = INVALID_ENUM_INDEX;
  4376. pDeviceInfoSet->InstallParamBlock.Flags &= ~(DI_DIDCLASS | DI_MULTMFGS);
  4377. pDeviceInfoSet->InstallParamBlock.FlagsEx &= ~DI_FLAGSEX_DIDINFOLIST;
  4378. }
  4379. //
  4380. // Dereference the class driver list.
  4381. //
  4382. DereferenceClassDriverList(pDeviceInfoSet, DriverNode);
  4383. break;
  4384. case SPDIT_COMPATDRIVER :
  4385. if(DeviceInfoData) {
  4386. DestroyDriverNodes(DevInfoElem->CompatDriverHead, pDeviceInfoSet);
  4387. DevInfoElem->CompatDriverCount = 0;
  4388. DevInfoElem->CompatDriverHead = DevInfoElem->CompatDriverTail = NULL;
  4389. DevInfoElem->CompatDriverEnumHint = NULL;
  4390. DevInfoElem->CompatDriverEnumHintIndex = INVALID_ENUM_INDEX;
  4391. DevInfoElem->InstallParamBlock.Flags &= ~DI_DIDCOMPAT;
  4392. DevInfoElem->InstallParamBlock.FlagsEx &= ~DI_FLAGSEX_DIDCOMPATINFO;
  4393. break;
  4394. }
  4395. //
  4396. // otherwise, let fall through for error condition.
  4397. //
  4398. default :
  4399. Err = ERROR_INVALID_PARAMETER;
  4400. goto clean0;
  4401. }
  4402. clean0: ; // Nothing to do.
  4403. } except(EXCEPTION_EXECUTE_HANDLER) {
  4404. Err = ERROR_INVALID_PARAMETER;
  4405. }
  4406. UnlockDeviceInfoSet(pDeviceInfoSet);
  4407. SetLastError(Err);
  4408. return(Err == NO_ERROR);
  4409. }
  4410. #ifdef UNICODE
  4411. //
  4412. // ANSI version
  4413. //
  4414. BOOL
  4415. WINAPI
  4416. SetupDiGetDriverInstallParamsA(
  4417. IN HDEVINFO DeviceInfoSet,
  4418. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  4419. IN PSP_DRVINFO_DATA_A DriverInfoData,
  4420. OUT PSP_DRVINSTALL_PARAMS DriverInstallParams
  4421. )
  4422. {
  4423. DWORD rc;
  4424. SP_DRVINFO_DATA_W driverInfoData;
  4425. rc = pSetupDiDrvInfoDataAnsiToUnicode(DriverInfoData,&driverInfoData);
  4426. if(rc != NO_ERROR) {
  4427. SetLastError(rc);
  4428. return(FALSE);
  4429. }
  4430. return SetupDiGetDriverInstallParamsW(
  4431. DeviceInfoSet,
  4432. DeviceInfoData,
  4433. &driverInfoData,
  4434. DriverInstallParams
  4435. );
  4436. }
  4437. #else
  4438. //
  4439. // Unicode stub
  4440. //
  4441. BOOL
  4442. WINAPI
  4443. SetupDiGetDriverInstallParamsW(
  4444. IN HDEVINFO DeviceInfoSet,
  4445. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  4446. IN PSP_DRVINFO_DATA_W DriverInfoData,
  4447. OUT PSP_DRVINSTALL_PARAMS DriverInstallParams
  4448. )
  4449. {
  4450. UNREFERENCED_PARAMETER(DeviceInfoSet);
  4451. UNREFERENCED_PARAMETER(DeviceInfoData);
  4452. UNREFERENCED_PARAMETER(DriverInfoData);
  4453. UNREFERENCED_PARAMETER(DriverInstallParams);
  4454. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  4455. return(FALSE);
  4456. }
  4457. #endif
  4458. BOOL
  4459. WINAPI
  4460. SetupDiGetDriverInstallParams(
  4461. IN HDEVINFO DeviceInfoSet,
  4462. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  4463. IN PSP_DRVINFO_DATA DriverInfoData,
  4464. OUT PSP_DRVINSTALL_PARAMS DriverInstallParams
  4465. )
  4466. /*++
  4467. Routine Description:
  4468. This routine retrieves installation parameters for the specified driver.
  4469. Arguments:
  4470. DeviceInfoSet - Supplies a handle to a device information set containing
  4471. a driver information structure to retrieve installation parameters for.
  4472. DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
  4473. structure that contains a driver information structure to retrieve
  4474. installation parameters for. If this parameter is not specified, then
  4475. the driver referenced will be a member of the 'global' class driver list
  4476. owned by the device information set.
  4477. DriverInfoData - Supplies the address of a SP_DRVINFO_DATA structure
  4478. specifying the driver for whom installation parameters are to be
  4479. retrieved.
  4480. DriverInstallParams - Supplies the address of a SP_DRVINSTALL_PARAMS structure
  4481. that will receive the installation parameters for this driver. The cbSize
  4482. field of this structure must be set to the size, in bytes, of the
  4483. structure before calling this API.
  4484. Return Value:
  4485. If the function succeeds, the return value is TRUE.
  4486. If the function fails, the return value is FALSE. To get extended error
  4487. information, call GetLastError.
  4488. --*/
  4489. {
  4490. PDEVICE_INFO_SET pDeviceInfoSet;
  4491. DWORD Err;
  4492. PDEVINFO_ELEM DevInfoElem;
  4493. DWORD DriverType;
  4494. PDRIVER_NODE DriverListHead, DriverNode;
  4495. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  4496. SetLastError(ERROR_INVALID_HANDLE);
  4497. return FALSE;
  4498. }
  4499. Err = NO_ERROR;
  4500. try {
  4501. if(DeviceInfoData) {
  4502. //
  4503. // Then this is a driver for a particular device.
  4504. //
  4505. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  4506. DeviceInfoData,
  4507. NULL))) {
  4508. Err = ERROR_INVALID_PARAMETER;
  4509. goto clean0;
  4510. }
  4511. }
  4512. //
  4513. // Retrieve the driver type from the SP_DRVINFO_DATA structure
  4514. // so we know which linked list to search.
  4515. //
  4516. if((DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA)) ||
  4517. (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V1))) {
  4518. DriverType = DriverInfoData->DriverType;
  4519. } else {
  4520. Err = ERROR_INVALID_PARAMETER;
  4521. goto clean0;
  4522. }
  4523. switch(DriverType) {
  4524. case SPDIT_CLASSDRIVER :
  4525. if(DeviceInfoData) {
  4526. DriverListHead = DevInfoElem->ClassDriverHead;
  4527. } else {
  4528. DriverListHead = pDeviceInfoSet->ClassDriverHead;
  4529. }
  4530. break;
  4531. case SPDIT_COMPATDRIVER :
  4532. if(DeviceInfoData) {
  4533. DriverListHead = DevInfoElem->CompatDriverHead;
  4534. break;
  4535. }
  4536. //
  4537. // otherwise, let fall through for error condition.
  4538. //
  4539. default :
  4540. Err = ERROR_INVALID_PARAMETER;
  4541. goto clean0;
  4542. }
  4543. //
  4544. // Find the referenced driver node in the appropriate list.
  4545. //
  4546. if(!(DriverNode = FindAssociatedDriverNode(DriverListHead,
  4547. DriverInfoData,
  4548. NULL))) {
  4549. Err = ERROR_INVALID_PARAMETER;
  4550. goto clean0;
  4551. }
  4552. //
  4553. // We have the driver node, now fill in the caller's buffer with
  4554. // its installation parameters.
  4555. //
  4556. Err = GetDrvInstallParams(DriverNode,
  4557. DriverInstallParams
  4558. );
  4559. if(Err == NO_ERROR) {
  4560. //
  4561. // Fill in the Win98-compatible DNF flags indicating whether this
  4562. // driver node is from a compatible or class driver list.
  4563. //
  4564. DriverInstallParams->Flags |= (DriverType == SPDIT_CLASSDRIVER)
  4565. ? DNF_CLASS_DRIVER
  4566. : DNF_COMPATIBLE_DRIVER;
  4567. //
  4568. // Hide the private PDNF_xxx flags
  4569. //
  4570. DriverInstallParams->Flags &= ~PDNF_MASK;
  4571. }
  4572. clean0: ; // Nothing to do.
  4573. } except(EXCEPTION_EXECUTE_HANDLER) {
  4574. Err = ERROR_INVALID_PARAMETER;
  4575. }
  4576. UnlockDeviceInfoSet(pDeviceInfoSet);
  4577. SetLastError(Err);
  4578. return(Err == NO_ERROR);
  4579. }
  4580. #ifdef UNICODE
  4581. //
  4582. // ANSI version
  4583. //
  4584. BOOL
  4585. WINAPI
  4586. SetupDiSetDriverInstallParamsA(
  4587. IN HDEVINFO DeviceInfoSet,
  4588. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  4589. IN PSP_DRVINFO_DATA_A DriverInfoData,
  4590. OUT PSP_DRVINSTALL_PARAMS DriverInstallParams
  4591. )
  4592. {
  4593. SP_DRVINFO_DATA_W driverInfoData;
  4594. DWORD rc;
  4595. rc = pSetupDiDrvInfoDataAnsiToUnicode(DriverInfoData,&driverInfoData);
  4596. if(rc != NO_ERROR) {
  4597. SetLastError(rc);
  4598. return(FALSE);
  4599. }
  4600. return SetupDiSetDriverInstallParamsW(
  4601. DeviceInfoSet,
  4602. DeviceInfoData,
  4603. &driverInfoData,
  4604. DriverInstallParams
  4605. );
  4606. }
  4607. #else
  4608. //
  4609. // Unicode stub
  4610. //
  4611. BOOL
  4612. WINAPI
  4613. SetupDiSetDriverInstallParamsW(
  4614. IN HDEVINFO DeviceInfoSet,
  4615. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  4616. IN PSP_DRVINFO_DATA_W DriverInfoData,
  4617. OUT PSP_DRVINSTALL_PARAMS DriverInstallParams
  4618. )
  4619. {
  4620. UNREFERENCED_PARAMETER(DeviceInfoSet);
  4621. UNREFERENCED_PARAMETER(DeviceInfoData);
  4622. UNREFERENCED_PARAMETER(DriverInfoData);
  4623. UNREFERENCED_PARAMETER(DriverInstallParams);
  4624. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  4625. return(FALSE);
  4626. }
  4627. #endif
  4628. BOOL
  4629. WINAPI
  4630. SetupDiSetDriverInstallParams(
  4631. IN HDEVINFO DeviceInfoSet,
  4632. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  4633. IN PSP_DRVINFO_DATA DriverInfoData,
  4634. IN PSP_DRVINSTALL_PARAMS DriverInstallParams
  4635. )
  4636. /*++
  4637. Routine Description:
  4638. This routine sets installation parameters for the specified driver.
  4639. Arguments:
  4640. DeviceInfoSet - Supplies a handle to a device information set containing
  4641. a driver information structure to set installation parameters for.
  4642. DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
  4643. structure that contains a driver information structure to set
  4644. installation parameters for. If this parameter is not specified, then
  4645. the driver referenced will be a member of the 'global' class driver list
  4646. owned by the device information set.
  4647. DriverInfoData - Supplies the address of a SP_DRVINFO_DATA structure
  4648. specifying the driver for whom installation parameters are to be
  4649. set.
  4650. DriverInstallParams - Supplies the address of a SP_DRVINSTALL_PARAMS structure
  4651. specifying what the new driver install parameters should be. The cbSize
  4652. field of this structure must be set to the size, in bytes, of the
  4653. structure before calling this API.
  4654. Return Value:
  4655. If the function succeeds, the return value is TRUE.
  4656. If the function fails, the return value is FALSE. To get extended error
  4657. information, call GetLastError.
  4658. --*/
  4659. {
  4660. PDEVICE_INFO_SET pDeviceInfoSet;
  4661. DWORD Err;
  4662. PDEVINFO_ELEM DevInfoElem;
  4663. DWORD DriverType;
  4664. PDRIVER_NODE DriverListHead, DriverNode;
  4665. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  4666. SetLastError(ERROR_INVALID_HANDLE);
  4667. return FALSE;
  4668. }
  4669. Err = NO_ERROR;
  4670. try {
  4671. if(DeviceInfoData) {
  4672. //
  4673. // Then this is a driver for a particular device.
  4674. //
  4675. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  4676. DeviceInfoData,
  4677. NULL))) {
  4678. Err = ERROR_INVALID_PARAMETER;
  4679. goto clean0;
  4680. }
  4681. }
  4682. //
  4683. // Retrieve the driver type from the SP_DRVINFO_DATA structure
  4684. // so we know which linked list to search.
  4685. //
  4686. if((DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA)) ||
  4687. (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V1))) {
  4688. DriverType = DriverInfoData->DriverType;
  4689. } else {
  4690. Err = ERROR_INVALID_PARAMETER;
  4691. goto clean0;
  4692. }
  4693. switch(DriverType) {
  4694. case SPDIT_CLASSDRIVER :
  4695. if(DeviceInfoData) {
  4696. DriverListHead = DevInfoElem->ClassDriverHead;
  4697. } else {
  4698. DriverListHead = pDeviceInfoSet->ClassDriverHead;
  4699. }
  4700. break;
  4701. case SPDIT_COMPATDRIVER :
  4702. if(DeviceInfoData) {
  4703. DriverListHead = DevInfoElem->CompatDriverHead;
  4704. break;
  4705. }
  4706. //
  4707. // otherwise, let fall through for error condition.
  4708. //
  4709. default :
  4710. Err = ERROR_INVALID_PARAMETER;
  4711. goto clean0;
  4712. }
  4713. //
  4714. // Find the referenced driver node in the appropriate list.
  4715. //
  4716. if(!(DriverNode = FindAssociatedDriverNode(DriverListHead,
  4717. DriverInfoData,
  4718. NULL))) {
  4719. Err = ERROR_INVALID_PARAMETER;
  4720. goto clean0;
  4721. }
  4722. //
  4723. // We have the driver node, now set its installation parameters
  4724. // based on the caller-supplied buffer.
  4725. //
  4726. Err = SetDrvInstallParams(DriverInstallParams,
  4727. DriverNode
  4728. );
  4729. clean0: ; // Nothing to do.
  4730. } except(EXCEPTION_EXECUTE_HANDLER) {
  4731. Err = ERROR_INVALID_PARAMETER;
  4732. }
  4733. UnlockDeviceInfoSet(pDeviceInfoSet);
  4734. SetLastError(Err);
  4735. return(Err == NO_ERROR);
  4736. }
  4737. BOOL
  4738. pSetupDoesInfContainDevIds(
  4739. IN PLOADED_INF Inf,
  4740. IN PDRVSEARCH_CONTEXT Context
  4741. )
  4742. /*++
  4743. Routine Description:
  4744. This routine determines whether any of the hardware or compatible IDs contained
  4745. in the context structure are in the specified INF.
  4746. Arguments:
  4747. Inf - Supplies the address of the loaded INF structure to be searched.
  4748. Context - Supplies the address of the context structure containing hardware ID
  4749. and compatible ID lists.
  4750. Return Value:
  4751. If the INF contains any of the IDs listed in the context structure, the return
  4752. value is TRUE, otherwise, it is FALSE.
  4753. Remarks:
  4754. This routine accesses the string table within the loaded INF structure, but
  4755. _does not_ obtain the INF lock. This routine should only be called if the INF
  4756. lock has been obtained, or if there is no possibility of contention (e.g., from
  4757. withing the driver search callback routine).
  4758. --*/
  4759. {
  4760. PTSTR CurDevId;
  4761. DWORD StringLength;
  4762. LONG i;
  4763. PLONG pDevIdNum;
  4764. for(i = 0; i < 2; i++) {
  4765. for(pDevIdNum = Context->IdList[i]; *pDevIdNum != -1; pDevIdNum++) {
  4766. //
  4767. // First, obtain the device ID string corresponding to our stored-away
  4768. // string table ID.
  4769. //
  4770. CurDevId = pStringTableStringFromId(Context->StringTable, *pDevIdNum);
  4771. //
  4772. // Now, try to lookup this string in the INF's string table. Since we
  4773. // added the device IDs to our Context string table case-insensitively,
  4774. // then we know that they're already lowercase, so we speed up the lookup
  4775. // even further by passing the STRTAB_ALREADY_LOWERCASE flag.
  4776. //
  4777. MYASSERT(!(Inf->Next)); // We'd better only have one of these at this point.
  4778. if(pStringTableLookUpString(Inf->StringTable,
  4779. CurDevId,
  4780. &StringLength,
  4781. NULL,
  4782. NULL,
  4783. STRTAB_CASE_INSENSITIVE | STRTAB_ALREADY_LOWERCASE,
  4784. NULL,0) != -1) {
  4785. //
  4786. // We found a match--return success.
  4787. //
  4788. return TRUE;
  4789. }
  4790. }
  4791. }
  4792. //
  4793. // No matches found.
  4794. //
  4795. return FALSE;
  4796. }
  4797. DWORD
  4798. BuildCompatListFromClassList(
  4799. IN PDRIVER_NODE ClassDriverList,
  4800. IN OUT PDRVSEARCH_CONTEXT Context
  4801. )
  4802. /*++
  4803. Routine Description:
  4804. This routine builds a compatible driver list for the specified device
  4805. information element based on an existing class driver list for that element.
  4806. Arguments:
  4807. ClassDriverList - Pointer to the head of a linked list of class driver nodes.
  4808. Context - Supplies the address of a context structure used in building the
  4809. compatible driver list.
  4810. Return Value:
  4811. If successful, the return code is NO_ERROR, otherwise, it is a Win32 error code.
  4812. --*/
  4813. {
  4814. PDRIVER_NODE CompatDriverNode = NULL;
  4815. DWORD Err = NO_ERROR;
  4816. BOOL InsertedAtHead;
  4817. UINT Rank, CurrentRank, i;
  4818. try {
  4819. //
  4820. // Examine each node in the class driver list, and copy any compatible drivers
  4821. // into the compatible driver list.
  4822. //
  4823. for(; ClassDriverList; ClassDriverList = ClassDriverList->Next) {
  4824. if(ClassDriverList->HardwareId == -1) {
  4825. //
  4826. // If there's no HardwareId, then we know there are no compatible IDs,
  4827. // we can skip this driver node
  4828. //
  4829. continue;
  4830. }
  4831. if(pSetupCalculateRankMatch(ClassDriverList->HardwareId,
  4832. 2,
  4833. Context->IdList,
  4834. &Rank)) {
  4835. //
  4836. // Then we didn't hit a hardware ID match, so check the compatible IDs.
  4837. //
  4838. for(i = 0; i < ClassDriverList->NumCompatIds; i++) {
  4839. if(!pSetupCalculateRankMatch(ClassDriverList->CompatIdList[i],
  4840. i + 3,
  4841. Context->IdList,
  4842. &CurrentRank)) {
  4843. //
  4844. // Then we had a match on a hardware ID--that's the best we're gonna get.
  4845. //
  4846. Rank = CurrentRank;
  4847. break;
  4848. } else if(CurrentRank < Rank) {
  4849. //
  4850. // This new rank is better than our current rank.
  4851. //
  4852. Rank = CurrentRank;
  4853. }
  4854. }
  4855. }
  4856. if(Rank != RANK_NO_MATCH) {
  4857. //
  4858. // Make a copy of the class driver node for our new compatible driver node.
  4859. //
  4860. if(CompatDriverNode = DuplicateDriverNode(ClassDriverList)) {
  4861. //
  4862. // Update the rank of our new driver node to what we just calculated.
  4863. //
  4864. CompatDriverNode->Rank = Rank;
  4865. //
  4866. // Mask out the duplicate description flag--this will be re-computed below.
  4867. //
  4868. CompatDriverNode->Flags &= ~DNF_DUPDESC;
  4869. } else {
  4870. Err = ERROR_NOT_ENOUGH_MEMORY;
  4871. break;
  4872. }
  4873. //
  4874. // Merge the new driver node into our existing list.
  4875. // NOTE: Do not dereference CompatDriverNode after this call,
  4876. // since it may have been a duplicate, in which case it
  4877. // will be destroyed by this routine.
  4878. //
  4879. pSetupMergeDriverNode(Context, CompatDriverNode, &InsertedAtHead);
  4880. CompatDriverNode = NULL;
  4881. if(InsertedAtHead) {
  4882. //
  4883. // Update the device instance class to that of the new lowest-rank driver.
  4884. //
  4885. CopyMemory(&(Context->ClassGuid),
  4886. &(Context->DeviceInfoSet->GuidTable[ClassDriverList->GuidIndex]),
  4887. sizeof(GUID)
  4888. );
  4889. Context->Flags |= DRVSRCH_HASCLASSGUID;
  4890. *(Context->ClassName) = TEXT('\0');
  4891. }
  4892. }
  4893. }
  4894. } except(EXCEPTION_EXECUTE_HANDLER) {
  4895. Err = ERROR_INVALID_PARAMETER;
  4896. if(CompatDriverNode) {
  4897. //
  4898. // Make sure it didn't get partially linked into a list.
  4899. //
  4900. CompatDriverNode->Next = NULL;
  4901. DestroyDriverNodes(CompatDriverNode, Context->DeviceInfoSet);
  4902. }
  4903. }
  4904. if(Err != NO_ERROR) {
  4905. DestroyDriverNodes(*(Context->pDriverListHead), Context->DeviceInfoSet);
  4906. *(Context->pDriverListHead) = *(Context->pDriverListTail) = NULL;
  4907. *(Context->pDriverCount) = 0;
  4908. }
  4909. return Err;
  4910. }
  4911. PDRIVER_NODE
  4912. DuplicateDriverNode(
  4913. IN PDRIVER_NODE DriverNode
  4914. )
  4915. /*++
  4916. Routine Description:
  4917. This routine makes a copy of the specified driver node.
  4918. Arguments:
  4919. DriverNode - Supplies the address of the driver node to be copied.
  4920. Return Value:
  4921. If successful, the return value is the address of the newly-allocated copy.
  4922. If failure (due to out-of-memory), the return value is NULL.
  4923. --*/
  4924. {
  4925. PDRIVER_NODE NewDriverNode;
  4926. BOOL FreeCompatIdList;
  4927. if(!(NewDriverNode = MyMalloc(sizeof(DRIVER_NODE)))) {
  4928. return NULL;
  4929. }
  4930. FreeCompatIdList = FALSE;
  4931. try {
  4932. CopyMemory(NewDriverNode, DriverNode, sizeof(DRIVER_NODE));
  4933. NewDriverNode->Next = NULL;
  4934. if(DriverNode->NumCompatIds) {
  4935. //
  4936. // Then allocate an array to contain them.
  4937. //
  4938. if(NewDriverNode->CompatIdList = MyMalloc(DriverNode->NumCompatIds * sizeof(LONG))) {
  4939. FreeCompatIdList = TRUE;
  4940. CopyMemory(NewDriverNode->CompatIdList,
  4941. DriverNode->CompatIdList,
  4942. DriverNode->NumCompatIds * sizeof(LONG)
  4943. );
  4944. } else {
  4945. MyFree(NewDriverNode);
  4946. NewDriverNode = NULL;
  4947. }
  4948. }
  4949. } except(EXCEPTION_EXECUTE_HANDLER) {
  4950. if(FreeCompatIdList) {
  4951. MyFree(NewDriverNode->CompatIdList);
  4952. }
  4953. MyFree(NewDriverNode);
  4954. NewDriverNode = NULL;
  4955. }
  4956. return NewDriverNode;
  4957. }
  4958. BOOL
  4959. WINAPI
  4960. SetupDiCancelDriverInfoSearch(
  4961. IN HDEVINFO DeviceInfoSet
  4962. )
  4963. /*++
  4964. Routine Description:
  4965. This routine cancels a driver list search that is currently underway in a
  4966. different thread. This call is synchronous, i.e., it does not return until
  4967. the driver search thread responds to the abort request.
  4968. Arguments:
  4969. DeviceInfoSet - Supplies a handle to the device information set for which
  4970. a driver list is being built.
  4971. Return Value:
  4972. If there was a driver list search currently underway for the specified set,
  4973. it will be aborted, and this routine will return TRUE once the abort is
  4974. confirmed.
  4975. Otherwise, the return value is FALSE, and GetLastError() will return
  4976. ERROR_INVALID_HANDLE.
  4977. --*/
  4978. {
  4979. DWORD Err = ERROR_INVALID_HANDLE;
  4980. PDRVSEARCH_INPROGRESS_NODE DrvSearchNode;
  4981. HANDLE SearchCancelledEvent;
  4982. if(!LockDrvSearchInProgressList(&GlobalDrvSearchInProgressList)) {
  4983. //
  4984. // Uh-oh! We're going away!
  4985. //
  4986. goto clean0;
  4987. }
  4988. try {
  4989. //
  4990. // Step through the list, looking for a node that matches our HDEVINFO.
  4991. //
  4992. for(DrvSearchNode = GlobalDrvSearchInProgressList.DrvSearchHead;
  4993. DrvSearchNode;
  4994. DrvSearchNode = DrvSearchNode->Next) {
  4995. if(DrvSearchNode->DeviceInfoSet == DeviceInfoSet) {
  4996. //
  4997. // We found the node--therefore, this devinfo set is currently
  4998. // tied up with a driver list search. Set the 'CancelSearch' flag,
  4999. // to notify the other thread that it should abort.
  5000. //
  5001. DrvSearchNode->CancelSearch = TRUE;
  5002. SearchCancelledEvent = DrvSearchNode->SearchCancelledEvent;
  5003. Err = NO_ERROR;
  5004. break;
  5005. }
  5006. }
  5007. } except(EXCEPTION_EXECUTE_HANDLER) {
  5008. Err = ERROR_INVALID_HANDLE;
  5009. }
  5010. //
  5011. // Very important that we unlock this list _before_ waiting on the other thread
  5012. // to respond!
  5013. //
  5014. UnlockDrvSearchInProgressList(&GlobalDrvSearchInProgressList);
  5015. if(Err == NO_ERROR) {
  5016. //
  5017. // We've signalled the other thread to abort--now wait for it to respond.
  5018. //
  5019. WaitForSingleObject(SearchCancelledEvent, INFINITE);
  5020. }
  5021. clean0:
  5022. SetLastError(Err);
  5023. return (Err == NO_ERROR);
  5024. }
  5025. BOOL
  5026. InitDrvSearchInProgressList(
  5027. VOID
  5028. )
  5029. /*++
  5030. Routine Description:
  5031. This routine initializes the global "Driver Search In-Progress" list, that is
  5032. used to allow one thread to abort a driver search operation taking place in
  5033. another thread.
  5034. Arguments:
  5035. None
  5036. Return Value:
  5037. If success, the return value is TRUE, otherwise, it is FALSE.
  5038. --*/
  5039. {
  5040. ZeroMemory(&GlobalDrvSearchInProgressList, sizeof(DRVSEARCH_INPROGRESS_LIST));
  5041. return InitializeSynchronizedAccess(&GlobalDrvSearchInProgressList.Lock);
  5042. }
  5043. BOOL
  5044. DestroyDrvSearchInProgressList(
  5045. VOID
  5046. )
  5047. /*++
  5048. Routine Description:
  5049. This routine destroys the global "Driver Search In-Progress" list, that is
  5050. used to allow one thread to abort a driver search operation taking place in
  5051. another thread.
  5052. Arguments:
  5053. None
  5054. Return Value:
  5055. If success, the return value is TRUE, otherwise, it is FALSE.
  5056. --*/
  5057. {
  5058. PDRVSEARCH_INPROGRESS_NODE DriverSearchNode;
  5059. if(LockDrvSearchInProgressList(&GlobalDrvSearchInProgressList)) {
  5060. //
  5061. // We would hope that this list is empty, but that may not be the case.
  5062. // We will traverse this list, and signal the event for each node we find.
  5063. // That way, any threads still waiting for driver searches to abort can
  5064. // continue on. We do not free the memory associated with these nodes,
  5065. // since it is 'owned' by the HDEVINFO, and that is where the responsibility
  5066. // lies to free it.
  5067. //
  5068. try {
  5069. for(DriverSearchNode = GlobalDrvSearchInProgressList.DrvSearchHead;
  5070. DriverSearchNode;
  5071. DriverSearchNode = DriverSearchNode->Next)
  5072. {
  5073. SetEvent(DriverSearchNode->SearchCancelledEvent);
  5074. }
  5075. } except(EXCEPTION_EXECUTE_HANDLER) {
  5076. ; // nothing
  5077. }
  5078. DestroySynchronizedAccess(&GlobalDrvSearchInProgressList.Lock);
  5079. return TRUE;
  5080. }
  5081. return FALSE;
  5082. }
  5083. BOOL
  5084. ExtractDrvSearchInProgressNode(
  5085. PDRVSEARCH_INPROGRESS_NODE Node
  5086. )
  5087. /*++
  5088. Routine Description:
  5089. This routine extracts the specified node out of the global "Driver Search
  5090. In-Progress" list, and if its 'CancelSearch' flag is set, then it signals
  5091. all waiting threads that it has responded to their cancel request.
  5092. Arguments:
  5093. Node - Supplies the address of the node to be extracted from the list.
  5094. Return Value:
  5095. If the node was found in the list, and the 'CancelSearch' flag was set, then
  5096. the return value is TRUE, otherwise, it is FALSE.
  5097. --*/
  5098. {
  5099. PDRVSEARCH_INPROGRESS_NODE PrevNode, CurNode;
  5100. BOOL b;
  5101. if(!LockDrvSearchInProgressList(&GlobalDrvSearchInProgressList)) {
  5102. //
  5103. // This should only happen if we're in the middle of a DLL_PROCESS_DETACH.
  5104. // In this case, the clean-up code in CommonProcessAttach(FALSE) will signal
  5105. // all waiting threads, so there's nothing we need to do.
  5106. //
  5107. return FALSE;
  5108. }
  5109. b = FALSE;
  5110. try {
  5111. //
  5112. // Search through the list, looking for our node.
  5113. //
  5114. for(CurNode = GlobalDrvSearchInProgressList.DrvSearchHead, PrevNode = NULL;
  5115. CurNode;
  5116. PrevNode = CurNode, CurNode = CurNode->Next) {
  5117. if(CurNode == Node) {
  5118. //
  5119. // We've found the specified node in the global list.
  5120. //
  5121. break;
  5122. }
  5123. }
  5124. if(!CurNode) {
  5125. //
  5126. // The node wasn't in the list--probably because some kind of exception occurred
  5127. // before it could be linked in. Since it wasn't in the list, no other thread
  5128. // could be waiting on it, so again, there's nothing to do.
  5129. //
  5130. goto clean0;
  5131. }
  5132. if(CurNode->CancelSearch) {
  5133. b = TRUE;
  5134. SetEvent(CurNode->SearchCancelledEvent);
  5135. }
  5136. //
  5137. // Remove this node from the linked list.
  5138. //
  5139. if(PrevNode) {
  5140. PrevNode->Next = CurNode->Next;
  5141. } else {
  5142. GlobalDrvSearchInProgressList.DrvSearchHead = CurNode->Next;
  5143. }
  5144. clean0: ; // nothing to do.
  5145. } except(EXCEPTION_EXECUTE_HANDLER) {
  5146. //
  5147. // Access the flag variable so the compiler will respect our statement ordering w.r.t.
  5148. // this value.
  5149. //
  5150. b = b;
  5151. }
  5152. UnlockDrvSearchInProgressList(&GlobalDrvSearchInProgressList);
  5153. return b;
  5154. }