Leaked source code of windows server 2003
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.

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