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

6699 lines
214 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. diutil.c
  5. Abstract:
  6. Device Installer utility routines.
  7. Author:
  8. Lonny McMichael (lonnym) 10-May-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include <initguid.h>
  14. //
  15. // Define and initialize all device class GUIDs.
  16. // (This must only be done once per module!)
  17. //
  18. #include <devguid.h>
  19. //
  20. // Define and initialize a global variable, GUID_NULL
  21. // (from coguid.h)
  22. //
  23. DEFINE_GUID(GUID_NULL, 0L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  24. //
  25. // Define the period in miliseconds to wait between attempts to lock the SCM database
  26. //
  27. #define ACQUIRE_SCM_LOCK_INTERVAL 500
  28. //
  29. // Define the number of attempts at locking the SCM database should be made
  30. //
  31. #define ACQUIRE_SCM_LOCK_ATTEMPTS 5
  32. //
  33. // Declare global string variables used throughout device
  34. // installer routines.
  35. //
  36. // These strings are defined in regstr.h:
  37. //
  38. CONST TCHAR pszNoUseClass[] = REGSTR_VAL_NOUSECLASS,
  39. pszNoInstallClass[] = REGSTR_VAL_NOINSTALLCLASS,
  40. pszNoDisplayClass[] = REGSTR_VAL_NODISPLAYCLASS,
  41. pszDeviceDesc[] = REGSTR_VAL_DEVDESC,
  42. pszDevicePath[] = REGSTR_VAL_DEVICEPATH,
  43. pszPathSetup[] = REGSTR_PATH_SETUP,
  44. pszKeySetup[] = REGSTR_KEY_SETUP,
  45. pszPathRunOnce[] = REGSTR_PATH_RUNONCE,
  46. pszSourcePath[] = REGSTR_VAL_SRCPATH,
  47. pszSvcPackPath[] = REGSTR_VAL_SVCPAKSRCPATH,
  48. pszDriverCachePath[] = REGSTR_VAL_DRIVERCACHEPATH,
  49. pszBootDir[] = REGSTR_VAL_BOOTDIR,
  50. pszInsIcon[] = REGSTR_VAL_INSICON,
  51. pszInstaller32[] = REGSTR_VAL_INSTALLER_32,
  52. pszEnumPropPages32[] = REGSTR_VAL_ENUMPROPPAGES_32,
  53. pszInfPath[] = REGSTR_VAL_INFPATH,
  54. pszInfSection[] = REGSTR_VAL_INFSECTION,
  55. pszDrvDesc[] = REGSTR_VAL_DRVDESC,
  56. pszHardwareID[] = REGSTR_VAL_HARDWAREID,
  57. pszCompatibleIDs[] = REGSTR_VAL_COMPATIBLEIDS,
  58. pszDriver[] = REGSTR_VAL_DRIVER,
  59. pszConfigFlags[] = REGSTR_VAL_CONFIGFLAGS,
  60. pszMfg[] = REGSTR_VAL_MFG,
  61. pszService[] = REGSTR_VAL_SERVICE,
  62. pszProviderName[] = REGSTR_VAL_PROVIDER_NAME,
  63. pszFriendlyName[] = REGSTR_VAL_FRIENDLYNAME,
  64. pszServicesRegPath[] = REGSTR_PATH_SERVICES,
  65. pszLegacyInfOption[] = REGSTR_VAL_LEGACYINFOPT,
  66. pszInfSectionExt[] = REGSTR_VAL_INFSECTIONEXT,
  67. pszDeviceClassesPath[] = REGSTR_PATH_DEVICE_CLASSES,
  68. pszDeviceInstance[] = REGSTR_VAL_DEVICE_INSTANCE,
  69. pszDefault[] = REGSTR_VAL_DEFAULT,
  70. pszControl[] = REGSTR_KEY_CONTROL,
  71. pszLinked[] = REGSTR_VAL_LINKED,
  72. pszDeviceParameters[] = REGSTR_KEY_DEVICEPARAMETERS,
  73. pszLocationInformation[] = REGSTR_VAL_LOCATION_INFORMATION,
  74. pszCapabilities[] = REGSTR_VAL_CAPABILITIES,
  75. pszUiNumber[] = REGSTR_VAL_UI_NUMBER,
  76. pszUpperFilters[] = REGSTR_VAL_UPPERFILTERS,
  77. pszLowerFilters[] = REGSTR_VAL_LOWERFILTERS,
  78. pszMatchingDeviceId[] = REGSTR_VAL_MATCHINGDEVID,
  79. pszBasicProperties32[] = REGSTR_VAL_BASICPROPERTIES_32,
  80. pszCoInstallers32[] = REGSTR_VAL_COINSTALLERS_32,
  81. pszPathCoDeviceInstallers[] = REGSTR_PATH_CODEVICEINSTALLERS,
  82. pszSystem[] = REGSTR_KEY_SYSTEM,
  83. pszDrvSignPath[] = REGSTR_PATH_DRIVERSIGN,
  84. pszNonDrvSignPath[] = REGSTR_PATH_NONDRIVERSIGN,
  85. pszDrvSignPolicyPath[] = REGSTR_PATH_DRIVERSIGN_POLICY,
  86. pszNonDrvSignPolicyPath[] = REGSTR_PATH_NONDRIVERSIGN_POLICY,
  87. pszDrvSignPolicyValue[] = REGSTR_VAL_POLICY,
  88. pszDrvSignBehaviorOnFailedVerifyDS[] = REGSTR_VAL_BEHAVIOR_ON_FAILED_VERIFY,
  89. pszDriverDate[] = REGSTR_VAL_DRIVERDATE,
  90. pszDriverDateData[] = REGSTR_VAL_DRIVERDATEDATA,
  91. pszDriverVersion[] = REGSTR_VAL_DRIVERVERSION,
  92. pszDevSecurity[] = REGSTR_VAL_DEVICE_SECURITY_DESCRIPTOR,
  93. pszDevType[] = REGSTR_VAL_DEVICE_TYPE,
  94. pszExclusive[] = REGSTR_VAL_DEVICE_EXCLUSIVE,
  95. pszCharacteristics[] = REGSTR_VAL_DEVICE_CHARACTERISTICS,
  96. pszUiNumberDescFormat[] = REGSTR_VAL_UI_NUMBER_DESC_FORMAT,
  97. pszRemovalPolicyOverride[] = REGSTR_VAL_REMOVAL_POLICY,
  98. pszReinstallPath[] = REGSTR_PATH_REINSTALL,
  99. pszReinstallDeviceInstanceIds[] = REGSTR_VAL_REINSTALL_DEVICEINSTANCEIDS,
  100. pszReinstallDisplayName[] = REGSTR_VAL_REINSTALL_DISPLAYNAME,
  101. pszReinstallString[] = REGSTR_VAL_REINSTALL_STRING;
  102. //
  103. // Other misc. global strings (defined in devinst.h):
  104. //
  105. CONST TCHAR pszInfWildcard[] = DISTR_INF_WILDCARD,
  106. pszOemInfWildcard[] = DISTR_OEMINF_WILDCARD,
  107. pszCiDefaultProc[] = DISTR_CI_DEFAULTPROC,
  108. pszSpaceLparen[] = DISTR_SPACE_LPAREN,
  109. pszRparen[] = DISTR_RPAREN,
  110. pszUniqueSubKey[] = DISTR_UNIQUE_SUBKEY,
  111. pszOemInfGenerate[] = DISTR_OEMINF_GENERATE,
  112. pszOemInfDefaultPath[] = DISTR_OEMINF_DEFAULTPATH,
  113. pszDefaultService[] = DISTR_DEFAULT_SERVICE,
  114. pszGuidNull[] = DISTR_GUID_NULL,
  115. pszEventLog[] = DISTR_EVENTLOG,
  116. pszGroupOrderListPath[] = DISTR_GROUPORDERLIST_PATH,
  117. pszServiceGroupOrderPath[] = DISTR_SERVICEGROUPORDER_PATH,
  118. pszOptions[] = DISTR_OPTIONS,
  119. pszOptionsText[] = DISTR_OPTIONSTEXT,
  120. pszLanguagesSupported[] = DISTR_LANGUAGESSUPPORTED,
  121. pszRunOnceExe[] = DISTR_RUNONCE_EXE,
  122. pszGrpConv[] = DISTR_GRPCONV,
  123. pszGrpConvNoUi[] = DISTR_GRPCONV_NOUI,
  124. pszDefaultSystemPartition[] = DISTR_DEFAULT_SYSPART,
  125. pszBasicPropDefaultProc[] = DISTR_BASICPROP_DEFAULTPROC,
  126. pszEnumPropDefaultProc[] = DISTR_ENUMPROP_DEFAULTPROC,
  127. pszCoInstallerDefaultProc[] = DISTR_CODEVICEINSTALL_DEFAULTPROC,
  128. pszDriverObjectPathPrefix[] = DISTR_DRIVER_OBJECT_PATH_PREFIX,
  129. pszDriverSigningClasses[] = DISTR_DRIVER_SIGNING_CLASSES,
  130. pszEmbeddedNTSecurity[] = DISTR_PATH_EMBEDDED_NT_SECURITY,
  131. pszMinimizeFootprint[] = DISTR_VAL_MINIMIZE_FOOTPRINT,
  132. pszDisableSCE[] = DISTR_VAL_DISABLE_SCE;
  133. //
  134. // Define flag bitmask indicating which flags are controlled internally by the
  135. // device installer routines, and thus are read-only to clients.
  136. //
  137. #define DI_FLAGS_READONLY ( DI_DIDCOMPAT | DI_DIDCLASS | DI_MULTMFGS )
  138. #define DI_FLAGSEX_READONLY ( DI_FLAGSEX_DIDINFOLIST \
  139. | DI_FLAGSEX_DIDCOMPATINFO \
  140. | DI_FLAGSEX_IN_SYSTEM_SETUP )
  141. #define DNF_FLAGS_READONLY ( DNF_DUPDESC \
  142. | DNF_OLDDRIVER \
  143. | DNF_LEGACYINF \
  144. | DNF_CLASS_DRIVER \
  145. | DNF_COMPATIBLE_DRIVER \
  146. | DNF_INET_DRIVER \
  147. | DNF_INDEXED_DRIVER \
  148. | DNF_OLD_INET_DRIVER \
  149. | DNF_DUPPROVIDER \
  150. | DNF_INF_IS_SIGNED \
  151. | DNF_OEM_F6_INF \
  152. | DNF_DUPDRIVERVER )
  153. //
  154. // Define flag bitmask indicating which flags are illegal.
  155. //
  156. #define DI_FLAGS_ILLEGAL ( 0x00400000L ) // setupx DI_NOSYNCPROCESSING flag
  157. #define DI_FLAGSEX_ILLEGAL ( 0xC0000008L ) // all flags not currently defined
  158. #define DNF_FLAGS_ILLEGAL ( 0xFFFE0000L ) // ""
  159. #define NDW_INSTALLFLAG_ILLEGAL (~( NDW_INSTALLFLAG_DIDFACTDEFS \
  160. | NDW_INSTALLFLAG_HARDWAREALLREADYIN \
  161. | NDW_INSTALLFLAG_NEEDRESTART \
  162. | NDW_INSTALLFLAG_NEEDREBOOT \
  163. | NDW_INSTALLFLAG_NEEDSHUTDOWN \
  164. | NDW_INSTALLFLAG_EXPRESSINTRO \
  165. | NDW_INSTALLFLAG_SKIPISDEVINSTALLED \
  166. | NDW_INSTALLFLAG_NODETECTEDDEVS \
  167. | NDW_INSTALLFLAG_INSTALLSPECIFIC \
  168. | NDW_INSTALLFLAG_SKIPCLASSLIST \
  169. | NDW_INSTALLFLAG_CI_PICKED_OEM \
  170. | NDW_INSTALLFLAG_PCMCIAMODE \
  171. | NDW_INSTALLFLAG_PCMCIADEVICE \
  172. | NDW_INSTALLFLAG_USERCANCEL \
  173. | NDW_INSTALLFLAG_KNOWNCLASS ))
  174. #define DYNAWIZ_FLAG_ILLEGAL (~( DYNAWIZ_FLAG_PAGESADDED \
  175. | DYNAWIZ_FLAG_INSTALLDET_NEXT \
  176. | DYNAWIZ_FLAG_INSTALLDET_PREV \
  177. | DYNAWIZ_FLAG_ANALYZE_HANDLECONFLICT ))
  178. #define NEWDEVICEWIZARD_FLAG_ILLEGAL (~(0)) // no flags are legal presently
  179. //
  180. // Declare data used in GUID->string conversion (from ole32\common\ccompapi.cxx).
  181. //
  182. static const BYTE GuidMap[] = { 3, 2, 1, 0, '-', 5, 4, '-', 7, 6, '-',
  183. 8, 9, '-', 10, 11, 12, 13, 14, 15 };
  184. static const TCHAR szDigits[] = TEXT("0123456789ABCDEF");
  185. PDEVICE_INFO_SET
  186. AllocateDeviceInfoSet(
  187. VOID
  188. )
  189. /*++
  190. Routine Description:
  191. This routine allocates a device information set structure, zeroes it,
  192. and initializes the synchronization lock for it.
  193. Arguments:
  194. none.
  195. Return Value:
  196. If the function succeeds, the return value is a pointer to the new
  197. device information set.
  198. If the function fails, the return value is NULL.
  199. --*/
  200. {
  201. PDEVICE_INFO_SET p;
  202. if(p = MyMalloc(sizeof(DEVICE_INFO_SET))) {
  203. ZeroMemory(p, sizeof(DEVICE_INFO_SET));
  204. p->MachineName = -1;
  205. p->InstallParamBlock.DriverPath = -1;
  206. p->InstallParamBlock.CoInstallerCount = -1;
  207. //
  208. // If we're in GUI-mode setup on Windows NT, we'll automatically set
  209. // the DI_FLAGSEX_IN_SYSTEM_SETUP flag in the devinstall parameter
  210. // block for this devinfo set.
  211. //
  212. if(GuiSetupInProgress) {
  213. p->InstallParamBlock.FlagsEx |= DI_FLAGSEX_IN_SYSTEM_SETUP;
  214. }
  215. //
  216. // If we're in non-interactive mode, set the "be quiet" bits.
  217. //
  218. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  219. p->InstallParamBlock.Flags |= DI_QUIETINSTALL;
  220. p->InstallParamBlock.FlagsEx |= DI_FLAGSEX_NOUIONQUERYREMOVE;
  221. }
  222. //
  223. // Initialize our enumeration 'hints'
  224. //
  225. p->DeviceInfoEnumHintIndex = INVALID_ENUM_INDEX;
  226. p->ClassDriverEnumHintIndex = INVALID_ENUM_INDEX;
  227. if(p->StringTable = pStringTableInitialize(0)) {
  228. if (CreateLogContext(NULL, FALSE, &(p->InstallParamBlock.LogContext)) == NO_ERROR) {
  229. //
  230. // succeeded
  231. //
  232. if(InitializeSynchronizedAccess(&(p->Lock))) {
  233. return p;
  234. }
  235. DeleteLogContext(p->InstallParamBlock.LogContext);
  236. }
  237. pStringTableDestroy(p->StringTable);
  238. }
  239. MyFree(p);
  240. }
  241. return NULL;
  242. }
  243. VOID
  244. DestroyDeviceInfoElement(
  245. IN HDEVINFO hDevInfo,
  246. IN PDEVICE_INFO_SET pDeviceInfoSet,
  247. IN PDEVINFO_ELEM DeviceInfoElement
  248. )
  249. /*++
  250. Routine Description:
  251. This routine destroys the specified device information element, freeing
  252. all resources associated with it.
  253. ASSUMES THAT THE CALLING ROUTINE HAS ALREADY ACQUIRED THE LOCK!
  254. Arguments:
  255. hDevInfo - Supplies a handle to the device information set whose internal
  256. representation is given by pDeviceInfoSet. This opaque handle is
  257. actually the same pointer as pDeviceInfoSet, but we want to keep this
  258. distinction clean, so that in the future we can change our implementation
  259. (e.g., hDevInfo might represent an offset in an array of DEVICE_INFO_SET
  260. elements).
  261. pDeviceInfoSet - Supplies a pointer to the device information set of which
  262. the devinfo element is a member. This set contains the class driver list
  263. object list that must be used in destroying the class driver list.
  264. DeviceInfoElement - Supplies a pointer to the device information element
  265. to be destroyed.
  266. Return Value:
  267. None.
  268. --*/
  269. {
  270. DWORD i;
  271. PINTERFACE_DEVICE_NODE InterfaceDeviceNode, NextInterfaceDeviceNode;
  272. CONFIGRET cr;
  273. MYASSERT(hDevInfo && (hDevInfo != INVALID_HANDLE_VALUE));
  274. //
  275. // Free resources contained in the install parameters block. Do this
  276. // before anything else, because we'll be calling the class installer
  277. // with DIF_DESTROYPRIVATEDATA, and we want everything to be in a
  278. // consistent state when we do (plus, it may need to destroy private
  279. // data it's stored with individual driver nodes).
  280. //
  281. DestroyInstallParamBlock(hDevInfo,
  282. pDeviceInfoSet,
  283. DeviceInfoElement,
  284. &(DeviceInfoElement->InstallParamBlock)
  285. );
  286. //
  287. // Dereference the class driver list.
  288. //
  289. DereferenceClassDriverList(pDeviceInfoSet, DeviceInfoElement->ClassDriverHead);
  290. //
  291. // Destroy compatible driver list.
  292. //
  293. DestroyDriverNodes(DeviceInfoElement->CompatDriverHead, pDeviceInfoSet);
  294. //
  295. // If this is a non-registered device instance, then delete any registry
  296. // keys the caller may have created during the lifetime of this element.
  297. //
  298. if(DeviceInfoElement->DevInst && !(DeviceInfoElement->DiElemFlags & DIE_IS_REGISTERED)) {
  299. pSetupDeleteDevRegKeys(DeviceInfoElement->DevInst,
  300. DICS_FLAG_GLOBAL | DICS_FLAG_CONFIGSPECIFIC,
  301. (DWORD)-1,
  302. DIREG_BOTH,
  303. TRUE
  304. );
  305. cr = CM_Uninstall_DevInst(DeviceInfoElement->DevInst, 0);
  306. }
  307. //
  308. // Free any interface device lists that may be associated with this devinfo element.
  309. //
  310. if(DeviceInfoElement->InterfaceClassList) {
  311. for(i = 0; i < DeviceInfoElement->InterfaceClassListSize; i++) {
  312. for(InterfaceDeviceNode = DeviceInfoElement->InterfaceClassList[i].InterfaceDeviceNode;
  313. InterfaceDeviceNode;
  314. InterfaceDeviceNode = NextInterfaceDeviceNode) {
  315. NextInterfaceDeviceNode = InterfaceDeviceNode->Next;
  316. MyFree(InterfaceDeviceNode);
  317. }
  318. }
  319. MyFree(DeviceInfoElement->InterfaceClassList);
  320. }
  321. //
  322. // Zero the signature field containing the address of the containing devinfo
  323. // set. This will keep us thinking an SP_DEVINFO_DATA is still valid after
  324. // the underlying element has been deleted.
  325. //
  326. DeviceInfoElement->ContainingDeviceInfoSet = NULL;
  327. MyFree(DeviceInfoElement);
  328. }
  329. DWORD
  330. DestroyDeviceInfoSet(
  331. IN HDEVINFO hDevInfo, OPTIONAL
  332. IN PDEVICE_INFO_SET pDeviceInfoSet
  333. )
  334. /*++
  335. Routine Description:
  336. This routine frees a device information set, and all resources
  337. used on its behalf.
  338. Arguments:
  339. hDevInfo - Optionally, supplies a handle to the device information set
  340. whose internal representation is given by pDeviceInfoSet. This
  341. opaque handle is actually the same pointer as pDeviceInfoSet, but
  342. we want to keep this distinction clean, so that in the future we
  343. can change our implementation (e.g., hDevInfo might represent an
  344. offset in an array of DEVICE_INFO_SET elements).
  345. This parameter will only be NULL if we're cleaning up half-way
  346. through the creation of a device information set.
  347. pDeviceInfoSet - supplies a pointer to the device information set
  348. to be freed.
  349. Return Value:
  350. If successful, the return code is NO_ERROR, otherwise, it is an
  351. ERROR_* code.
  352. --*/
  353. {
  354. PDEVINFO_ELEM NextElem;
  355. PDRIVER_NODE DriverNode, NextNode;
  356. PMODULE_HANDLE_LIST_NODE NextModuleHandleNode;
  357. DWORD i;
  358. SPFUSIONINSTANCE spFusionInstance;
  359. //
  360. // We have to make sure that the wizard refcount is zero, and that
  361. // we haven't acquired the lock more than once (i.e., we're nested
  362. // more than one level deep in Di calls.
  363. //
  364. if(pDeviceInfoSet->WizPageList ||
  365. (pDeviceInfoSet->LockRefCount > 1)) {
  366. return ERROR_DEVINFO_LIST_LOCKED;
  367. }
  368. //
  369. // Destroy all the device information elements in this set. Make sure
  370. // that we maintain consistency while removing devinfo elements, because
  371. // we may be calling the class installer. This means that the device
  372. // installer APIs still have to work, even while we're tearing down the
  373. // list.
  374. //
  375. while(pDeviceInfoSet->DeviceInfoHead) {
  376. //
  377. // We'd better not have any device info elements locked by wizard
  378. // pages, since our wizard refcount is zero!
  379. //
  380. MYASSERT(!(pDeviceInfoSet->DeviceInfoHead->DiElemFlags & DIE_IS_LOCKED));
  381. NextElem = pDeviceInfoSet->DeviceInfoHead->Next;
  382. DestroyDeviceInfoElement(hDevInfo, pDeviceInfoSet, pDeviceInfoSet->DeviceInfoHead);
  383. MYASSERT(pDeviceInfoSet->DeviceInfoCount > 0);
  384. pDeviceInfoSet->DeviceInfoCount--;
  385. //
  386. // If this element was the currently selected device for this
  387. // set, then reset the device selection.
  388. //
  389. if(pDeviceInfoSet->SelectedDevInfoElem == pDeviceInfoSet->DeviceInfoHead) {
  390. pDeviceInfoSet->SelectedDevInfoElem = NULL;
  391. }
  392. pDeviceInfoSet->DeviceInfoHead = NextElem;
  393. }
  394. MYASSERT(pDeviceInfoSet->DeviceInfoCount == 0);
  395. pDeviceInfoSet->DeviceInfoTail = NULL;
  396. //
  397. // Free resources contained in the install parameters block. Do this
  398. // before anything else, because we'll be calling the class installer
  399. // with DIF_DESTROYPRIVATEDATA, and we want everything to be in a
  400. // consistent state when we do (plus, it may need to destroy private
  401. // data it's stored with individual driver nodes).
  402. //
  403. DestroyInstallParamBlock(hDevInfo,
  404. pDeviceInfoSet,
  405. NULL,
  406. &(pDeviceInfoSet->InstallParamBlock)
  407. );
  408. //
  409. // Destroy class driver list.
  410. //
  411. if(pDeviceInfoSet->ClassDriverHead) {
  412. //
  413. // We've already destroyed all device information elements, so there should be
  414. // exactly one driver list object remaining--the one referenced by the global
  415. // class driver list. Also, it's refcount should be 1.
  416. //
  417. MYASSERT(
  418. (pDeviceInfoSet->ClassDrvListObjectList) &&
  419. (!pDeviceInfoSet->ClassDrvListObjectList->Next) &&
  420. (pDeviceInfoSet->ClassDrvListObjectList->RefCount == 1) &&
  421. (pDeviceInfoSet->ClassDrvListObjectList->DriverListHead == pDeviceInfoSet->ClassDriverHead)
  422. );
  423. MyFree(pDeviceInfoSet->ClassDrvListObjectList);
  424. DestroyDriverNodes(pDeviceInfoSet->ClassDriverHead, pDeviceInfoSet);
  425. }
  426. //
  427. // Free the interface class GUID list (if there is one).
  428. //
  429. if(pDeviceInfoSet->GuidTable) {
  430. MyFree(pDeviceInfoSet->GuidTable);
  431. }
  432. //
  433. // Destroy the associated string table.
  434. //
  435. pStringTableDestroy(pDeviceInfoSet->StringTable);
  436. //
  437. // Destroy the lock (we have to do this after we've made all necessary calls
  438. // to the class installer, because after the lock is freed, the HDEVINFO set
  439. // is inaccessible).
  440. //
  441. DestroySynchronizedAccess(&(pDeviceInfoSet->Lock));
  442. //
  443. // If there are any module handles left to be freed, do that now.
  444. //
  445. for(; pDeviceInfoSet->ModulesToFree; pDeviceInfoSet->ModulesToFree = NextModuleHandleNode) {
  446. NextModuleHandleNode = pDeviceInfoSet->ModulesToFree->Next;
  447. for(i = 0; i < pDeviceInfoSet->ModulesToFree->ModuleCount; i++) {
  448. MYASSERT(pDeviceInfoSet->ModulesToFree->ModuleList[i].ModuleHandle);
  449. spFusionEnterContext(pDeviceInfoSet->ModulesToFree->ModuleList[i].FusionContext,
  450. &spFusionInstance);
  451. FreeLibrary(pDeviceInfoSet->ModulesToFree->ModuleList[i].ModuleHandle);
  452. spFusionLeaveContext(&spFusionInstance);
  453. spFusionKillContext(pDeviceInfoSet->ModulesToFree->ModuleList[i].FusionContext);
  454. }
  455. MyFree(pDeviceInfoSet->ModulesToFree);
  456. }
  457. //
  458. // If this is a remote HDEVINFO set, then disconnect from the remote machine.
  459. //
  460. if(pDeviceInfoSet->hMachine) {
  461. CM_Disconnect_Machine(pDeviceInfoSet->hMachine);
  462. }
  463. //
  464. // Now, destroy the container itself.
  465. //
  466. MyFree(pDeviceInfoSet);
  467. return NO_ERROR;
  468. }
  469. VOID
  470. DestroyInstallParamBlock(
  471. IN HDEVINFO hDevInfo, OPTIONAL
  472. IN PDEVICE_INFO_SET pDeviceInfoSet,
  473. IN PDEVINFO_ELEM DevInfoElem, OPTIONAL
  474. IN PDEVINSTALL_PARAM_BLOCK InstallParamBlock
  475. )
  476. /*++
  477. Routine Description:
  478. This routine frees any resources contained in the specified install
  479. parameter block. THE BLOCK ITSELF IS NOT FREED!
  480. Arguments:
  481. hDevInfo - Optionally, supplies a handle to the device information set
  482. containing the element whose parameter block is to be destroyed.
  483. If this parameter is not supplied, then we're cleaning up after
  484. failing part-way through a SetupDiCreateDeviceInfoList.
  485. pDeviceInfoSet - Supplies a pointer to the device information set of which
  486. the devinfo element is a member.
  487. DevInfoElem - Optionally, supplies the address of the device information
  488. element whose parameter block is to be destroyed. If the parameter
  489. block being destroyed is associated with the set itself, then this
  490. parameter will be NULL.
  491. InstallParamBlock - Supplies the address of the install parameter
  492. block whose resources are to be freed.
  493. Return Value:
  494. None.
  495. --*/
  496. {
  497. SP_DEVINFO_DATA DeviceInfoData;
  498. LONG i;
  499. if(InstallParamBlock->UserFileQ) {
  500. //
  501. // If there's a user-supplied file queue stored in this installation
  502. // parameter block, then decrement the refcount on it. Make sure we
  503. // do this before calling the class installer with DIF_DESTROYPRIVATEDATA,
  504. // or else they won't be able to close the queue.
  505. //
  506. MYASSERT(((PSP_FILE_QUEUE)(InstallParamBlock->UserFileQ))->LockRefCount);
  507. ((PSP_FILE_QUEUE)(InstallParamBlock->UserFileQ))->LockRefCount--;
  508. }
  509. if(hDevInfo && (hDevInfo != INVALID_HANDLE_VALUE)) {
  510. //
  511. // Call the class installer/co-installers (if there are any) to let them
  512. // clean up any private data they may have.
  513. //
  514. if(DevInfoElem) {
  515. //
  516. // Generate an SP_DEVINFO_DATA structure from our device information
  517. // element (if we have one).
  518. //
  519. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  520. DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
  521. DevInfoElem,
  522. &DeviceInfoData
  523. );
  524. }
  525. InvalidateHelperModules(hDevInfo,
  526. (DevInfoElem ? &DeviceInfoData : NULL),
  527. IHM_FREE_IMMEDIATELY
  528. );
  529. }
  530. if(InstallParamBlock->ClassInstallHeader) {
  531. MyFree(InstallParamBlock->ClassInstallHeader);
  532. }
  533. //
  534. // Get rid of the log context sitting in here.
  535. //
  536. DeleteLogContext(InstallParamBlock->LogContext);
  537. }
  538. PDEVICE_INFO_SET
  539. AccessDeviceInfoSet(
  540. IN HDEVINFO DeviceInfoSet
  541. )
  542. /*++
  543. Routine Description:
  544. This routine locks the specified device information set, and returns
  545. a pointer to the structure for its internal representation. It also
  546. increments the lock refcount on this set, so that it can't be destroyed
  547. if the lock has been acquired multiple times.
  548. After access to the set is completed, the caller must call
  549. UnlockDeviceInfoSet with the pointer returned by this function.
  550. Arguments:
  551. DeviceInfoSet - Supplies the pointer to the device information set
  552. to be accessed.
  553. Return Value:
  554. If the function succeeds, the return value is a pointer to the
  555. device information set.
  556. If the function fails, the return value is NULL.
  557. Remarks:
  558. If the method for accessing a device information set's internal
  559. representation via its handle changes (e.g., instead of a pointer, it's an
  560. index into a table), then RollbackDeviceInfoSet and CommitDeviceInfoSet
  561. must also be changed. Also, we cast an HDEVINFO to a PDEVICE_INFO_SET
  562. when specifying the containing device information set in a call to
  563. pSetupOpenAndAddNewDevInfoElem in devinfo.c!SetupDiGetClassDevsEx (only
  564. when we're working with a cloned devinfo set).
  565. --*/
  566. {
  567. PDEVICE_INFO_SET p;
  568. try {
  569. p = (PDEVICE_INFO_SET)DeviceInfoSet;
  570. if(LockDeviceInfoSet(p)) {
  571. p->LockRefCount++;
  572. } else {
  573. p = NULL;
  574. }
  575. } except(EXCEPTION_EXECUTE_HANDLER) {
  576. p = NULL;
  577. }
  578. return p;
  579. }
  580. PDEVICE_INFO_SET
  581. CloneDeviceInfoSet(
  582. IN HDEVINFO hDevInfo
  583. )
  584. /*++
  585. Routine Description:
  586. This routine locks the specified device information set, then returns a
  587. clone of the structure used for its internal representation. Device
  588. information elements or device interface nodes may subsequently be added to
  589. this cloned devinfo set, and the results can be committed via
  590. CommitDeviceInfoSet. If the changes must be backed out (e.g., because an
  591. error was encountered while adding the additional elements to the set), the
  592. routine RollbackDeviceInfoSet must be called.
  593. After access to the set is completed (and the changes have either been
  594. committed or rolled back per the discussion above), the caller must call
  595. UnlockDeviceInfoSet with the pointer returned by CommitDeviceInfoSet or
  596. RollbackDeviceInfoSet.
  597. Arguments:
  598. hDevInfo - Supplies the handle of the device information set to be cloned.
  599. Return Value:
  600. If the function succeeds, the return value is a pointer to the
  601. device information set.
  602. If the function fails, the return value is NULL.
  603. Remarks:
  604. The device information set handle specified to this routine MUST NOT BE
  605. USED until the changes are either committed or rolled back. Also, the
  606. PDEVICE_INFO_SET returned by this routine must not be treated like an
  607. HDEVINFO handle--it is not.
  608. --*/
  609. {
  610. PDEVICE_INFO_SET p, NewDevInfoSet;
  611. BOOL b;
  612. PVOID StringTable;
  613. try {
  614. p = (PDEVICE_INFO_SET)hDevInfo;
  615. if(LockDeviceInfoSet(p)) {
  616. p->LockRefCount++;
  617. } else {
  618. p = NULL;
  619. }
  620. } except(EXCEPTION_EXECUTE_HANDLER) {
  621. p = NULL;
  622. }
  623. if(!p) {
  624. return NULL;
  625. }
  626. NewDevInfoSet = NULL;
  627. StringTable = NULL;
  628. b = FALSE;
  629. try {
  630. //
  631. // OK, we successfully locked the device information set. Now, make a copy
  632. // of the internal structure to return to the caller.
  633. //
  634. NewDevInfoSet = MyMalloc(sizeof(DEVICE_INFO_SET));
  635. if(!NewDevInfoSet) {
  636. goto clean0;
  637. }
  638. CopyMemory(NewDevInfoSet, p, sizeof(DEVICE_INFO_SET));
  639. //
  640. // Duplicate the string table contained in this device information set.
  641. //
  642. StringTable = pStringTableDuplicate(p->StringTable);
  643. if(!StringTable) {
  644. goto clean0;
  645. }
  646. NewDevInfoSet->StringTable = StringTable;
  647. //
  648. // We've successfully cloned the device information set!
  649. //
  650. b = TRUE;
  651. clean0: ; // nothing to do.
  652. } except(EXCEPTION_EXECUTE_HANDLER) {
  653. //
  654. // Access the following variables so the compiler will respect our
  655. // statement ordering w.r.t. assignment.
  656. //
  657. NewDevInfoSet = NewDevInfoSet;
  658. StringTable = StringTable;
  659. }
  660. if(!b) {
  661. //
  662. // We failed to make a copy of the device information set--free any
  663. // memory we may have allocated, and unlock the original devinfo set
  664. // before returning failure.
  665. //
  666. if(NewDevInfoSet) {
  667. MyFree(NewDevInfoSet);
  668. }
  669. if(StringTable) {
  670. pStringTableDestroy(StringTable);
  671. }
  672. UnlockDeviceInfoSet(p);
  673. return NULL;
  674. }
  675. return NewDevInfoSet;
  676. }
  677. PDEVICE_INFO_SET
  678. RollbackDeviceInfoSet(
  679. IN HDEVINFO hDevInfo,
  680. IN PDEVICE_INFO_SET ClonedDeviceInfoSet
  681. )
  682. /*++
  683. Routine Description:
  684. This routine rolls back the specified hDevInfo to a known good state that
  685. was saved when the set was cloned via a prior call to CloneDeviceInfoSet.
  686. Arguments:
  687. hDevInfo - Supplies the handle of the device information set to be rolled
  688. back.
  689. ClonedDeviceInfoSet - Supplies the address of the internal structure
  690. representing the hDevInfo set's cloned (and potentially, modified)
  691. information. Upon successful return, this structure will be freed.
  692. Return Value:
  693. If the function succeeds, the return value is a pointer to the rolled-back
  694. device information set structure.
  695. If the function fails, the return value is NULL.
  696. --*/
  697. {
  698. PDEVICE_INFO_SET pDeviceInfoSet;
  699. PDEVINFO_ELEM DevInfoElem, NextDevInfoElem;
  700. DWORD i, InterfaceDeviceCount;
  701. PINTERFACE_DEVICE_NODE InterfaceDeviceNode, NextInterfaceDeviceNode;
  702. //
  703. // Retrieve a pointer to the hDevInfo set's internal representation (we
  704. // don't need to acquire the lock, because we did that when we cloned the
  705. // originally cloned the structure).
  706. //
  707. // NOTE: If the method for accessing an HDEVINFO set's internal
  708. // representation ever changes (i.e., the AccessDeviceInfoSet routine),
  709. // then this code will need to be modified accordingly.
  710. //
  711. pDeviceInfoSet = (PDEVICE_INFO_SET)hDevInfo;
  712. //
  713. // Make sure no additional locks have been acquired against the cloned
  714. // DEVICE_INFO_SET.
  715. //
  716. MYASSERT(pDeviceInfoSet->LockRefCount == ClonedDeviceInfoSet->LockRefCount);
  717. //
  718. // Do some validation to see whether it looks like only new device
  719. // information elements were added onto the end of our existing list (i.e.,
  720. // it's invalid to add new elements within the existing list, or to remove
  721. // elements from the existing list).
  722. //
  723. #if ASSERTS_ON
  724. if(pDeviceInfoSet->DeviceInfoHead) {
  725. DWORD DevInfoElemCount = 1;
  726. MYASSERT(pDeviceInfoSet->DeviceInfoHead == ClonedDeviceInfoSet->DeviceInfoHead);
  727. for(DevInfoElem = ClonedDeviceInfoSet->DeviceInfoHead;
  728. DevInfoElem->Next;
  729. DevInfoElem = DevInfoElem->Next, DevInfoElemCount++) {
  730. if(DevInfoElem == pDeviceInfoSet->DeviceInfoTail) {
  731. break;
  732. }
  733. }
  734. //
  735. // Did we find the original tail?
  736. //
  737. MYASSERT(DevInfoElem == pDeviceInfoSet->DeviceInfoTail);
  738. //
  739. // And did we traverse the same number of nodes in getting there that
  740. // was in the original list?
  741. //
  742. MYASSERT(DevInfoElemCount == pDeviceInfoSet->DeviceInfoCount);
  743. }
  744. #endif
  745. //
  746. // Destroy any newly-added members of the device information element list.
  747. //
  748. for(DevInfoElem = (pDeviceInfoSet->DeviceInfoTail ? pDeviceInfoSet->DeviceInfoTail->Next : pDeviceInfoSet->DeviceInfoHead);
  749. DevInfoElem;
  750. DevInfoElem = NextDevInfoElem) {
  751. NextDevInfoElem = DevInfoElem->Next;
  752. MYASSERT(!DevInfoElem->ClassDriverCount);
  753. MYASSERT(!DevInfoElem->CompatDriverCount);
  754. //
  755. // Free any interface device lists that may be associated with this
  756. // devinfo element.
  757. //
  758. if(DevInfoElem->InterfaceClassList) {
  759. for(i = 0; i < DevInfoElem->InterfaceClassListSize; i++) {
  760. for(InterfaceDeviceNode = DevInfoElem->InterfaceClassList[i].InterfaceDeviceNode;
  761. InterfaceDeviceNode;
  762. InterfaceDeviceNode = NextInterfaceDeviceNode) {
  763. NextInterfaceDeviceNode = InterfaceDeviceNode->Next;
  764. MyFree(InterfaceDeviceNode);
  765. }
  766. }
  767. MyFree(DevInfoElem->InterfaceClassList);
  768. }
  769. MyFree(DevInfoElem);
  770. }
  771. if(pDeviceInfoSet->DeviceInfoTail) {
  772. pDeviceInfoSet->DeviceInfoTail->Next = NULL;
  773. }
  774. //
  775. // At this point, we've trimmed our device information element list back to
  776. // what it was prior to the cloning of the device information set. However,
  777. // we may have added new device interface nodes onto the interface class
  778. // lists of existing devinfo elements. Go and truncate any such nodes.
  779. //
  780. for(DevInfoElem = pDeviceInfoSet->DeviceInfoHead;
  781. DevInfoElem;
  782. DevInfoElem = DevInfoElem->Next) {
  783. if(DevInfoElem->InterfaceClassList) {
  784. for(i = 0; i < DevInfoElem->InterfaceClassListSize; i++) {
  785. if(DevInfoElem->InterfaceClassList[i].InterfaceDeviceTruncateNode) {
  786. //
  787. // One or more device interface nodes were added to this
  788. // list. Find the tail of the list as it existed prior to
  789. // cloning, and truncate from there.
  790. //
  791. InterfaceDeviceNode = NULL;
  792. InterfaceDeviceCount = 0;
  793. for(NextInterfaceDeviceNode = DevInfoElem->InterfaceClassList[i].InterfaceDeviceNode;
  794. NextInterfaceDeviceNode;
  795. InterfaceDeviceNode = NextInterfaceDeviceNode, NextInterfaceDeviceNode = NextInterfaceDeviceNode->Next) {
  796. if(NextInterfaceDeviceNode == DevInfoElem->InterfaceClassList[i].InterfaceDeviceTruncateNode) {
  797. break;
  798. }
  799. //
  800. // We haven't encountered the truncate point yet--
  801. // increment the count of device interface nodes we've
  802. // traversed so far.
  803. //
  804. InterfaceDeviceCount++;
  805. }
  806. //
  807. // We'd better have found the node to truncate in our list!
  808. //
  809. MYASSERT(NextInterfaceDeviceNode);
  810. //
  811. // Truncate the list, and destroy all newly-added device
  812. // interface nodes.
  813. //
  814. if(InterfaceDeviceNode) {
  815. InterfaceDeviceNode->Next = NULL;
  816. } else {
  817. DevInfoElem->InterfaceClassList[i].InterfaceDeviceNode = NULL;
  818. }
  819. DevInfoElem->InterfaceClassList[i].InterfaceDeviceCount = InterfaceDeviceCount;
  820. for(InterfaceDeviceNode = NextInterfaceDeviceNode;
  821. InterfaceDeviceNode;
  822. InterfaceDeviceNode = NextInterfaceDeviceNode) {
  823. NextInterfaceDeviceNode = InterfaceDeviceNode->Next;
  824. MyFree(InterfaceDeviceNode);
  825. }
  826. //
  827. // Reset the truncate node pointer.
  828. //
  829. DevInfoElem->InterfaceClassList[i].InterfaceDeviceTruncateNode = NULL;
  830. }
  831. }
  832. }
  833. }
  834. //
  835. // OK, our device information element list and device interface node lists
  836. // are exactly as they were before the cloning took place. However, it's
  837. // possible that we allocated (or reallocated) a new buffer for our
  838. // GUID table, so we need to update that GUID table pointer and size in our
  839. // original device information set structure.
  840. //
  841. pDeviceInfoSet->GuidTable = ClonedDeviceInfoSet->GuidTable;
  842. pDeviceInfoSet->GuidTableSize = ClonedDeviceInfoSet->GuidTableSize;
  843. //
  844. // The device information set has been successfully rolled back. Free the
  845. // memory associated with the clone.
  846. //
  847. pStringTableDestroy(ClonedDeviceInfoSet->StringTable);
  848. MyFree(ClonedDeviceInfoSet);
  849. //
  850. // Return the original (rolled-back) device information set structure to
  851. // the caller.
  852. //
  853. return pDeviceInfoSet;
  854. }
  855. PDEVICE_INFO_SET
  856. CommitDeviceInfoSet(
  857. IN HDEVINFO hDevInfo,
  858. IN PDEVICE_INFO_SET ClonedDeviceInfoSet
  859. )
  860. /*++
  861. Routine Description:
  862. This routine commits the changes that have been made to a cloned device
  863. information set. The clone was generated via a prior call to
  864. CloneDeviceInfoSet.
  865. Arguments:
  866. hDevInfo - Supplies the handle of the device information set whose changes
  867. are to be committed.
  868. ClonedDeviceInfoSet - Supplies the address of the internal structure
  869. representing the hDevInfo set's cloned (and potentially, modified)
  870. information. Upon successful return, this structure will be freed.
  871. Return Value:
  872. If the function succeeds, the return value is a pointer to the committed
  873. device information set structure.
  874. If the function fails, the return value is NULL.
  875. --*/
  876. {
  877. PDEVICE_INFO_SET pDeviceInfoSet;
  878. PDEVINFO_ELEM DevInfoElem;
  879. DWORD i;
  880. //
  881. // Retrieve a pointer to the hDevInfo set's internal representation (we
  882. // don't need to acquire the lock, because we did that when we cloned the
  883. // originally cloned the structure).
  884. //
  885. // NOTE: If the method for accessing an HDEVINFO set's internal
  886. // representation ever changes (i.e., the AccessDeviceInfoSet routine),
  887. // then this code will need to be modified accordingly.
  888. //
  889. pDeviceInfoSet = (PDEVICE_INFO_SET)hDevInfo;
  890. //
  891. // Make sure no additional locks have been acquired against the cloned
  892. // DEVICE_INFO_SET.
  893. //
  894. MYASSERT(pDeviceInfoSet->LockRefCount == ClonedDeviceInfoSet->LockRefCount);
  895. //
  896. // Free the old string table.
  897. //
  898. pStringTableDestroy(pDeviceInfoSet->StringTable);
  899. //
  900. // Now copy the cloned device information set structure into the 'real' one.
  901. //
  902. CopyMemory(pDeviceInfoSet, ClonedDeviceInfoSet, sizeof(DEVICE_INFO_SET));
  903. //
  904. // Now we have to go through each device information element's interface
  905. // class list and reset the InterfaceDeviceTruncateNode fields to indicate
  906. // that all the new device interface nodes that were added have been
  907. // committed.
  908. //
  909. for(DevInfoElem = pDeviceInfoSet->DeviceInfoHead;
  910. DevInfoElem;
  911. DevInfoElem = DevInfoElem->Next) {
  912. for(i = 0; i < DevInfoElem->InterfaceClassListSize; i++) {
  913. DevInfoElem->InterfaceClassList[i].InterfaceDeviceTruncateNode = NULL;
  914. }
  915. }
  916. //
  917. // Free the cloned device information set structure.
  918. //
  919. MyFree(ClonedDeviceInfoSet);
  920. //
  921. // We've successfully committed the changes into the original device
  922. // information set structure--return that structure.
  923. //
  924. return pDeviceInfoSet;
  925. }
  926. PDEVINFO_ELEM
  927. FindDevInfoByDevInst(
  928. IN PDEVICE_INFO_SET DeviceInfoSet,
  929. IN DEVINST DevInst,
  930. OUT PDEVINFO_ELEM *PrevDevInfoElem OPTIONAL
  931. )
  932. /*++
  933. Routine Description:
  934. This routine searches through all (registered) elements of a
  935. device information set, looking for one that corresponds to the
  936. specified device instance handle. If a match is found, a pointer
  937. to the device information element is returned.
  938. Arguments:
  939. DeviceInfoSet - Specifies the set to be searched.
  940. DevInst - Specifies the device instance handle to search for.
  941. PrevDevInfoElem - Optionaly, supplies the address of the variable that
  942. receives a pointer to the device information element immediately
  943. preceding the matching element. If the element was found at the
  944. front of the list, then this variable will be set to NULL.
  945. Return Value:
  946. If a device information element is found, the return value is a
  947. pointer to that element, otherwise, the return value is NULL.
  948. --*/
  949. {
  950. PDEVINFO_ELEM cur, prev;
  951. for(cur = DeviceInfoSet->DeviceInfoHead, prev = NULL;
  952. cur;
  953. prev = cur, cur = cur->Next)
  954. {
  955. if((cur->DiElemFlags & DIE_IS_REGISTERED) && (cur->DevInst == DevInst)) {
  956. if(PrevDevInfoElem) {
  957. *PrevDevInfoElem = prev;
  958. }
  959. return cur;
  960. }
  961. }
  962. return NULL;
  963. }
  964. BOOL
  965. DevInfoDataFromDeviceInfoElement(
  966. IN PDEVICE_INFO_SET DeviceInfoSet,
  967. IN PDEVINFO_ELEM DevInfoElem,
  968. OUT PSP_DEVINFO_DATA DeviceInfoData
  969. )
  970. /*++
  971. Routine Description:
  972. This routine fills in a SP_DEVINFO_DATA structure based on the
  973. information in the supplied DEVINFO_ELEM structure.
  974. Note: The supplied DeviceInfoData structure must have its cbSize
  975. field filled in correctly, or the call will fail.
  976. Arguments:
  977. DeviceInfoSet - Supplies a pointer to the device information set
  978. containing the specified element.
  979. DevInfoElem - Supplies a pointer to the DEVINFO_ELEM structure
  980. containing information to be used in filling in the
  981. SP_DEVINFO_DATA buffer.
  982. DeviceInfoData - Supplies a pointer to the buffer that will
  983. receive the filled-in SP_DEVINFO_DATA structure
  984. Return Value:
  985. If the function succeeds, the return value is TRUE, otherwise, it
  986. is FALSE.
  987. --*/
  988. {
  989. if(DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) {
  990. return FALSE;
  991. }
  992. ZeroMemory(DeviceInfoData, sizeof(SP_DEVINFO_DATA));
  993. DeviceInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
  994. CopyMemory(&(DeviceInfoData->ClassGuid),
  995. &(DevInfoElem->ClassGuid),
  996. sizeof(GUID)
  997. );
  998. DeviceInfoData->DevInst = DevInfoElem->DevInst;
  999. //
  1000. // The 'Reserved' field actually contains a pointer to the
  1001. // corresponding device information element.
  1002. //
  1003. DeviceInfoData->Reserved = (ULONG_PTR)DevInfoElem;
  1004. return TRUE;
  1005. }
  1006. PDEVINFO_ELEM
  1007. FindAssociatedDevInfoElem(
  1008. IN PDEVICE_INFO_SET DeviceInfoSet,
  1009. IN PSP_DEVINFO_DATA DeviceInfoData,
  1010. OUT PDEVINFO_ELEM *PreviousElement OPTIONAL
  1011. )
  1012. /*++
  1013. Routine Description:
  1014. This routine returns the devinfo element for the specified
  1015. SP_DEVINFO_DATA, or NULL if no devinfo element exists.
  1016. Arguments:
  1017. DeviceInfoSet - Specifies the set to be searched.
  1018. DeviceInfoData - Supplies a pointer to a device information data
  1019. buffer specifying the device information element to retrieve.
  1020. PreviousElement - Optionally, supplies the address of a
  1021. DEVINFO_ELEM pointer that receives the element that precedes
  1022. the specified element in the linked list. If the returned
  1023. element is located at the front of the list, then this value
  1024. will be set to NULL.
  1025. Return Value:
  1026. If a device information element is found, the return value is a
  1027. pointer to that element, otherwise, the return value is NULL.
  1028. --*/
  1029. {
  1030. PDEVINFO_ELEM DevInfoElem, CurElem, PrevElem;
  1031. PDEVINFO_ELEM ActualDevInfoElem = NULL;
  1032. try {
  1033. if((DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) ||
  1034. !(DevInfoElem = (PDEVINFO_ELEM)DeviceInfoData->Reserved)) {
  1035. leave;
  1036. }
  1037. if(PreviousElement) {
  1038. //
  1039. // The caller requested that the preceding element be returned
  1040. // (probably because the element is about to be deleted). Since
  1041. // this is a singly-linked list, we'll search through the list
  1042. // until we find the desired element.
  1043. //
  1044. for(CurElem = DeviceInfoSet->DeviceInfoHead, PrevElem = NULL;
  1045. CurElem;
  1046. PrevElem = CurElem, CurElem = CurElem->Next) {
  1047. if(CurElem == DevInfoElem) {
  1048. //
  1049. // We found the element in our set.
  1050. //
  1051. if(PreviousElement) {
  1052. *PreviousElement = PrevElem;
  1053. }
  1054. ActualDevInfoElem = CurElem;
  1055. leave;
  1056. }
  1057. }
  1058. } else {
  1059. //
  1060. // The caller doesn't care what the preceding element is, so we
  1061. // can go right to the element, and validate it by ensuring that
  1062. // the ContainingDeviceInfoSet field at the location pointed to
  1063. // by DevInfoElem matches the devinfo set where this guy is supposed
  1064. // to exist.
  1065. //
  1066. if(DevInfoElem->ContainingDeviceInfoSet == DeviceInfoSet) {
  1067. ActualDevInfoElem = DevInfoElem;
  1068. leave;
  1069. }
  1070. }
  1071. } except (EXCEPTION_EXECUTE_HANDLER) {
  1072. //
  1073. // invalid memory
  1074. //
  1075. ActualDevInfoElem = NULL;
  1076. }
  1077. return ActualDevInfoElem;
  1078. }
  1079. BOOL
  1080. DrvInfoDataFromDriverNode(
  1081. IN PDEVICE_INFO_SET DeviceInfoSet,
  1082. IN PDRIVER_NODE DriverNode,
  1083. IN DWORD DriverType,
  1084. OUT PSP_DRVINFO_DATA DriverInfoData
  1085. )
  1086. /*++
  1087. Routine Description:
  1088. This routine fills in a SP_DRVINFO_DATA structure based on the
  1089. information in the supplied DRIVER_NODE structure.
  1090. Note: The supplied DriverInfoData structure must have its cbSize
  1091. field filled in correctly, or the call will fail.
  1092. Arguments:
  1093. DeviceInfoSet - Supplies a pointer to the device information set
  1094. in which the driver node is located.
  1095. DriverNode - Supplies a pointer to the DRIVER_NODE structure
  1096. containing information to be used in filling in the
  1097. SP_DRVNFO_DATA buffer.
  1098. DriverType - Specifies what type of driver this is. This value
  1099. may be either SPDIT_CLASSDRIVER or SPDIT_COMPATDRIVER.
  1100. DriverInfoData - Supplies a pointer to the buffer that will
  1101. receive the filled-in SP_DRVINFO_DATA structure
  1102. Return Value:
  1103. If the function succeeds, the return value is TRUE, otherwise, it
  1104. is FALSE.
  1105. --*/
  1106. {
  1107. PTSTR StringPtr;
  1108. DWORD DriverInfoDataSize;
  1109. if((DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA)) &&
  1110. (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1))) {
  1111. return FALSE;
  1112. }
  1113. DriverInfoDataSize = DriverInfoData->cbSize;
  1114. ZeroMemory(DriverInfoData, DriverInfoDataSize);
  1115. DriverInfoData->cbSize = DriverInfoDataSize;
  1116. DriverInfoData->DriverType = DriverType;
  1117. MYASSERT(DriverNode->DevDescriptionDisplayName != -1);
  1118. StringPtr = pStringTableStringFromId(DeviceInfoSet->StringTable,
  1119. DriverNode->DevDescriptionDisplayName
  1120. );
  1121. lstrcpy(DriverInfoData->Description,
  1122. StringPtr
  1123. );
  1124. MYASSERT(DriverNode->MfgDisplayName != -1);
  1125. StringPtr = pStringTableStringFromId(DeviceInfoSet->StringTable,
  1126. DriverNode->MfgDisplayName
  1127. );
  1128. lstrcpy(DriverInfoData->MfgName,
  1129. StringPtr
  1130. );
  1131. if(DriverNode->ProviderDisplayName != -1) {
  1132. StringPtr = pStringTableStringFromId(DeviceInfoSet->StringTable,
  1133. DriverNode->ProviderDisplayName
  1134. );
  1135. lstrcpy(DriverInfoData->ProviderName,
  1136. StringPtr
  1137. );
  1138. }
  1139. //
  1140. // The 'Reserved' field actually contains a pointer to the
  1141. // corresponding driver node.
  1142. //
  1143. DriverInfoData->Reserved = (ULONG_PTR)DriverNode;
  1144. //
  1145. //new NT 5 fields
  1146. //
  1147. if (DriverInfoDataSize == sizeof(SP_DRVINFO_DATA)) {
  1148. DriverInfoData->DriverDate = DriverNode->DriverDate;
  1149. DriverInfoData->DriverVersion = DriverNode->DriverVersion;
  1150. }
  1151. return TRUE;
  1152. }
  1153. PDRIVER_NODE
  1154. FindAssociatedDriverNode(
  1155. IN PDRIVER_NODE DriverListHead,
  1156. IN PSP_DRVINFO_DATA DriverInfoData,
  1157. OUT PDRIVER_NODE *PreviousNode OPTIONAL
  1158. )
  1159. /*++
  1160. Routine Description:
  1161. This routine searches through all driver nodes in a driver node
  1162. list, looking for one that corresponds to the specified driver
  1163. information structure. If a match is found, a pointer to the
  1164. driver node is returned.
  1165. Arguments:
  1166. DriverListHead - Supplies a pointer to the head of linked list
  1167. of driver nodes to be searched.
  1168. DriverInfoData - Supplies a pointer to a driver information buffer
  1169. specifying the driver node to retrieve.
  1170. PreviousNode - Optionally, supplies the address of a DRIVER_NODE
  1171. pointer that receives the node that precedes the specified
  1172. node in the linked list. If the returned node is located at
  1173. the front of the list, then this value will be set to NULL.
  1174. Return Value:
  1175. If a driver node is found, the return value is a pointer to that
  1176. node, otherwise, the return value is NULL.
  1177. --*/
  1178. {
  1179. PDRIVER_NODE DriverNode, CurNode, PrevNode;
  1180. if(((DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA)) &&
  1181. (DriverInfoData->cbSize != sizeof(SP_DRVINFO_DATA_V1))) ||
  1182. !(DriverNode = (PDRIVER_NODE)DriverInfoData->Reserved)) {
  1183. return NULL;
  1184. }
  1185. for(CurNode = DriverListHead, PrevNode = NULL;
  1186. CurNode;
  1187. PrevNode = CurNode, CurNode = CurNode->Next) {
  1188. if(CurNode == DriverNode) {
  1189. //
  1190. // We found the driver node in our list.
  1191. //
  1192. if(PreviousNode) {
  1193. *PreviousNode = PrevNode;
  1194. }
  1195. return CurNode;
  1196. }
  1197. }
  1198. return NULL;
  1199. }
  1200. PDRIVER_NODE
  1201. SearchForDriverNode(
  1202. IN PVOID StringTable,
  1203. IN PDRIVER_NODE DriverListHead,
  1204. IN PSP_DRVINFO_DATA DriverInfoData,
  1205. OUT PDRIVER_NODE *PreviousNode OPTIONAL
  1206. )
  1207. /*++
  1208. Routine Description:
  1209. This routine searches through all driver nodes in a driver node
  1210. list, looking for one that matches the fields in the specified
  1211. driver information structure (the 'Reserved' field is ignored).
  1212. If a match is found, a pointer to the driver node is returned.
  1213. Arguments:
  1214. StringTable - Supplies the string table that should be used in
  1215. retrieving string IDs for driver look-up.
  1216. DriverListHead - Supplies a pointer to the head of linked list
  1217. of driver nodes to be searched.
  1218. DriverInfoData - Supplies a pointer to a driver information buffer
  1219. specifying the driver parameters we're looking for.
  1220. PreviousNode - Optionally, supplies the address of a DRIVER_NODE
  1221. pointer that receives the node that precedes the specified
  1222. node in the linked list. If the returned node is located at
  1223. the front of the list, then this value will be set to NULL.
  1224. Return Value:
  1225. If a driver node is found, the return value is a pointer to that
  1226. node, otherwise, the return value is NULL.
  1227. --*/
  1228. {
  1229. PDRIVER_NODE CurNode, PrevNode;
  1230. LONG DevDescription, MfgName, ProviderName;
  1231. TCHAR TempString[LINE_LEN];
  1232. DWORD TempStringLength;
  1233. BOOL Match;
  1234. MYASSERT((DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA)) ||
  1235. (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA_V1)));
  1236. //
  1237. // Retrieve the string IDs for the 3 driver parameters we'll be
  1238. // matching against.
  1239. //
  1240. lstrcpyn(TempString, DriverInfoData->Description, SIZECHARS(TempString));
  1241. if((DevDescription = pStringTableLookUpString(
  1242. StringTable,
  1243. TempString,
  1244. &TempStringLength,
  1245. NULL,
  1246. NULL,
  1247. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  1248. NULL,0)) == -1) {
  1249. return NULL;
  1250. }
  1251. lstrcpyn(TempString, DriverInfoData->MfgName, SIZECHARS(TempString));
  1252. if((MfgName = pStringTableLookUpString(
  1253. StringTable,
  1254. TempString,
  1255. &TempStringLength,
  1256. NULL,
  1257. NULL,
  1258. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  1259. NULL,0)) == -1) {
  1260. return NULL;
  1261. }
  1262. //
  1263. // ProviderName may be empty...
  1264. //
  1265. if(*(DriverInfoData->ProviderName)) {
  1266. lstrcpyn(TempString, DriverInfoData->ProviderName, SIZECHARS(TempString));
  1267. if((ProviderName = pStringTableLookUpString(
  1268. StringTable,
  1269. TempString,
  1270. &TempStringLength,
  1271. NULL,
  1272. NULL,
  1273. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  1274. NULL,0)) == -1) {
  1275. return NULL;
  1276. }
  1277. } else {
  1278. ProviderName = -1;
  1279. }
  1280. for(CurNode = DriverListHead, PrevNode = NULL;
  1281. CurNode;
  1282. PrevNode = CurNode, CurNode = CurNode->Next)
  1283. {
  1284. //
  1285. // Check first on DevDescription (least likely to match), then on MfgName, and finally
  1286. // on ProviderName. On NT 5 and later we will also check the DriverDate and DriverVersion.
  1287. //
  1288. if(CurNode->DevDescription == DevDescription) {
  1289. if(CurNode->MfgName == MfgName) {
  1290. if(CurNode->ProviderName == ProviderName) {
  1291. //
  1292. //On NT 5 and later, also compare the DriverDate and DriverVersion
  1293. //
  1294. if (DriverInfoData->cbSize == sizeof(SP_DRVINFO_DATA)) {
  1295. //
  1296. //Assume that we have a match
  1297. //
  1298. Match = TRUE;
  1299. //
  1300. //If the DriverDate passed in is not 0 then make sure it matches
  1301. //
  1302. if (DriverInfoData->DriverDate.dwLowDateTime != 0 ||
  1303. DriverInfoData->DriverDate.dwHighDateTime != 0) {
  1304. if ((CurNode->DriverDate.dwLowDateTime != DriverInfoData->DriverDate.dwLowDateTime) ||
  1305. (CurNode->DriverDate.dwHighDateTime != DriverInfoData->DriverDate.dwHighDateTime)) {
  1306. Match = FALSE;
  1307. }
  1308. }
  1309. //
  1310. //If the DriverVersion passed in is not 0 then make sure it matches
  1311. //
  1312. else if (DriverInfoData->DriverVersion != 0) {
  1313. if (CurNode->DriverVersion != DriverInfoData->DriverVersion) {
  1314. Match = FALSE;
  1315. }
  1316. }
  1317. if (Match) {
  1318. //
  1319. // We found the driver node in our list.
  1320. //
  1321. if(PreviousNode) {
  1322. *PreviousNode = PrevNode;
  1323. }
  1324. return CurNode;
  1325. }
  1326. } else {
  1327. //
  1328. // We found the driver node in our list.
  1329. //
  1330. if(PreviousNode) {
  1331. *PreviousNode = PrevNode;
  1332. }
  1333. return CurNode;
  1334. }
  1335. }
  1336. }
  1337. }
  1338. }
  1339. return NULL;
  1340. }
  1341. DWORD
  1342. DrvInfoDetailsFromDriverNode(
  1343. IN PDEVICE_INFO_SET DeviceInfoSet,
  1344. IN PDRIVER_NODE DriverNode,
  1345. OUT PSP_DRVINFO_DETAIL_DATA DriverInfoDetailData, OPTIONAL
  1346. IN DWORD BufferSize,
  1347. OUT PDWORD RequiredSize OPTIONAL
  1348. )
  1349. /*++
  1350. Routine Description:
  1351. This routine fills in a SP_DRVINFO_DETAIL_DATA structure based on the
  1352. information in the supplied DRIVER_NODE structure.
  1353. If the buffer is supplied, and is valid, this routine is guaranteed to
  1354. fill in all statically-sized fields, and as many IDs as will fit in the
  1355. variable-length multi-sz buffer.
  1356. Note: If supplied, the DriverInfoDetailData structure must have its
  1357. cbSize field filled in correctly, or the call will fail. Here correctly
  1358. means sizeof(SP_DRVINFO_DETAIL_DATA), which we use as a signature.
  1359. This is entirely separate from BufferSize. See below.
  1360. Arguments:
  1361. DeviceInfoSet - Supplies a pointer to the device information set
  1362. in which the driver node is located.
  1363. DriverNode - Supplies a pointer to the DRIVER_NODE structure
  1364. containing information to be used in filling in the
  1365. SP_DRVNFO_DETAIL_DATA buffer.
  1366. DriverInfoDetailData - Optionally, supplies a pointer to the buffer
  1367. that will receive the filled-in SP_DRVINFO_DETAIL_DATA structure.
  1368. If this buffer is not supplied, then the caller is only interested
  1369. in what the RequiredSize for the buffer is.
  1370. BufferSize - Supplies size of the DriverInfoDetailData buffer, in
  1371. bytes. If DriverInfoDetailData is not specified, then this
  1372. value must be zero. This value must be at least the size
  1373. of the fixed part of the structure (ie,
  1374. offsetof(SP_DRVINFO_DETAIL_DATA,HardwareID)) plus sizeof(TCHAR),
  1375. which gives us enough room to store the fixed part plus
  1376. a terminating nul to guarantee we return at least a valid
  1377. empty multi_sz.
  1378. RequiredSize - Optionally, supplies the address of a variable that
  1379. receives the number of bytes required to store the data. Note that
  1380. depending on structure alignment and the data itself, this may
  1381. actually be *smaller* than sizeof(SP_DRVINFO_DETAIL_DATA).
  1382. Return Value:
  1383. If the function succeeds, the return value is NO_ERROR.
  1384. If the function fails, an ERROR_* code is returned.
  1385. --*/
  1386. {
  1387. PTSTR StringPtr, BufferPtr;
  1388. DWORD IdListLen, CompatIdListLen, StringLen, TotalLen, i;
  1389. DWORD Err = ERROR_INSUFFICIENT_BUFFER;
  1390. #define FIXEDPARTLEN offsetof(SP_DRVINFO_DETAIL_DATA,HardwareID)
  1391. if(DriverInfoDetailData) {
  1392. //
  1393. // Check validity of the DriverInfoDetailData buffer on the way in,
  1394. // and make sure we have enough room for the fixed part
  1395. // of the structure plus the extra nul that will terminate the
  1396. // multi_sz.
  1397. //
  1398. if((DriverInfoDetailData->cbSize != sizeof(SP_DRVINFO_DETAIL_DATA))
  1399. || (BufferSize < (FIXEDPARTLEN+sizeof(TCHAR)))) {
  1400. return ERROR_INVALID_USER_BUFFER;
  1401. }
  1402. //
  1403. // The buffer is large enough to contain at least the fixed-length part
  1404. // of the structure.
  1405. //
  1406. Err = NO_ERROR;
  1407. } else if(BufferSize) {
  1408. return ERROR_INVALID_USER_BUFFER;
  1409. }
  1410. if(DriverInfoDetailData) {
  1411. ZeroMemory(DriverInfoDetailData,FIXEDPARTLEN);
  1412. DriverInfoDetailData->cbSize = FIXEDPARTLEN + sizeof(TCHAR);
  1413. DriverInfoDetailData->InfDate = DriverNode->InfDate;
  1414. MYASSERT(DriverNode->InfSectionName != -1);
  1415. StringPtr = pStringTableStringFromId(DeviceInfoSet->StringTable,
  1416. DriverNode->InfSectionName
  1417. );
  1418. lstrcpyn(DriverInfoDetailData->SectionName, StringPtr,sizeof(DriverInfoDetailData->SectionName)/sizeof(TCHAR));
  1419. MYASSERT(DriverNode->InfFileName != -1);
  1420. StringPtr = pStringTableStringFromId(DeviceInfoSet->StringTable,
  1421. DriverNode->InfFileName
  1422. );
  1423. lstrcpyn(DriverInfoDetailData->InfFileName, StringPtr,sizeof(DriverInfoDetailData->InfFileName)/sizeof(TCHAR));
  1424. MYASSERT(DriverNode->DrvDescription != -1);
  1425. StringPtr = pStringTableStringFromId(DeviceInfoSet->StringTable,
  1426. DriverNode->DrvDescription
  1427. );
  1428. lstrcpyn(DriverInfoDetailData->DrvDescription, StringPtr,sizeof(DriverInfoDetailData->DrvDescription)/sizeof(TCHAR));
  1429. //
  1430. // Initialize the multi_sz to be empty.
  1431. //
  1432. DriverInfoDetailData->HardwareID[0] = 0;
  1433. //
  1434. // The 'Reserved' field actually contains a pointer to the
  1435. // corresponding driver node.
  1436. //
  1437. DriverInfoDetailData->Reserved = (ULONG_PTR)DriverNode;
  1438. }
  1439. //
  1440. // Now, build the multi-sz buffer containing the hardware and compatible IDs.
  1441. //
  1442. if(DriverNode->HardwareId == -1) {
  1443. //
  1444. // If there's no HardwareId, then we know there are no compatible IDs, so
  1445. // we can return right now.
  1446. //
  1447. if(RequiredSize) {
  1448. *RequiredSize = FIXEDPARTLEN + sizeof(TCHAR);
  1449. }
  1450. return Err;
  1451. }
  1452. if(DriverInfoDetailData) {
  1453. BufferPtr = DriverInfoDetailData->HardwareID;
  1454. IdListLen = (BufferSize - FIXEDPARTLEN) / sizeof(TCHAR);
  1455. } else {
  1456. IdListLen = 0;
  1457. }
  1458. //
  1459. // Retrieve the HardwareId.
  1460. //
  1461. StringPtr = pStringTableStringFromId(DeviceInfoSet->StringTable,
  1462. DriverNode->HardwareId
  1463. );
  1464. TotalLen = StringLen = lstrlen(StringPtr) + 1; // include nul terminator
  1465. if(StringLen < IdListLen) {
  1466. MYASSERT(Err == NO_ERROR);
  1467. CopyMemory(BufferPtr,
  1468. StringPtr,
  1469. StringLen * sizeof(TCHAR)
  1470. );
  1471. BufferPtr += StringLen;
  1472. IdListLen -= StringLen;
  1473. DriverInfoDetailData->CompatIDsOffset = StringLen;
  1474. } else {
  1475. if(RequiredSize) {
  1476. //
  1477. // Since the caller requested the required size, we can't just return
  1478. // here. Set the error, so we'll know not to bother trying to fill
  1479. // the buffer.
  1480. //
  1481. Err = ERROR_INSUFFICIENT_BUFFER;
  1482. } else {
  1483. return ERROR_INSUFFICIENT_BUFFER;
  1484. }
  1485. }
  1486. //
  1487. // Remember the size of the buffer left over for CompatibleIDs.
  1488. //
  1489. CompatIdListLen = IdListLen;
  1490. //
  1491. // Now retrieve the CompatibleIDs.
  1492. //
  1493. for(i = 0; i < DriverNode->NumCompatIds; i++) {
  1494. MYASSERT(DriverNode->CompatIdList[i] != -1);
  1495. StringPtr = pStringTableStringFromId(DeviceInfoSet->StringTable,
  1496. DriverNode->CompatIdList[i]
  1497. );
  1498. StringLen = lstrlen(StringPtr) + 1;
  1499. if(Err == NO_ERROR) {
  1500. if(StringLen < IdListLen) {
  1501. CopyMemory(BufferPtr,
  1502. StringPtr,
  1503. StringLen * sizeof(TCHAR)
  1504. );
  1505. BufferPtr += StringLen;
  1506. IdListLen -= StringLen;
  1507. } else {
  1508. Err = ERROR_INSUFFICIENT_BUFFER;
  1509. if(!RequiredSize) {
  1510. //
  1511. // We've run out of buffer, and the caller doesn't care what
  1512. // the total required size is, so bail now.
  1513. //
  1514. break;
  1515. }
  1516. }
  1517. }
  1518. TotalLen += StringLen;
  1519. }
  1520. if(DriverInfoDetailData) {
  1521. //
  1522. // Append the additional terminating nul. Note that we've been saving the
  1523. // last character position in the buffer all along, so we're guaranteed to
  1524. // be inside the buffer.
  1525. //
  1526. MYASSERT(BufferPtr < (PTSTR)((PBYTE)DriverInfoDetailData + BufferSize));
  1527. *BufferPtr = 0;
  1528. //
  1529. // Store the length of the CompatibleIDs list. Note that this is the length
  1530. // of the list actually returned, which may be less than the length of the
  1531. // entire list (if the caller-supplied buffer wasn't large enough).
  1532. //
  1533. if(CompatIdListLen -= IdListLen) {
  1534. //
  1535. // If this list is non-empty, then add a character for the extra nul
  1536. // terminating the multi-sz list.
  1537. //
  1538. CompatIdListLen++;
  1539. }
  1540. DriverInfoDetailData->CompatIDsLength = CompatIdListLen;
  1541. }
  1542. if(RequiredSize) {
  1543. *RequiredSize = FIXEDPARTLEN + ((TotalLen + 1) * sizeof(TCHAR));
  1544. }
  1545. return Err;
  1546. }
  1547. PDRIVER_LIST_OBJECT
  1548. GetAssociatedDriverListObject(
  1549. IN PDRIVER_LIST_OBJECT ObjectListHead,
  1550. IN PDRIVER_NODE DriverListHead,
  1551. OUT PDRIVER_LIST_OBJECT *PrevDriverListObject OPTIONAL
  1552. )
  1553. /*++
  1554. Routine Description:
  1555. This routine searches through a driver list object list, and returns a
  1556. pointer to the driver list object containing the list specified by
  1557. DrvListHead. It also optionally returns the preceding object in the list
  1558. (used when extracting the driver list object from the linked list).
  1559. Arguments:
  1560. ObjectListHead - Specifies the linked list of driver list objects to be
  1561. searched.
  1562. DriverListHead - Specifies the driver list to be searched for.
  1563. PrevDriverListObject - Optionaly, supplies the address of the variable that
  1564. receives a pointer to the driver list object immediately preceding the
  1565. matching object. If the object was found at the front of the list, then
  1566. this variable will be set to NULL.
  1567. Return Value:
  1568. If the matching driver list object is found, the return value is a pointer
  1569. to that element, otherwise, the return value is NULL.
  1570. --*/
  1571. {
  1572. PDRIVER_LIST_OBJECT prev = NULL;
  1573. while(ObjectListHead) {
  1574. if(ObjectListHead->DriverListHead == DriverListHead) {
  1575. if(PrevDriverListObject) {
  1576. *PrevDriverListObject = prev;
  1577. }
  1578. return ObjectListHead;
  1579. }
  1580. prev = ObjectListHead;
  1581. ObjectListHead = ObjectListHead->Next;
  1582. }
  1583. return NULL;
  1584. }
  1585. VOID
  1586. DereferenceClassDriverList(
  1587. IN PDEVICE_INFO_SET DeviceInfoSet,
  1588. IN PDRIVER_NODE DriverListHead OPTIONAL
  1589. )
  1590. /*++
  1591. Routine Description:
  1592. This routine dereferences the class driver list object associated with the
  1593. supplied DriverListHead. If the refcount goes to zero, the object is destroyed,
  1594. and all associated memory is freed.
  1595. Arguments:
  1596. DeviceInfoSet - Supplies the address of the device information set containing the
  1597. linked list of class driver list objects.
  1598. DriverListHead - Optionally, supplies a pointer to the header of the driver list
  1599. to be dereferenced. If this parameter is not supplied, the routine does nothing.
  1600. Return Value:
  1601. None.
  1602. --*/
  1603. {
  1604. PDRIVER_LIST_OBJECT DrvListObject, PrevDrvListObject;
  1605. if(DriverListHead) {
  1606. DrvListObject = GetAssociatedDriverListObject(DeviceInfoSet->ClassDrvListObjectList,
  1607. DriverListHead,
  1608. &PrevDrvListObject
  1609. );
  1610. MYASSERT(DrvListObject && DrvListObject->RefCount);
  1611. if(!(--DrvListObject->RefCount)) {
  1612. if(PrevDrvListObject) {
  1613. PrevDrvListObject->Next = DrvListObject->Next;
  1614. } else {
  1615. DeviceInfoSet->ClassDrvListObjectList = DrvListObject->Next;
  1616. }
  1617. MyFree(DrvListObject);
  1618. DestroyDriverNodes(DriverListHead, DeviceInfoSet);
  1619. }
  1620. }
  1621. }
  1622. DWORD
  1623. GetDevInstallParams(
  1624. IN PDEVICE_INFO_SET DeviceInfoSet,
  1625. IN PDEVINSTALL_PARAM_BLOCK DevInstParamBlock,
  1626. OUT PSP_DEVINSTALL_PARAMS DeviceInstallParams
  1627. )
  1628. /*++
  1629. Routine Description:
  1630. This routine fills in a SP_DEVINSTALL_PARAMS structure based on the
  1631. installation parameter block supplied.
  1632. Note: The DeviceInstallParams structure must have its cbSize field
  1633. filled in correctly, or the call will fail.
  1634. Arguments:
  1635. DeviceInfoSet - Supplies the address of the device information set
  1636. containing the parameters to be retrieved. (This parameter is
  1637. used to gain access to the string table for some of the string
  1638. parameters).
  1639. DevInstParamBlock - Supplies the address of an installation parameter
  1640. block containing the parameters to be used in filling out the
  1641. return buffer.
  1642. DeviceInstallParams - Supplies the address of a buffer that will
  1643. receive the filled-in SP_DEVINSTALL_PARAMS structure.
  1644. Return Value:
  1645. If the function succeeds, the return value is NO_ERROR.
  1646. If the function fails, an ERROR_* code is returned.
  1647. --*/
  1648. {
  1649. PTSTR StringPtr;
  1650. if(DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS)) {
  1651. return ERROR_INVALID_USER_BUFFER;
  1652. }
  1653. //
  1654. // Fill in parameters.
  1655. //
  1656. ZeroMemory(DeviceInstallParams, sizeof(SP_DEVINSTALL_PARAMS));
  1657. DeviceInstallParams->cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  1658. DeviceInstallParams->Flags = DevInstParamBlock->Flags;
  1659. DeviceInstallParams->FlagsEx = DevInstParamBlock->FlagsEx;
  1660. DeviceInstallParams->hwndParent = DevInstParamBlock->hwndParent;
  1661. DeviceInstallParams->InstallMsgHandler = DevInstParamBlock->InstallMsgHandler;
  1662. DeviceInstallParams->InstallMsgHandlerContext = DevInstParamBlock->InstallMsgHandlerContext;
  1663. DeviceInstallParams->FileQueue = DevInstParamBlock->UserFileQ;
  1664. DeviceInstallParams->ClassInstallReserved = DevInstParamBlock->ClassInstallReserved;
  1665. //
  1666. // The Reserved field is currently unused.
  1667. //
  1668. if(DevInstParamBlock->DriverPath != -1) {
  1669. StringPtr = pStringTableStringFromId(DeviceInfoSet->StringTable,
  1670. DevInstParamBlock->DriverPath
  1671. );
  1672. lstrcpy(DeviceInstallParams->DriverPath, StringPtr);
  1673. }
  1674. return NO_ERROR;
  1675. }
  1676. DWORD
  1677. GetClassInstallParams(
  1678. IN PDEVINSTALL_PARAM_BLOCK DevInstParamBlock,
  1679. OUT PSP_CLASSINSTALL_HEADER ClassInstallParams, OPTIONAL
  1680. IN DWORD BufferSize,
  1681. OUT PDWORD RequiredSize OPTIONAL
  1682. )
  1683. /*++
  1684. Routine Description:
  1685. This routine fills in a buffer with the class installer parameters (if any)
  1686. contained in the installation parameter block supplied.
  1687. Note: If supplied, the ClassInstallParams structure must have the cbSize
  1688. field of the embedded SP_CLASSINSTALL_HEADER structure set to the size, in bytes,
  1689. of the header. If this is not set correctly, the call will fail.
  1690. Arguments:
  1691. DevInstParamBlock - Supplies the address of an installation parameter block
  1692. containing the class installer parameters to be used in filling out the
  1693. return buffer.
  1694. DeviceInstallParams - Optionally, supplies the address of a buffer
  1695. that will receive the class installer parameters structure currently
  1696. stored in the installation parameters block. If this parameter is not
  1697. supplied, then BufferSize must be zero.
  1698. BufferSize - Supplies the size, in bytes, of the DeviceInstallParams
  1699. buffer, or zero if DeviceInstallParams is not supplied.
  1700. RequiredSize - Optionally, supplies the address of a variable that
  1701. receives the number of bytes required to store the data.
  1702. Return Value:
  1703. If the function succeeds, the return value is NO_ERROR.
  1704. If the function fails, an ERROR_* code is returned.
  1705. --*/
  1706. {
  1707. //
  1708. // First, see whether we have any class install params, and if not, return
  1709. // ERROR_NO_CLASSINSTALL_PARAMS.
  1710. //
  1711. if(!DevInstParamBlock->ClassInstallHeader) {
  1712. return ERROR_NO_CLASSINSTALL_PARAMS;
  1713. }
  1714. if(ClassInstallParams) {
  1715. if((BufferSize < sizeof(SP_CLASSINSTALL_HEADER)) ||
  1716. (ClassInstallParams->cbSize != sizeof(SP_CLASSINSTALL_HEADER))) {
  1717. return ERROR_INVALID_USER_BUFFER;
  1718. }
  1719. } else if(BufferSize) {
  1720. return ERROR_INVALID_USER_BUFFER;
  1721. }
  1722. //
  1723. // Store required size in output parameter (if requested).
  1724. //
  1725. if(RequiredSize) {
  1726. *RequiredSize = DevInstParamBlock->ClassInstallParamsSize;
  1727. }
  1728. //
  1729. // See if supplied buffer is large enough.
  1730. //
  1731. if(BufferSize < DevInstParamBlock->ClassInstallParamsSize) {
  1732. return ERROR_INSUFFICIENT_BUFFER;
  1733. }
  1734. CopyMemory((PVOID)ClassInstallParams,
  1735. (PVOID)DevInstParamBlock->ClassInstallHeader,
  1736. DevInstParamBlock->ClassInstallParamsSize
  1737. );
  1738. return NO_ERROR;
  1739. }
  1740. DWORD
  1741. SetDevInstallParams(
  1742. IN OUT PDEVICE_INFO_SET DeviceInfoSet,
  1743. IN PSP_DEVINSTALL_PARAMS DeviceInstallParams,
  1744. OUT PDEVINSTALL_PARAM_BLOCK DevInstParamBlock,
  1745. IN BOOL MsgHandlerIsNativeCharWidth
  1746. )
  1747. /*++
  1748. Routine Description:
  1749. This routine updates an internal parameter block based on the parameters
  1750. supplied in a SP_DEVINSTALL_PARAMS structure.
  1751. Note: The supplied DeviceInstallParams structure must have its cbSize
  1752. field filled in correctly, or the call will fail.
  1753. Arguments:
  1754. DeviceInfoSet - Supplies the address of the device information set
  1755. containing the parameters to be set.
  1756. DeviceInstallParams - Supplies the address of a buffer containing the new
  1757. installation parameters.
  1758. DevInstParamBlock - Supplies the address of an installation parameter
  1759. block to be updated.
  1760. MsgHandlerIsNativeCharWidth - supplies a flag indicating whether the
  1761. InstallMsgHandler in the DeviceInstallParams structure points to
  1762. a callback routine that is expecting arguments in the 'native'
  1763. character format. A value of FALSE is meaningful only in the
  1764. Unicode build and specifies that the callback routine wants
  1765. ANSI parameters.
  1766. Return Value:
  1767. If the function succeeds, the return value is NO_ERROR.
  1768. If the function fails, an ERROR_* code is returned.
  1769. --*/
  1770. {
  1771. DWORD DriverPathLen;
  1772. LONG StringId;
  1773. TCHAR TempString[MAX_PATH];
  1774. HSPFILEQ OldQueueHandle = NULL;
  1775. BOOL bRestoreQueue = FALSE;
  1776. if(DeviceInstallParams->cbSize != sizeof(SP_DEVINSTALL_PARAMS)) {
  1777. return ERROR_INVALID_USER_BUFFER;
  1778. }
  1779. //
  1780. // No validation is currently required for the hwndParent, InstallMsgHandler,
  1781. // InstallMsgHandlerContext, or ClassInstallReserved fields.
  1782. //
  1783. //
  1784. // Validate Flags(Ex)
  1785. //
  1786. if((DeviceInstallParams->Flags & DI_FLAGS_ILLEGAL) ||
  1787. (DeviceInstallParams->FlagsEx & DI_FLAGSEX_ILLEGAL)) {
  1788. return ERROR_INVALID_FLAGS;
  1789. }
  1790. //
  1791. // Make sure that if DI_CLASSINSTALLPARAMS is being set, that we really do have
  1792. // class install parameters.
  1793. //
  1794. if((DeviceInstallParams->Flags & DI_CLASSINSTALLPARAMS) &&
  1795. !(DevInstParamBlock->ClassInstallHeader)) {
  1796. return ERROR_NO_CLASSINSTALL_PARAMS;
  1797. }
  1798. //
  1799. // Make sure that if DI_NOVCP is being set, that we have a caller-supplied file queue.
  1800. //
  1801. if((DeviceInstallParams->Flags & DI_NOVCP) &&
  1802. ((DeviceInstallParams->FileQueue == NULL) || (DeviceInstallParams->FileQueue == INVALID_HANDLE_VALUE))) {
  1803. return ERROR_INVALID_FLAGS;
  1804. }
  1805. //
  1806. // Make sure that if DI_FLAGSEX_ALTPLATFORM_DRVSEARCH is being set, that we
  1807. // have a caller-supplied file queue.
  1808. //
  1809. // NOTE: We don't actually verify at this time that the file queue has
  1810. // alternate platform info associated with it--this association can
  1811. // actually be done later. We _will_ catch this (and return an error) in
  1812. // SetupDiBuildDriverInfoList if at that time we find that the file queue
  1813. // has no alt platform info.
  1814. //
  1815. if((DeviceInstallParams->FlagsEx & DI_FLAGSEX_ALTPLATFORM_DRVSEARCH) &&
  1816. !(DeviceInstallParams->Flags & DI_NOVCP)) {
  1817. return ERROR_INVALID_PARAMETER;
  1818. }
  1819. //
  1820. // Validate that the DriverPath string is properly NULL-terminated.
  1821. //
  1822. if((DriverPathLen = lstrlen(DeviceInstallParams->DriverPath)) >= MAX_PATH) {
  1823. return ERROR_INVALID_PARAMETER;
  1824. }
  1825. //
  1826. // Validate the caller-supplied file queue.
  1827. //
  1828. if((DeviceInstallParams->FileQueue == NULL) || (DeviceInstallParams->FileQueue == INVALID_HANDLE_VALUE)) {
  1829. //
  1830. // Store the current file queue handle (if any) to be released later.
  1831. //
  1832. OldQueueHandle = DevInstParamBlock->UserFileQ;
  1833. DevInstParamBlock->UserFileQ = NULL;
  1834. bRestoreQueue = TRUE;
  1835. } else {
  1836. //
  1837. // The caller supplied a file queue handle. See if it's the same one
  1838. // we already have.
  1839. //
  1840. if(DeviceInstallParams->FileQueue != DevInstParamBlock->UserFileQ) {
  1841. //
  1842. // The caller has supplied a file queue handle that's different
  1843. // from the one we currently have stored. Remember the old handle
  1844. // (in case we need to restore), and store the new handle. Also,
  1845. // increment the lock refcount on the new handle (enclose in
  1846. // try/except in case it's a bogus one).
  1847. //
  1848. OldQueueHandle = DevInstParamBlock->UserFileQ;
  1849. bRestoreQueue = TRUE;
  1850. try {
  1851. if(((PSP_FILE_QUEUE)(DeviceInstallParams->FileQueue))->Signature == SP_FILE_QUEUE_SIG) {
  1852. ((PSP_FILE_QUEUE)(DeviceInstallParams->FileQueue))->LockRefCount++;
  1853. DevInstParamBlock->UserFileQ = DeviceInstallParams->FileQueue;
  1854. } else {
  1855. //
  1856. // Queue's signature isn't valid
  1857. //
  1858. bRestoreQueue = FALSE;
  1859. }
  1860. } except(EXCEPTION_EXECUTE_HANDLER) {
  1861. DevInstParamBlock->UserFileQ = OldQueueHandle;
  1862. bRestoreQueue = FALSE;
  1863. }
  1864. if(!bRestoreQueue) {
  1865. //
  1866. // The file queue handle we were given was invalid.
  1867. //
  1868. return ERROR_INVALID_PARAMETER;
  1869. }
  1870. }
  1871. }
  1872. //
  1873. // Store the specified driver path.
  1874. //
  1875. if(DriverPathLen) {
  1876. lstrcpy(TempString, DeviceInstallParams->DriverPath);
  1877. if((StringId = pStringTableAddString(DeviceInfoSet->StringTable,
  1878. TempString,
  1879. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  1880. NULL,0
  1881. )) == -1) {
  1882. //
  1883. // We couldn't add the new driver path string to the string table. Restore the old
  1884. // file queue (if necessary) and return an out-of-memory error.
  1885. //
  1886. if(bRestoreQueue) {
  1887. if(DevInstParamBlock->UserFileQ) {
  1888. try {
  1889. ((PSP_FILE_QUEUE)(DevInstParamBlock->UserFileQ))->LockRefCount--;
  1890. } except(EXCEPTION_EXECUTE_HANDLER) {
  1891. ; // nothing to do
  1892. }
  1893. }
  1894. DevInstParamBlock->UserFileQ = OldQueueHandle;
  1895. }
  1896. return ERROR_NOT_ENOUGH_MEMORY;
  1897. }
  1898. DevInstParamBlock->DriverPath = StringId;
  1899. } else {
  1900. DevInstParamBlock->DriverPath = -1;
  1901. }
  1902. //
  1903. // Should be smooth sailing from here on out. Decrement the refcount on the old queue handle,
  1904. // if there was one.
  1905. //
  1906. if(OldQueueHandle) {
  1907. try {
  1908. MYASSERT(((PSP_FILE_QUEUE)OldQueueHandle)->LockRefCount);
  1909. ((PSP_FILE_QUEUE)OldQueueHandle)->LockRefCount--;
  1910. } except(EXCEPTION_EXECUTE_HANDLER) {
  1911. ; // nothing to do
  1912. }
  1913. }
  1914. //
  1915. // Ignore attempts at modifying read-only flags.
  1916. //
  1917. DevInstParamBlock->Flags = (DeviceInstallParams->Flags & ~DI_FLAGS_READONLY) |
  1918. (DevInstParamBlock->Flags & DI_FLAGS_READONLY);
  1919. DevInstParamBlock->FlagsEx = (DeviceInstallParams->FlagsEx & ~DI_FLAGSEX_READONLY) |
  1920. (DevInstParamBlock->FlagsEx & DI_FLAGSEX_READONLY);
  1921. //
  1922. // Additionally, if we're in non-interactive mode, make sure not to clear
  1923. // our "be quiet" flags.
  1924. //
  1925. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  1926. DevInstParamBlock->Flags |= DI_QUIETINSTALL;
  1927. DevInstParamBlock->FlagsEx |= DI_FLAGSEX_NOUIONQUERYREMOVE;
  1928. }
  1929. //
  1930. // Store the rest of the parameters.
  1931. //
  1932. DevInstParamBlock->hwndParent = DeviceInstallParams->hwndParent;
  1933. DevInstParamBlock->InstallMsgHandler = DeviceInstallParams->InstallMsgHandler;
  1934. DevInstParamBlock->InstallMsgHandlerContext = DeviceInstallParams->InstallMsgHandlerContext;
  1935. DevInstParamBlock->ClassInstallReserved = DeviceInstallParams->ClassInstallReserved;
  1936. DevInstParamBlock->InstallMsgHandlerIsNativeCharWidth = MsgHandlerIsNativeCharWidth;
  1937. return NO_ERROR;
  1938. }
  1939. DWORD
  1940. SetClassInstallParams(
  1941. IN OUT PDEVICE_INFO_SET DeviceInfoSet,
  1942. IN PSP_CLASSINSTALL_HEADER ClassInstallParams, OPTIONAL
  1943. IN DWORD ClassInstallParamsSize,
  1944. OUT PDEVINSTALL_PARAM_BLOCK DevInstParamBlock
  1945. )
  1946. /*++
  1947. Routine Description:
  1948. This routine updates an internal class installer parameter block based on
  1949. the parameters supplied in a class installer parameter buffer. If this
  1950. buffer is not supplied, then the existing class installer parameters (if
  1951. any) are cleared.
  1952. Arguments:
  1953. DeviceInfoSet - Supplies the address of the device information set
  1954. for which class installer parameters are to be set.
  1955. ClassInstallParams - Optionally, supplies the address of a buffer containing
  1956. the class installer parameters to be used. The SP_CLASSINSTALL_HEADER
  1957. structure at the beginning of the buffer must have its cbSize field set to
  1958. be sizeof(SP_CLASSINSTALL_HEADER), and the InstallFunction field must be
  1959. set to the DI_FUNCTION code reflecting the type of parameters supplied in
  1960. the rest of the buffer.
  1961. If this parameter is not supplied, then the current class installer parameters
  1962. (if any) will be cleared for the specified device information set or element.
  1963. ClassInstallParamsSize - Supplies the size, in bytes, of the ClassInstallParams
  1964. buffer. If the buffer is not supplied (i.e., the class installer parameters
  1965. are to be cleared), then this value must be zero.
  1966. DevInstParamBlock - Supplies the address of an installation parameter
  1967. block to be updated.
  1968. Return Value:
  1969. If the function succeeds, the return value is NO_ERROR.
  1970. If the function fails, an ERROR_* code is returned.
  1971. --*/
  1972. {
  1973. PBYTE NewParamBuffer;
  1974. if(ClassInstallParams) {
  1975. if((ClassInstallParamsSize < sizeof(SP_CLASSINSTALL_HEADER)) ||
  1976. (ClassInstallParams->cbSize != sizeof(SP_CLASSINSTALL_HEADER))) {
  1977. return ERROR_INVALID_USER_BUFFER;
  1978. }
  1979. } else {
  1980. //
  1981. // We are to clear any existing class installer parameters.
  1982. //
  1983. if(ClassInstallParamsSize) {
  1984. return ERROR_INVALID_USER_BUFFER;
  1985. }
  1986. if(DevInstParamBlock->ClassInstallHeader) {
  1987. MyFree(DevInstParamBlock->ClassInstallHeader);
  1988. DevInstParamBlock->ClassInstallHeader = NULL;
  1989. DevInstParamBlock->ClassInstallParamsSize = 0;
  1990. DevInstParamBlock->Flags &= ~DI_CLASSINSTALLPARAMS;
  1991. }
  1992. return NO_ERROR;
  1993. }
  1994. //
  1995. // Validate the new class install parameters w.r.t. the value of the specified
  1996. // InstallFunction code.
  1997. //
  1998. switch(ClassInstallParams->InstallFunction) {
  1999. case DIF_ENABLECLASS :
  2000. //
  2001. // We should have a SP_ENABLECLASS_PARAMS structure.
  2002. //
  2003. if(ClassInstallParamsSize == sizeof(SP_ENABLECLASS_PARAMS)) {
  2004. PSP_ENABLECLASS_PARAMS EnableClassParams;
  2005. EnableClassParams = (PSP_ENABLECLASS_PARAMS)ClassInstallParams;
  2006. //
  2007. // Don't bother validating GUID--just validate EnableMessage field.
  2008. //
  2009. if(EnableClassParams->EnableMessage <= ENABLECLASS_FAILURE) {
  2010. //
  2011. // parameter set validated.
  2012. //
  2013. break;
  2014. }
  2015. }
  2016. return ERROR_INVALID_PARAMETER;
  2017. case DIF_MOVEDEVICE :
  2018. //
  2019. // We should have a SP_MOVEDEV_PARAMS structure.
  2020. //
  2021. if(ClassInstallParamsSize == sizeof(SP_MOVEDEV_PARAMS)) {
  2022. PSP_MOVEDEV_PARAMS MoveDevParams;
  2023. MoveDevParams = (PSP_MOVEDEV_PARAMS)ClassInstallParams;
  2024. if(FindAssociatedDevInfoElem(DeviceInfoSet,
  2025. &(MoveDevParams->SourceDeviceInfoData),
  2026. NULL)) {
  2027. //
  2028. // parameter set validated.
  2029. //
  2030. break;
  2031. }
  2032. }
  2033. return ERROR_INVALID_PARAMETER;
  2034. case DIF_PROPERTYCHANGE :
  2035. //
  2036. // We should have a SP_PROPCHANGE_PARAMS structure.
  2037. //
  2038. if(ClassInstallParamsSize == sizeof(SP_PROPCHANGE_PARAMS)) {
  2039. PSP_PROPCHANGE_PARAMS PropChangeParams;
  2040. PropChangeParams = (PSP_PROPCHANGE_PARAMS)ClassInstallParams;
  2041. if((PropChangeParams->StateChange >= DICS_ENABLE) &&
  2042. (PropChangeParams->StateChange <= DICS_STOP)) {
  2043. //
  2044. // Validate Scope specifier--even though these values are defined like
  2045. // flags, they are mutually exclusive, so treat them like ordinals.
  2046. //
  2047. if((PropChangeParams->Scope == DICS_FLAG_GLOBAL) ||
  2048. (PropChangeParams->Scope == DICS_FLAG_CONFIGSPECIFIC) ||
  2049. (PropChangeParams->Scope == DICS_FLAG_CONFIGGENERAL)) {
  2050. //
  2051. // DICS_START and DICS_STOP are always config specific.
  2052. //
  2053. if(((PropChangeParams->StateChange == DICS_START) || (PropChangeParams->StateChange == DICS_STOP)) &&
  2054. (PropChangeParams->Scope != DICS_FLAG_CONFIGSPECIFIC)) {
  2055. goto BadPropChangeParams;
  2056. }
  2057. //
  2058. // parameter set validated
  2059. //
  2060. // NOTE: Even though DICS_FLAG_CONFIGSPECIFIC indicates
  2061. // that the HwProfile field specifies a hardware profile,
  2062. // there's no need to do validation on that.
  2063. //
  2064. break;
  2065. }
  2066. }
  2067. }
  2068. BadPropChangeParams:
  2069. return ERROR_INVALID_PARAMETER;
  2070. case DIF_REMOVE :
  2071. //
  2072. // We should have a SP_REMOVEDEVICE_PARAMS structure.
  2073. //
  2074. if(ClassInstallParamsSize == sizeof(SP_REMOVEDEVICE_PARAMS)) {
  2075. PSP_REMOVEDEVICE_PARAMS RemoveDevParams;
  2076. RemoveDevParams = (PSP_REMOVEDEVICE_PARAMS)ClassInstallParams;
  2077. if((RemoveDevParams->Scope == DI_REMOVEDEVICE_GLOBAL) ||
  2078. (RemoveDevParams->Scope == DI_REMOVEDEVICE_CONFIGSPECIFIC)) {
  2079. //
  2080. // parameter set validated
  2081. //
  2082. // NOTE: Even though DI_REMOVEDEVICE_CONFIGSPECIFIC indicates
  2083. // that the HwProfile field specifies a hardware profile,
  2084. // there's no need to do validation on that.
  2085. //
  2086. break;
  2087. }
  2088. }
  2089. return ERROR_INVALID_PARAMETER;
  2090. case DIF_UNREMOVE :
  2091. //
  2092. // We should have a SP_UNREMOVEDEVICE_PARAMS structure.
  2093. //
  2094. if(ClassInstallParamsSize == sizeof(SP_UNREMOVEDEVICE_PARAMS)) {
  2095. PSP_UNREMOVEDEVICE_PARAMS UnremoveDevParams;
  2096. UnremoveDevParams = (PSP_UNREMOVEDEVICE_PARAMS)ClassInstallParams;
  2097. if(UnremoveDevParams->Scope == DI_UNREMOVEDEVICE_CONFIGSPECIFIC) {
  2098. //
  2099. // parameter set validated
  2100. //
  2101. // NOTE: Even though DI_UNREMOVEDEVICE_CONFIGSPECIFIC indicates
  2102. // that the HwProfile field specifies a hardware profile,
  2103. // there's no need to do validation on that.
  2104. //
  2105. break;
  2106. }
  2107. }
  2108. return ERROR_INVALID_PARAMETER;
  2109. case DIF_SELECTDEVICE :
  2110. //
  2111. // We should have a SP_SELECTDEVICE_PARAMS structure.
  2112. //
  2113. if(ClassInstallParamsSize == sizeof(SP_SELECTDEVICE_PARAMS)) {
  2114. PSP_SELECTDEVICE_PARAMS SelectDevParams;
  2115. SelectDevParams = (PSP_SELECTDEVICE_PARAMS)ClassInstallParams;
  2116. //
  2117. // Validate that the string fields are properly NULL-terminated.
  2118. //
  2119. if((lstrlen(SelectDevParams->Title) < MAX_TITLE_LEN) &&
  2120. (lstrlen(SelectDevParams->Instructions) < MAX_INSTRUCTION_LEN) &&
  2121. (lstrlen(SelectDevParams->ListLabel) < MAX_LABEL_LEN) &&
  2122. (lstrlen(SelectDevParams->SubTitle) < MAX_SUBTITLE_LEN)) {
  2123. //
  2124. // parameter set validated
  2125. //
  2126. break;
  2127. }
  2128. }
  2129. return ERROR_INVALID_PARAMETER;
  2130. case DIF_INSTALLWIZARD :
  2131. //
  2132. // We should have a SP_INSTALLWIZARD_DATA structure.
  2133. //
  2134. if(ClassInstallParamsSize == sizeof(SP_INSTALLWIZARD_DATA)) {
  2135. PSP_INSTALLWIZARD_DATA InstallWizData;
  2136. DWORD i;
  2137. InstallWizData = (PSP_INSTALLWIZARD_DATA)ClassInstallParams;
  2138. //
  2139. // Validate the propsheet handle list.
  2140. //
  2141. if(InstallWizData->NumDynamicPages <= MAX_INSTALLWIZARD_DYNAPAGES) {
  2142. for(i = 0; i < InstallWizData->NumDynamicPages; i++) {
  2143. //
  2144. // For now, just verify that all handles are non-NULL.
  2145. //
  2146. if(!(InstallWizData->DynamicPages[i])) {
  2147. //
  2148. // Invalid property sheet page handle
  2149. //
  2150. return ERROR_INVALID_PARAMETER;
  2151. }
  2152. }
  2153. //
  2154. // Handles are verified, now verify Flags.
  2155. //
  2156. if(!(InstallWizData->Flags & NDW_INSTALLFLAG_ILLEGAL)) {
  2157. if(!(InstallWizData->DynamicPageFlags & DYNAWIZ_FLAG_ILLEGAL)) {
  2158. //
  2159. // parameter set validated
  2160. //
  2161. break;
  2162. }
  2163. }
  2164. }
  2165. }
  2166. return ERROR_INVALID_PARAMETER;
  2167. case DIF_NEWDEVICEWIZARD_PRESELECT :
  2168. case DIF_NEWDEVICEWIZARD_SELECT :
  2169. case DIF_NEWDEVICEWIZARD_PREANALYZE :
  2170. case DIF_NEWDEVICEWIZARD_POSTANALYZE :
  2171. case DIF_NEWDEVICEWIZARD_FINISHINSTALL :
  2172. case DIF_ADDPROPERTYPAGE_ADVANCED:
  2173. case DIF_ADDPROPERTYPAGE_BASIC:
  2174. case DIF_ADDREMOTEPROPERTYPAGE_ADVANCED:
  2175. //
  2176. // We should have a SP_NEWDEVICEWIZARD_DATA structure.
  2177. //
  2178. if(ClassInstallParamsSize == sizeof(SP_NEWDEVICEWIZARD_DATA)) {
  2179. PSP_NEWDEVICEWIZARD_DATA NewDevWizData;
  2180. DWORD i;
  2181. NewDevWizData = (PSP_NEWDEVICEWIZARD_DATA)ClassInstallParams;
  2182. //
  2183. // Validate the propsheet handle list.
  2184. //
  2185. if(NewDevWizData->NumDynamicPages <= MAX_INSTALLWIZARD_DYNAPAGES) {
  2186. for(i = 0; i < NewDevWizData->NumDynamicPages; i++) {
  2187. //
  2188. // For now, just verify that all handles are non-NULL.
  2189. //
  2190. if(!(NewDevWizData->DynamicPages[i])) {
  2191. //
  2192. // Invalid property sheet page handle
  2193. //
  2194. return ERROR_INVALID_PARAMETER;
  2195. }
  2196. }
  2197. //
  2198. // Handles are verified, now verify Flags.
  2199. //
  2200. if(!(NewDevWizData->Flags & NEWDEVICEWIZARD_FLAG_ILLEGAL)) {
  2201. //
  2202. // parameter set validated
  2203. //
  2204. break;
  2205. }
  2206. }
  2207. }
  2208. return ERROR_INVALID_PARAMETER;
  2209. case DIF_DETECT :
  2210. //
  2211. // We should have a SP_DETECTDEVICE_PARAMS structure.
  2212. //
  2213. if(ClassInstallParamsSize == sizeof(SP_DETECTDEVICE_PARAMS)) {
  2214. PSP_DETECTDEVICE_PARAMS DetectDeviceParams;
  2215. DetectDeviceParams = (PSP_DETECTDEVICE_PARAMS)ClassInstallParams;
  2216. //
  2217. // Make sure there's an entry point for the progress notification callback.
  2218. //
  2219. if(DetectDeviceParams->DetectProgressNotify) {
  2220. //
  2221. // parameter set validated.
  2222. //
  2223. break;
  2224. }
  2225. }
  2226. return ERROR_INVALID_PARAMETER;
  2227. case DIF_GETWINDOWSUPDATEINFO:
  2228. //
  2229. // We should have a SP_WINDOWSUPDATE_PARAMS structure.
  2230. //
  2231. if(ClassInstallParamsSize == sizeof(SP_WINDOWSUPDATE_PARAMS)) {
  2232. break;
  2233. }
  2234. return ERROR_INVALID_PARAMETER;
  2235. case DIF_TROUBLESHOOTER:
  2236. //
  2237. // We should have a SP_TROUBLESHOOTER_PARAMS structure.
  2238. //
  2239. if (ClassInstallParamsSize == sizeof(SP_TROUBLESHOOTER_PARAMS)) {
  2240. break;
  2241. }
  2242. return ERROR_INVALID_PARAMETER;
  2243. case DIF_POWERMESSAGEWAKE:
  2244. //
  2245. // We should have a SP_POWERMESSAGEWAKE_PARAMS structure.
  2246. //
  2247. if (ClassInstallParamsSize == sizeof(SP_POWERMESSAGEWAKE_PARAMS)) {
  2248. break;
  2249. }
  2250. return ERROR_INVALID_PARAMETER;
  2251. case DIF_INTERFACE_TO_DEVICE:
  2252. #ifdef UNICODE
  2253. //
  2254. // We should have a SP_INTERFACE_TO_DEVICE_PARAMS_W structure
  2255. //
  2256. if (ClassInstallParamsSize == sizeof(SP_INTERFACE_TO_DEVICE_PARAMS_W)) {
  2257. PSP_INTERFACE_TO_DEVICE_PARAMS_W InterfaceToDeviceParams;
  2258. InterfaceToDeviceParams = (PSP_INTERFACE_TO_DEVICE_PARAMS_W)ClassInstallParams;
  2259. if(!InterfaceToDeviceParams->Interface) {
  2260. //
  2261. // this must be defined
  2262. //
  2263. return ERROR_INVALID_PARAMETER;
  2264. }
  2265. //
  2266. // Validated
  2267. //
  2268. break;
  2269. }
  2270. #endif
  2271. return ERROR_INVALID_PARAMETER;
  2272. default :
  2273. //
  2274. // Some generic buffer. No validation to be done.
  2275. //
  2276. break;
  2277. }
  2278. //
  2279. // The class install parameters have been validated. Allocate a buffer for the
  2280. // new parameter structure.
  2281. //
  2282. if(!(NewParamBuffer = MyMalloc(ClassInstallParamsSize))) {
  2283. return ERROR_NOT_ENOUGH_MEMORY;
  2284. }
  2285. try {
  2286. CopyMemory(NewParamBuffer,
  2287. ClassInstallParams,
  2288. ClassInstallParamsSize
  2289. );
  2290. } except(EXCEPTION_EXECUTE_HANDLER) {
  2291. MyFree(NewParamBuffer);
  2292. NewParamBuffer = NULL;
  2293. }
  2294. if(!NewParamBuffer) {
  2295. //
  2296. // Then an error occurred and we couldn't store the new parameters.
  2297. //
  2298. return ERROR_INVALID_PARAMETER;
  2299. }
  2300. if(DevInstParamBlock->ClassInstallHeader) {
  2301. MyFree(DevInstParamBlock->ClassInstallHeader);
  2302. }
  2303. DevInstParamBlock->ClassInstallHeader = (PSP_CLASSINSTALL_HEADER)NewParamBuffer;
  2304. DevInstParamBlock->ClassInstallParamsSize = ClassInstallParamsSize;
  2305. DevInstParamBlock->Flags |= DI_CLASSINSTALLPARAMS;
  2306. return NO_ERROR;
  2307. }
  2308. DWORD
  2309. GetDrvInstallParams(
  2310. IN PDRIVER_NODE DriverNode,
  2311. OUT PSP_DRVINSTALL_PARAMS DriverInstallParams
  2312. )
  2313. /*++
  2314. Routine Description:
  2315. This routine fills in a SP_DRVINSTALL_PARAMS structure based on the
  2316. driver node supplied
  2317. Note: The supplied DriverInstallParams structure must have its cbSize
  2318. field filled in correctly, or the call will fail.
  2319. Arguments:
  2320. DriverNode - Supplies the address of the driver node containing the
  2321. installation parameters to be retrieved.
  2322. DriverInstallParams - Supplies the address of a SP_DRVINSTALL_PARAMS
  2323. structure that will receive the installation parameters.
  2324. Return Value:
  2325. If the function succeeds, the return value is NO_ERROR.
  2326. If the function fails, an ERROR_* code is returned.
  2327. NOTE:
  2328. This routine _does not_ set the Win98-compatible DNF_CLASS_DRIVER or
  2329. DNF_COMPATIBLE_DRIVER flags that indicate whether or not the driver node is
  2330. from a class or compatible driver list, respectively.
  2331. --*/
  2332. {
  2333. if(DriverInstallParams->cbSize != sizeof(SP_DRVINSTALL_PARAMS)) {
  2334. return ERROR_INVALID_USER_BUFFER;
  2335. }
  2336. //
  2337. // Copy the parameters.
  2338. //
  2339. DriverInstallParams->Rank = DriverNode->Rank;
  2340. DriverInstallParams->Flags = DriverNode->Flags;
  2341. DriverInstallParams->PrivateData = DriverNode->PrivateData;
  2342. //
  2343. // The 'Reserved' field of the SP_DRVINSTALL_PARAMS structure isn't currently
  2344. // used.
  2345. //
  2346. return NO_ERROR;
  2347. }
  2348. DWORD
  2349. SetDrvInstallParams(
  2350. IN PSP_DRVINSTALL_PARAMS DriverInstallParams,
  2351. OUT PDRIVER_NODE DriverNode
  2352. )
  2353. /*++
  2354. Routine Description:
  2355. This routine sets the driver installation parameters for the specified
  2356. driver node based on the caller-supplied SP_DRVINSTALL_PARAMS structure.
  2357. Note: The supplied DriverInstallParams structure must have its cbSize
  2358. field filled in correctly, or the call will fail.
  2359. Arguments:
  2360. DriverInstallParams - Supplies the address of a SP_DRVINSTALL_PARAMS
  2361. structure containing the installation parameters to be used.
  2362. DriverNode - Supplies the address of the driver node whose installation
  2363. parameters are to be set.
  2364. Return Value:
  2365. If the function succeeds, the return value is NO_ERROR.
  2366. If the function fails, an ERROR_* code is returned.
  2367. --*/
  2368. {
  2369. if(DriverInstallParams->cbSize != sizeof(SP_DRVINSTALL_PARAMS)) {
  2370. return ERROR_INVALID_USER_BUFFER;
  2371. }
  2372. //
  2373. // Validate the flags.
  2374. //
  2375. if(DriverInstallParams->Flags & DNF_FLAGS_ILLEGAL) {
  2376. return ERROR_INVALID_FLAGS;
  2377. }
  2378. //
  2379. // No validation currently being done on Rank and PrivateData fields.
  2380. //
  2381. // We're ready to copy the parameters.
  2382. //
  2383. DriverNode->Rank = DriverInstallParams->Rank;
  2384. DriverNode->PrivateData = DriverInstallParams->PrivateData;
  2385. //
  2386. // Ignore attempts at modifying read-only flags.
  2387. //
  2388. DriverNode->Flags = (DriverInstallParams->Flags & ~DNF_FLAGS_READONLY) |
  2389. (DriverNode->Flags & DNF_FLAGS_READONLY);
  2390. return NO_ERROR;
  2391. }
  2392. LONG
  2393. AddMultiSzToStringTable(
  2394. IN PVOID StringTable,
  2395. IN PTCHAR MultiSzBuffer,
  2396. OUT PLONG StringIdList,
  2397. IN DWORD StringIdListSize,
  2398. IN BOOL CaseSensitive,
  2399. OUT PTCHAR *UnprocessedBuffer OPTIONAL
  2400. )
  2401. /*++
  2402. Routine Description:
  2403. This routine adds every string in the MultiSzBuffer to the specified
  2404. string table, and stores the resulting IDs in the supplied output buffer.
  2405. Arguments:
  2406. StringTable - Supplies the handle of the string table to add the strings to.
  2407. MultiSzBuffer - Supplies the address of the REG_MULTI_SZ buffer containing
  2408. the strings to be added.
  2409. StringIdList - Supplies the address of an array of LONGs that receives the
  2410. list of IDs for the added strings (the ordering of the IDs in this
  2411. list will be the same as the ordering of the strings in the MultiSzBuffer.
  2412. StringIdListSize - Supplies the size, in LONGs, of the StringIdList. If the
  2413. number of strings in MultiSzBuffer exceeds this amount, then only the
  2414. first StringIdListSize strings will be added, and the position in the
  2415. buffer where processing was halted will be stored in UnprocessedBuffer.
  2416. CaseSensitive - Specifies whether the string should be added case-sensitively.
  2417. UnprocessedBuffer - Optionally, supplies the address of a character pointer
  2418. that receives the position where processing was aborted because the
  2419. StringIdList buffer was filled. If all strings in the MultiSzBuffer were
  2420. processed, then this pointer will be set to NULL.
  2421. Return Value:
  2422. If successful, the return value is the number of strings added.
  2423. If failure, the return value is -1 (this happens if a string cannot be
  2424. added because of an out-of-memory condition).
  2425. --*/
  2426. {
  2427. PTSTR CurString;
  2428. LONG StringCount = 0;
  2429. for(CurString = MultiSzBuffer;
  2430. (*CurString && (StringCount < (LONG)StringIdListSize));
  2431. CurString += (lstrlen(CurString)+1)) {
  2432. if((StringIdList[StringCount] = pStringTableAddString(
  2433. StringTable,
  2434. CurString,
  2435. CaseSensitive
  2436. ? STRTAB_CASE_SENSITIVE
  2437. : STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  2438. NULL,0
  2439. )) == -1)
  2440. {
  2441. StringCount = -1;
  2442. break;
  2443. }
  2444. StringCount++;
  2445. }
  2446. if(UnprocessedBuffer) {
  2447. *UnprocessedBuffer = (*CurString ? CurString : NULL);
  2448. }
  2449. return StringCount;
  2450. }
  2451. LONG
  2452. LookUpStringInDevInfoSet(
  2453. IN HDEVINFO DeviceInfoSet,
  2454. IN PTSTR String,
  2455. IN BOOL CaseSensitive
  2456. )
  2457. /*++
  2458. Routine Description:
  2459. This routine looks up the specified string in the string table associated with
  2460. the specified device information set.
  2461. Arguments:
  2462. DeviceInfoSet - Supplies the pointer to the device information set containing
  2463. the string table to look the string up in.
  2464. String - Specifies the string to be looked up. This string is not specified as
  2465. const, so that the lookup routine may modify it (i.e., lower-case it) without
  2466. having to allocate a temporary buffer.
  2467. CaseSensitive - If TRUE, then a case-sensitive lookup is performed, otherwise, the
  2468. lookup is case-insensitive.
  2469. Return Value:
  2470. If the function succeeds, the return value is the string's ID in the string table.
  2471. device information set.
  2472. If the function fails, the return value is -1.
  2473. --*/
  2474. {
  2475. PDEVICE_INFO_SET pDeviceInfoSet;
  2476. LONG StringId;
  2477. DWORD StringLen;
  2478. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  2479. return -1;
  2480. }
  2481. try {
  2482. StringId = pStringTableLookUpString(pDeviceInfoSet->StringTable,
  2483. String,
  2484. &StringLen,
  2485. NULL,
  2486. NULL,
  2487. STRTAB_BUFFER_WRITEABLE |
  2488. (CaseSensitive ? STRTAB_CASE_SENSITIVE
  2489. : STRTAB_CASE_INSENSITIVE),
  2490. NULL,0
  2491. );
  2492. } except(EXCEPTION_EXECUTE_HANDLER) {
  2493. StringId = -1;
  2494. }
  2495. UnlockDeviceInfoSet(pDeviceInfoSet);
  2496. return StringId;
  2497. }
  2498. BOOL
  2499. ShouldClassBeExcluded(
  2500. IN LPGUID ClassGuid,
  2501. IN BOOL ExcludeNoInstallClass
  2502. )
  2503. /*++
  2504. Routine Description:
  2505. This routine determines whether a class should be excluded from
  2506. some operation, based on whether it has a NoInstallClass or
  2507. NoUseClass value entry in its registry key.
  2508. Arguments:
  2509. ClassGuidString - Supplies the address of the class GUID to be
  2510. filtered.
  2511. ExcludeNoInstallClass - TRUE if NoInstallClass classes should be
  2512. excluded and FALSE if they should not be excluded.
  2513. Return Value:
  2514. If the class should be excluded, the return value is TRUE, otherwise
  2515. it is FALSE.
  2516. --*/
  2517. {
  2518. HKEY hk;
  2519. BOOL ExcludeClass = FALSE;
  2520. if((hk = SetupDiOpenClassRegKey(ClassGuid, KEY_READ)) != INVALID_HANDLE_VALUE) {
  2521. try {
  2522. if(RegQueryValueEx(hk,
  2523. pszNoUseClass,
  2524. NULL,
  2525. NULL,
  2526. NULL,
  2527. NULL) == ERROR_SUCCESS) {
  2528. ExcludeClass = TRUE;
  2529. } else if (ExcludeNoInstallClass &&
  2530. RegQueryValueEx(hk,
  2531. pszNoInstallClass,
  2532. NULL,
  2533. NULL,
  2534. NULL,
  2535. NULL) == ERROR_SUCCESS) {
  2536. ExcludeClass = TRUE;
  2537. }
  2538. } except(EXCEPTION_EXECUTE_HANDLER) {
  2539. //
  2540. // Nothing to do.
  2541. //
  2542. ;
  2543. }
  2544. RegCloseKey(hk);
  2545. }
  2546. return ExcludeClass;
  2547. }
  2548. BOOL
  2549. ClassGuidFromInfVersionNode(
  2550. IN PINF_VERSION_NODE VersionNode,
  2551. OUT LPGUID ClassGuid
  2552. )
  2553. /*++
  2554. Routine Description:
  2555. This routine retrieves the class GUID for the INF whose version node
  2556. is specified. If the version node doesn't have a ClassGUID value,
  2557. then the Class value is retrieved, and all class GUIDs matching this
  2558. class name are retrieved. If there is exactly 1 match found, then
  2559. this GUID is returned, otherwise, the routine fails.
  2560. Arguments:
  2561. VersionNode - Supplies the address of an INF version node that
  2562. must contain either a ClassGUID or Class entry.
  2563. ClassGuid - Supplies the address of the variable that receives the
  2564. class GUID.
  2565. Return Value:
  2566. If a class GUID was retrieved, the return value is TRUE, otherwise,
  2567. it is FALSE.
  2568. --*/
  2569. {
  2570. PCTSTR GuidString, NameString;
  2571. DWORD NumGuids;
  2572. if(GuidString = pSetupGetVersionDatum(VersionNode, pszClassGuid)) {
  2573. if(pSetupGuidFromString(GuidString, ClassGuid) == NO_ERROR) {
  2574. return TRUE;
  2575. }
  2576. } else {
  2577. NameString = pSetupGetVersionDatum(VersionNode, pszClass);
  2578. if(NameString &&
  2579. SetupDiClassGuidsFromName(NameString,
  2580. ClassGuid,
  2581. 1,
  2582. &NumGuids) && NumGuids) {
  2583. return TRUE;
  2584. }
  2585. }
  2586. return FALSE;
  2587. }
  2588. DWORD
  2589. EnumSingleDrvInf(
  2590. IN PCTSTR InfName,
  2591. IN OUT LPWIN32_FIND_DATA InfFileData,
  2592. IN DWORD SearchControl,
  2593. IN InfCacheCallback EnumInfCallback,
  2594. IN PSETUP_LOG_CONTEXT LogContext,
  2595. IN OUT PDRVSEARCH_CONTEXT Context
  2596. )
  2597. /*++
  2598. Routine Description:
  2599. This routine finds and opens the specified INF, and calls the
  2600. supplied callback routine for it. It's primary purpose is to
  2601. provide the callback with the same information the cache-search
  2602. does.
  2603. Arguments:
  2604. InfName - Supplies the name of the INF to call the callback for.
  2605. InfFileData - Supplies data returned from FindFirstFile/FindNextFile
  2606. for this INF. This parameter is used as input if the
  2607. INFINFO_INF_NAME_IS_ABSOLUTE SearchControl value is specified.
  2608. If any other SearchControl value is specified, then this buffer
  2609. is used to retrieve the Win32 Find Data for the specified INF.
  2610. SearchControl - Specifies where the INF should be searched for. May
  2611. be one of the following values:
  2612. INFINFO_INF_NAME_IS_ABSOLUTE - Open the specified INF name as-is.
  2613. INFINFO_DEFAULT_SEARCH - Look in INF dir, then System32
  2614. INFINFO_REVERSE_DEFAULT_SEARCH - reverse of the above
  2615. INFINFO_INF_PATH_LIST_SEARCH - search each dir in 'DevicePath' list
  2616. (stored in registry).
  2617. EnumInfCallback - Supplies the address of the callback routine
  2618. to use. The prototype for this callback is as follows:
  2619. typedef BOOL (CALLBACK * InfCacheCallback)(
  2620. IN PSETUP_LOG_CONTEXT LogContext,
  2621. IN PCTSTR InfPath,
  2622. IN PLOADED_INF pInf,
  2623. IN PVOID Context
  2624. );
  2625. The callback routine returns TRUE to continue enumeration,
  2626. or FALSE to abort it (with GetLastError set to ERROR_CANCELLED)
  2627. Context - Supplies the address of a buffer that the callback may
  2628. use to retrieve/return data.
  2629. Return Value:
  2630. If the function succeeds, and the enumeration callback returned
  2631. TRUE (continue enumeration), the return value is NO_ERROR.
  2632. If the function succeeds, and the enumeration callback returned
  2633. FALSE (abort enumeration), the return value is ERROR_CANCELLED.
  2634. If the function fails, the return value is an ERROR_* status code.
  2635. --*/
  2636. {
  2637. TCHAR PathBuffer[MAX_PATH];
  2638. PCTSTR InfFullPath;
  2639. DWORD Err;
  2640. BOOL TryPnf = FALSE;
  2641. PLOADED_INF Inf;
  2642. BOOL PnfWasUsed;
  2643. UINT ErrorLineNumber;
  2644. BOOL Continue;
  2645. if(SearchControl == INFINFO_INF_NAME_IS_ABSOLUTE) {
  2646. InfFullPath = InfName;
  2647. } else {
  2648. //
  2649. // The specified INF name should be searched for based
  2650. // on the SearchControl type.
  2651. //
  2652. if(Err = SearchForInfFile(InfName,
  2653. InfFileData,
  2654. SearchControl,
  2655. PathBuffer,
  2656. SIZECHARS(PathBuffer),
  2657. NULL) != NO_ERROR) {
  2658. return Err;
  2659. } else {
  2660. InfFullPath = PathBuffer;
  2661. }
  2662. }
  2663. //
  2664. // If the 'try pnf' flag isn't set, then we need to examine this particular filename,
  2665. // to see whether it's a pnf candidate.
  2666. //
  2667. if(Context->Flags & DRVSRCH_TRY_PNF) {
  2668. TryPnf = TRUE;
  2669. } else {
  2670. InfSourcePathFromFileName(InfName, NULL, &TryPnf);
  2671. }
  2672. //
  2673. // Attempt to load the INF file. Note that throughout this routine, we don't do any
  2674. // explicit locking of the INF before searching for sections, etc. That's because we
  2675. // know that this INF handle will never be exposed to anyone else, and thus there are
  2676. // no concurrency problems.
  2677. //
  2678. if((Err = LoadInfFile(InfFullPath,
  2679. InfFileData,
  2680. INF_STYLE_WIN4 | ((Context->Flags & DRVSRCH_USEOLDINFS) ? INF_STYLE_OLDNT : 0),
  2681. LDINF_FLAG_IGNORE_VOLATILE_DIRIDS | (TryPnf ? LDINF_FLAG_ALWAYS_TRY_PNF : LDINF_FLAG_MATCH_CLASS_GUID),
  2682. (Context->Flags & DRVSRCH_FILTERCLASS) ? Context->ClassGuidString : NULL,
  2683. NULL,
  2684. NULL,
  2685. NULL,
  2686. LogContext,
  2687. &Inf,
  2688. &ErrorLineNumber,
  2689. &PnfWasUsed)) != NO_ERROR) {
  2690. WriteLogEntry(
  2691. LogContext,
  2692. DRIVER_LOG_ERROR,
  2693. MSG_LOG_COULD_NOT_LOAD_INF,
  2694. NULL,
  2695. InfFullPath);
  2696. return NO_ERROR;
  2697. }
  2698. //
  2699. // Call the supplied callback routine.
  2700. //
  2701. Err = EnumInfCallback(LogContext, InfFullPath, Inf, PnfWasUsed, Context) ? NO_ERROR : GetLastError();
  2702. MYASSERT(Err == NO_ERROR || Err == ERROR_CANCELLED);
  2703. FreeInfFile(Inf);
  2704. return Err;
  2705. }
  2706. DWORD
  2707. EnumDrvInfsInDirPathList(
  2708. IN PCTSTR DirPathList, OPTIONAL
  2709. IN DWORD SearchControl,
  2710. IN InfCacheCallback EnumInfCallback,
  2711. IN BOOL IgnoreNonCriticalErrors,
  2712. IN PSETUP_LOG_CONTEXT LogContext,
  2713. IN OUT PDRVSEARCH_CONTEXT Context
  2714. )
  2715. /*++
  2716. Routine Description:
  2717. This routine enumerates all INFs present in the search list specified
  2718. by SearchControl, using the accelerated search cache
  2719. Arguments:
  2720. DirPathList - Optionally, specifies the search path listing all
  2721. directories to be enumerated. This string may contain multiple
  2722. paths, separated by semicolons (;). If this parameter is not
  2723. specified, then the SearchControl value will determine the
  2724. search path to be used.
  2725. SearchControl - Specifies the set of directories to be enumerated.
  2726. If SearchPath is specified, this parameter is ignored. May be
  2727. one of the following values:
  2728. INFINFO_DEFAULT_SEARCH : enumerate %windir%\inf, then
  2729. %windir%\system32
  2730. INFINFO_REVERSE_DEFAULT_SEARCH : reverse of the above
  2731. INFINFO_INF_PATH_LIST_SEARCH : enumerate INFs in each of the
  2732. directories listed in the DevicePath value entry under:
  2733. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion.
  2734. EnumInfCallback - Supplies the address of the callback routine
  2735. to use. The prototype for this callback is as follows:
  2736. typedef BOOL (CALLBACK * InfCacheCallback)(
  2737. IN PSETUP_LOG_CONTEXT LogContext,
  2738. IN PCTSTR InfPath,
  2739. IN PLOADED_INF pInf,
  2740. IN PVOID Context
  2741. );
  2742. The callback routine returns TRUE to continue enumeration,
  2743. or FALSE to abort it (with GetLastError set to ERROR_CANCELLED)
  2744. IgnoreNonCriticalErrors - If TRUE, then all errors are ignored
  2745. except those that prevent enumeration from continuing.
  2746. Context - Supplies the address of a buffer that the callback may
  2747. use to retrieve/return data.
  2748. Return Value:
  2749. If the function succeeds, and enumeration has not been aborted,
  2750. then the return value is NO_ERROR.
  2751. If the function succeeds, and enumeration has been aborted,
  2752. then the return value is ERROR_CANCELLED.
  2753. If the function fails, the return value is an ERROR_* status code.
  2754. --*/
  2755. {
  2756. DWORD Err = NO_ERROR;
  2757. PCTSTR PathList, CurPath;
  2758. BOOL FreePathList = TRUE;
  2759. DWORD Action;
  2760. PTSTR ClassIdList = NULL;
  2761. PTSTR HwIdList = NULL;
  2762. if(DirPathList) {
  2763. //
  2764. // Use the specified search path(s).
  2765. //
  2766. PathList = GetFullyQualifiedMultiSzPathList(DirPathList);
  2767. } else if(SearchControl == INFINFO_INF_PATH_LIST_SEARCH) {
  2768. //
  2769. // Use our global list of INF search paths.
  2770. //
  2771. PathList = InfSearchPaths;
  2772. FreePathList = FALSE;
  2773. } else {
  2774. //
  2775. // Retrieve the path list.
  2776. //
  2777. PathList = AllocAndReturnDriverSearchList(SearchControl);
  2778. }
  2779. if(!PathList) {
  2780. Err = ERROR_NOT_ENOUGH_MEMORY;
  2781. FreePathList = FALSE;
  2782. goto clean0;
  2783. }
  2784. //
  2785. // If we're doing a non-native driver search, we want to search INFs the
  2786. // old-fashioned way (i.e., sans INF cache).
  2787. //
  2788. if(Context->AltPlatformInfo) {
  2789. Action = INFCACHE_ENUMALL;
  2790. } else {
  2791. Action = INFCACHE_DEFAULT;
  2792. }
  2793. if(Context->Flags & DRVSRCH_TRY_PNF) {
  2794. //
  2795. // TRY_PNF also forces us to build/use cache, except when we're doing
  2796. // non-native driver searching.
  2797. //
  2798. Action |= INFCACHE_FORCE_PNF;
  2799. if(!Context->AltPlatformInfo) {
  2800. Action |= INFCACHE_FORCE_CACHE;
  2801. }
  2802. }
  2803. if(!(Context->Flags & DRVSRCH_USEOLDINFS)) {
  2804. //
  2805. // don't report old inf's
  2806. //
  2807. Action |= INFCACHE_EXC_OLDINFS;
  2808. }
  2809. if (Context->Flags & DRVSRCH_EXCLUDE_OLD_INET_DRIVERS) {
  2810. //
  2811. // exclude old internet INF's from search
  2812. //
  2813. Action |= INFCACHE_EXC_URL;
  2814. }
  2815. Action |= INFCACHE_EXC_NOMANU; // exclude INF's that have no/empty [Manufacturer] section
  2816. Action |= INFCACHE_EXC_NULLCLASS; // exclude INF's that have a ClassGuid = {<nill>}
  2817. Action |= INFCACHE_EXC_NOCLASS; // exclude INF's that don't have class information
  2818. //
  2819. // build class list if needed
  2820. //
  2821. // this must consist of (1) the class GUID (string form)
  2822. // (2) name of class
  2823. // (3) if USEOLDINF's specified, legacy name of class
  2824. //
  2825. if (Context->Flags & DRVSRCH_FILTERCLASS) {
  2826. DWORD len = 2;
  2827. DWORD reqsize;
  2828. TCHAR clsnam[MAX_CLASS_NAME_LEN];
  2829. MYASSERT(Context->ClassGuidString);
  2830. len += 1 + lstrlen(Context->ClassGuidString);
  2831. //
  2832. // Call SetupDiClassNameFromGuid to retrieve the class name
  2833. // corresponding to this class GUID.
  2834. // this allows us to find INF's that list this specific class name
  2835. // but not the GUID, or list this class name but a different GUID
  2836. //
  2837. if(SetupDiClassNameFromGuid(&Context->ClassGuid,
  2838. clsnam,
  2839. SIZECHARS(clsnam),
  2840. NULL) && clsnam[0]) {
  2841. len += 1+lstrlen(clsnam);
  2842. } else {
  2843. clsnam[0]=TEXT('\0');
  2844. }
  2845. if (Context->Flags & DRVSRCH_USEOLDINFS) {
  2846. len += 1 + lstrlen(Context->LegacyClassName);
  2847. }
  2848. ClassIdList = (PTSTR)MyMalloc(len*sizeof(TCHAR));
  2849. if(!ClassIdList) {
  2850. goto clean0;
  2851. }
  2852. len = 0;
  2853. lstrcpy(ClassIdList+len,Context->ClassGuidString);
  2854. len += 1 + lstrlen(ClassIdList+len);
  2855. if(clsnam[0]) {
  2856. lstrcpy(ClassIdList+len,clsnam);
  2857. len += 1 + lstrlen(ClassIdList+len);
  2858. }
  2859. if (Context->Flags & DRVSRCH_USEOLDINFS) {
  2860. lstrcpy(ClassIdList+len,Context->LegacyClassName);
  2861. len += 1 + lstrlen(ClassIdList+len);
  2862. }
  2863. ClassIdList[len++]=TEXT('\0');
  2864. } else {
  2865. MYASSERT(!(Context->Flags & DRVSRCH_USEOLDINFS));
  2866. }
  2867. //
  2868. // build HwIdList if needed
  2869. //
  2870. if (!Context->BuildClassDrvList) {
  2871. DWORD len = 2;
  2872. PLONG pDevIdNum;
  2873. PCTSTR CurDevId;
  2874. int i;
  2875. //
  2876. // first pass, obtain size
  2877. //
  2878. for(i = 0; i < 2; i++) {
  2879. for(pDevIdNum = Context->IdList[i]; *pDevIdNum != -1; pDevIdNum++) {
  2880. //
  2881. // First, obtain the device ID string corresponding to our stored-away
  2882. // string table ID.
  2883. //
  2884. CurDevId = pStringTableStringFromId(Context->StringTable, *pDevIdNum);
  2885. MYASSERT(CurDevId);
  2886. len += 1+lstrlen(CurDevId);
  2887. }
  2888. }
  2889. HwIdList = (PTSTR)MyMalloc(len*sizeof(TCHAR));
  2890. if(!HwIdList) {
  2891. goto clean0;
  2892. }
  2893. //
  2894. // second pass, write list
  2895. //
  2896. len = 0;
  2897. for(i = 0; i < 2; i++) {
  2898. for(pDevIdNum = Context->IdList[i]; *pDevIdNum != -1; pDevIdNum++) {
  2899. //
  2900. // First, obtain the device ID string corresponding to our stored-away
  2901. // string table ID.
  2902. //
  2903. CurDevId = pStringTableStringFromId(Context->StringTable, *pDevIdNum);
  2904. lstrcpy(HwIdList+len,CurDevId);
  2905. len += 1+lstrlen(HwIdList+len);
  2906. }
  2907. }
  2908. HwIdList[len++]=TEXT('\0');
  2909. }
  2910. Err = InfCacheSearchPath(LogContext,
  2911. Action,
  2912. PathList,
  2913. EnumInfCallback,
  2914. Context,
  2915. ClassIdList,
  2916. HwIdList
  2917. );
  2918. clean0:
  2919. if (ClassIdList) {
  2920. MyFree(ClassIdList);
  2921. }
  2922. if (HwIdList) {
  2923. MyFree(HwIdList);
  2924. }
  2925. if(FreePathList) {
  2926. MyFree(PathList);
  2927. }
  2928. if((Err == ERROR_CANCELLED) || !IgnoreNonCriticalErrors) {
  2929. return Err;
  2930. } else {
  2931. return NO_ERROR;
  2932. }
  2933. }
  2934. DWORD
  2935. CreateDriverNode(
  2936. IN UINT Rank,
  2937. IN PCTSTR DevDescription,
  2938. IN PCTSTR DrvDescription,
  2939. IN PCTSTR ProviderName, OPTIONAL
  2940. IN PCTSTR MfgName,
  2941. IN PFILETIME InfDate,
  2942. IN PCTSTR InfFileName,
  2943. IN PCTSTR InfSectionName,
  2944. IN PVOID StringTable,
  2945. IN LONG InfClassGuidIndex,
  2946. OUT PDRIVER_NODE *DriverNode
  2947. )
  2948. /*++
  2949. Routine Description:
  2950. This routine creates a new driver node, and initializes it with
  2951. the supplied information.
  2952. Arguments:
  2953. Rank - The rank match of the driver node being created. This is a
  2954. value in [0..n], where a lower number indicates a higher level of
  2955. compatibility between the driver represented by the node, and the
  2956. device being installed.
  2957. DevDescription - Supplies the description of the device that will be
  2958. supported by this driver.
  2959. DrvDescription - Supplies the description of this driver.
  2960. ProviderName - Supplies the name of the provider of this INF.
  2961. MfgName - Supplies the name of the manufacturer of this device.
  2962. InfDate - Supplies the address of the variable containing the date
  2963. when the INF was last written to.
  2964. InfFileName - Supplies the full name of the INF file for this driver.
  2965. InfSectionName - Supplies the name of the install section in the INF
  2966. that would be used to install this driver.
  2967. StringTable - Supplies the string table that the specified strings are
  2968. to be added to.
  2969. InfClassGuidIndex - Supplies the index into the containing HDEVINFO set's
  2970. GUID table where the class GUID for this INF is stored.
  2971. DriverNode - Supplies the address of a DRIVER_NODE pointer that will
  2972. receive a pointer to the newly-allocated node.
  2973. Return Value:
  2974. If the function succeeds, the return value is NO_ERROR, otherwise the
  2975. ERROR_* code is returned.
  2976. --*/
  2977. {
  2978. PDRIVER_NODE pDriverNode;
  2979. DWORD Err = ERROR_NOT_ENOUGH_MEMORY;
  2980. TCHAR TempString[MAX_PATH]; // an INF path is the longest string we'll store in here.
  2981. //
  2982. // validate the sizes of the strings passed in
  2983. // certain assumptions are made about the strings thoughout
  2984. // but at this point the sizes are not yet within our control
  2985. //
  2986. if((DevDescription && (lstrlen(DevDescription) >= LINE_LEN)) ||
  2987. (DrvDescription && (lstrlen(DrvDescription) >= LINE_LEN)) ||
  2988. (ProviderName && (lstrlen(ProviderName) >= LINE_LEN)) ||
  2989. (MfgName && (lstrlen(MfgName) >= LINE_LEN)) ||
  2990. (InfFileName && (lstrlen(InfFileName) >= MAX_PATH)) ||
  2991. (InfSectionName && (lstrlen(InfSectionName) >= LINE_LEN))
  2992. ) {
  2993. //
  2994. // any of these could potentially cause a buffer overflow later
  2995. // on, so not allowed
  2996. //
  2997. return ERROR_BUFFER_OVERFLOW;
  2998. }
  2999. if(!(pDriverNode = MyMalloc(sizeof(DRIVER_NODE)))) {
  3000. return Err;
  3001. }
  3002. //
  3003. // Initialize the various fields in the driver node structure.
  3004. //
  3005. ZeroMemory(pDriverNode, sizeof(DRIVER_NODE));
  3006. pDriverNode->Rank = Rank;
  3007. pDriverNode->InfDate = *InfDate;
  3008. pDriverNode->HardwareId = -1;
  3009. pDriverNode->GuidIndex = InfClassGuidIndex;
  3010. //
  3011. // Now, add the strings to the associated string table, and store the string IDs.
  3012. //
  3013. // Cast the DrvDescription string being added case-sensitively as PTSTR instead of PCTSTR.
  3014. // Case sensitive string additions don't modify the buffer passed in, so we're safe in
  3015. // doing so.
  3016. //
  3017. if((pDriverNode->DrvDescription = pStringTableAddString(StringTable,
  3018. (PTSTR)DrvDescription,
  3019. STRTAB_CASE_SENSITIVE,
  3020. NULL,0)) == -1) {
  3021. goto clean0;
  3022. }
  3023. //
  3024. // For DevDescription, ProviderName, and MfgName, we use the string table IDs to do fast
  3025. // comparisons for driver nodes. Thus, we need to store case-insensitive IDs. However,
  3026. // these strings are also used for display, so we have to store them in their case-sensitive
  3027. // form as well.
  3028. //
  3029. // We must first copy the strings into a modifiable buffer, since we're going to need to add
  3030. // them case-insensitively.
  3031. //
  3032. lstrcpyn(TempString, DevDescription, SIZECHARS(TempString));
  3033. if((pDriverNode->DevDescriptionDisplayName = pStringTableAddString(StringTable,
  3034. TempString,
  3035. STRTAB_CASE_SENSITIVE,
  3036. NULL,0)) == -1) {
  3037. goto clean0;
  3038. }
  3039. if((pDriverNode->DevDescription = pStringTableAddString(
  3040. StringTable,
  3041. TempString,
  3042. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  3043. NULL,0)) == -1) {
  3044. goto clean0;
  3045. }
  3046. if(ProviderName) {
  3047. lstrcpyn(TempString, ProviderName, SIZECHARS(TempString));
  3048. if((pDriverNode->ProviderDisplayName = pStringTableAddString(
  3049. StringTable,
  3050. TempString,
  3051. STRTAB_CASE_SENSITIVE,
  3052. NULL,0)) == -1) {
  3053. goto clean0;
  3054. }
  3055. if((pDriverNode->ProviderName = pStringTableAddString(
  3056. StringTable,
  3057. TempString,
  3058. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  3059. NULL,0)) == -1) {
  3060. goto clean0;
  3061. }
  3062. } else {
  3063. pDriverNode->ProviderName = pDriverNode->ProviderDisplayName = -1;
  3064. }
  3065. lstrcpyn(TempString, MfgName, SIZECHARS(TempString));
  3066. if((pDriverNode->MfgDisplayName = pStringTableAddString(StringTable,
  3067. TempString,
  3068. STRTAB_CASE_SENSITIVE,
  3069. NULL,0)) == -1) {
  3070. goto clean0;
  3071. }
  3072. if((pDriverNode->MfgName = pStringTableAddString(
  3073. StringTable,
  3074. TempString,
  3075. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  3076. NULL,0)) == -1) {
  3077. goto clean0;
  3078. }
  3079. lstrcpyn(TempString, InfFileName, SIZECHARS(TempString));
  3080. if((pDriverNode->InfFileName = pStringTableAddString(
  3081. StringTable,
  3082. TempString,
  3083. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  3084. NULL,0)) == -1) {
  3085. goto clean0;
  3086. }
  3087. //
  3088. // Add INF section name case-sensitively, since we may have a legacy driver node, which requires
  3089. // that the original case be maintained.
  3090. //
  3091. if((pDriverNode->InfSectionName = pStringTableAddString(StringTable,
  3092. (PTSTR)InfSectionName,
  3093. STRTAB_CASE_SENSITIVE,
  3094. NULL,0)) == -1) {
  3095. goto clean0;
  3096. }
  3097. //
  3098. // If we get to here, then we've successfully stored all strings.
  3099. //
  3100. Err = NO_ERROR;
  3101. clean0:
  3102. if(Err == NO_ERROR) {
  3103. *DriverNode = pDriverNode;
  3104. } else {
  3105. DestroyDriverNodes(pDriverNode, (PDEVICE_INFO_SET)NULL);
  3106. }
  3107. return Err;
  3108. }
  3109. BOOL
  3110. pRemoveDirectory(
  3111. PTSTR Path
  3112. )
  3113. /*++
  3114. Routine Description:
  3115. This routine recursively deletes the specified directory and all the
  3116. files in it.
  3117. Arguments:
  3118. Path - Path to remove.
  3119. Return Value:
  3120. TRUE - if the directory was sucessfully deleted.
  3121. FALSE - if the directory was not successfully deleted.
  3122. --*/
  3123. {
  3124. WIN32_FIND_DATA FindFileData;
  3125. HANDLE hFind;
  3126. BOOL bFind = TRUE;
  3127. BOOL Ret = TRUE;
  3128. TCHAR szTemp[MAX_PATH];
  3129. TCHAR FindPath[MAX_PATH];
  3130. DWORD dwAttributes;
  3131. //
  3132. //If this is a directory then tack on *.* to the end of the path
  3133. //
  3134. lstrcpyn(FindPath, Path,SIZECHARS(FindPath));
  3135. dwAttributes = GetFileAttributes(Path);
  3136. if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  3137. pSetupConcatenatePaths(FindPath,TEXT("*.*"),SIZECHARS(FindPath),NULL);
  3138. }
  3139. hFind = FindFirstFile(FindPath, &FindFileData);
  3140. while (hFind != INVALID_HANDLE_VALUE && bFind == TRUE) {
  3141. lstrcpyn(szTemp, Path,SIZECHARS(szTemp));
  3142. pSetupConcatenatePaths(szTemp,FindFileData.cFileName,SIZECHARS(szTemp),NULL);
  3143. //
  3144. //This is a directory
  3145. //
  3146. if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  3147. (FindFileData.cFileName[0] != TEXT('.'))) {
  3148. if (!pRemoveDirectory(szTemp)) {
  3149. Ret = FALSE;
  3150. }
  3151. RemoveDirectory(szTemp);
  3152. }
  3153. //
  3154. //This is a file
  3155. //
  3156. else if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  3157. DeleteFile(szTemp);
  3158. }
  3159. bFind = FindNextFile(hFind, &FindFileData);
  3160. }
  3161. FindClose(hFind);
  3162. //
  3163. //Remove the root directory
  3164. //
  3165. dwAttributes = GetFileAttributes(Path);
  3166. if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  3167. if (!RemoveDirectory(Path)) {
  3168. Ret = FALSE;
  3169. }
  3170. }
  3171. return Ret;
  3172. }
  3173. BOOL
  3174. RemoveCDMDirectory(
  3175. IN PTSTR FullPathName
  3176. )
  3177. /*++
  3178. Routine Description:
  3179. This routine deletes the Code Download Manager temporary directory. It will
  3180. only delete the directory and all of it's contents if:
  3181. 1) it is a subdirectory of the Windows TEMP directory.
  3182. Note that we also assume that this is a full path (including a filename at the end).
  3183. We will strip off the filename and remove the entire directory where this INF file
  3184. is located.
  3185. Arguments:
  3186. FullPathName - Full path to the directory that might be deleted.
  3187. Return Value:
  3188. TRUE - if the directory was sucessfully deleted.
  3189. FALSE - if the directory was not successfully deleted.
  3190. --*/
  3191. {
  3192. TCHAR Directory[MAX_PATH];
  3193. TCHAR TempPath[MAX_PATH];
  3194. PTSTR FileName;
  3195. //
  3196. //First stip off the file name so we are just left with the directory.
  3197. //
  3198. lstrcpyn(Directory, FullPathName,SIZECHARS(Directory));
  3199. if ((FileName = (PTSTR)pSetupGetFileTitle((PCTSTR)Directory))) {
  3200. *FileName = TEXT('\0');
  3201. }
  3202. if (Directory[0] == TEXT('\0')) {
  3203. return FALSE;
  3204. }
  3205. if (GetTempPath(SIZECHARS(TempPath), TempPath) == 0) {
  3206. lstrcpy(TempPath, TEXT("UNKNOWN"));
  3207. }
  3208. //
  3209. // Only remove this directory if it is a subdirectory of the TEMP path
  3210. //
  3211. if (_tcsnicmp(TempPath, Directory, sizeof(TempPath) / sizeof(TCHAR))) {
  3212. //
  3213. //Remove the directory
  3214. //
  3215. return pRemoveDirectory(Directory);
  3216. } else {
  3217. TCHAR Debug[512];
  3218. wsprintf(Debug, TEXT("SETUPAPI: RemoveCDMDirectory(%s) -> bogus path\n"), FullPathName);
  3219. DebugPrintEx(DPFLTR_ERROR_LEVEL, Debug);
  3220. MYASSERT (FALSE);
  3221. }
  3222. return FALSE;
  3223. }
  3224. VOID
  3225. DestroyDriverNodes(
  3226. IN PDRIVER_NODE DriverNode,
  3227. IN PDEVICE_INFO_SET pDeviceInfoSet
  3228. )
  3229. /*++
  3230. Routine Description:
  3231. This routine destroys the specified driver node linked list, freeing
  3232. all resources associated with it.
  3233. Arguments:
  3234. DriverNode - Supplies a pointer to the head of the driver node linked
  3235. list to be destroyed.
  3236. Return Value:
  3237. None.
  3238. --*/
  3239. {
  3240. PDRIVER_NODE NextNode;
  3241. PTSTR szInfFileName = NULL;
  3242. while(DriverNode) {
  3243. NextNode = DriverNode->Next;
  3244. if(DriverNode->CompatIdList) {
  3245. MyFree(DriverNode->CompatIdList);
  3246. }
  3247. //
  3248. // If this driver was from the Internet then we want to delete the directory where
  3249. // it lives.
  3250. //
  3251. if (pDeviceInfoSet && (DriverNode->Flags & PDNF_CLEANUP_SOURCE_PATH)) {
  3252. szInfFileName = NULL;
  3253. szInfFileName = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  3254. DriverNode->InfFileName);
  3255. if (*szInfFileName) {
  3256. RemoveCDMDirectory(szInfFileName);
  3257. }
  3258. }
  3259. MyFree(DriverNode);
  3260. DriverNode = NextNode;
  3261. }
  3262. }
  3263. PTSTR
  3264. GetFullyQualifiedMultiSzPathList(
  3265. IN PCTSTR PathList
  3266. )
  3267. /*++
  3268. Routine Description:
  3269. This routine takes a list of semicolon-delimited directory paths, and returns a
  3270. newly-allocated buffer containing a multi-sz list of those paths, fully qualified.
  3271. The buffer returned from this routine must be freed with MyFree().
  3272. Arguments:
  3273. PathList - list of directories to be converted.
  3274. Return Value:
  3275. If the function succeeds, the return value is a pointer to the allocated buffer
  3276. containing the multi-sz list.
  3277. If failure (due to out-of-memory), the return value is NULL.
  3278. --*/
  3279. {
  3280. TCHAR PathListBuffer[MAX_PATH + 1]; // extra char 'cause this is a multi-sz list
  3281. PTSTR CurPath, CharPos, NewBuffer, TempPtr;
  3282. DWORD RequiredSize;
  3283. //
  3284. // First, convert this semicolon-delimited list into a multi-sz list.
  3285. //
  3286. lstrcpyn(PathListBuffer, PathList,SIZECHARS(PathListBuffer));
  3287. RequiredSize = DelimStringToMultiSz(PathListBuffer,
  3288. SIZECHARS(PathListBuffer),
  3289. TEXT(';')
  3290. );
  3291. RequiredSize = (RequiredSize * MAX_PATH * sizeof(TCHAR)) + sizeof(TCHAR);
  3292. if(!(NewBuffer = MyMalloc(RequiredSize * sizeof(TCHAR)))) {
  3293. return NULL;
  3294. }
  3295. //
  3296. // Now fill in the buffer with the fully-qualified directory paths.
  3297. //
  3298. CharPos = NewBuffer;
  3299. for(CurPath = PathListBuffer; *CurPath; CurPath += (lstrlen(CurPath) + 1)) {
  3300. RequiredSize = GetFullPathName(CurPath,
  3301. MAX_PATH,
  3302. CharPos,
  3303. &TempPtr
  3304. );
  3305. if(!RequiredSize || (RequiredSize >= MAX_PATH)) {
  3306. //
  3307. // If we start failing because MAX_PATH isn't big enough anymore, we
  3308. // wanna know about it!
  3309. //
  3310. MYASSERT(RequiredSize < MAX_PATH);
  3311. MyFree(NewBuffer);
  3312. return NULL;
  3313. }
  3314. CharPos += (RequiredSize + 1);
  3315. }
  3316. *(CharPos++) = TEXT('\0'); // add extra NULL to terminate the multi-sz list.
  3317. //
  3318. // Trim this buffer down to just the size required (this should never fail, but
  3319. // it's no big deal if it does).
  3320. //
  3321. if(TempPtr = MyRealloc(NewBuffer, (DWORD)((PBYTE)CharPos - (PBYTE)NewBuffer))) {
  3322. return TempPtr;
  3323. }
  3324. return NewBuffer;
  3325. }
  3326. BOOL
  3327. InitMiniIconList(
  3328. VOID
  3329. )
  3330. /*++
  3331. Routine Description:
  3332. This routine initializes the global mini-icon list, including setting up
  3333. the synchronization lock. When this global structure is no longer needed,
  3334. DestroyMiniIconList must be called.
  3335. Arguments:
  3336. None.
  3337. Return Value:
  3338. If the function succeeds, the return value is TRUE, otherwise it is FALSE.
  3339. --*/
  3340. {
  3341. ZeroMemory(&GlobalMiniIconList, sizeof(MINI_ICON_LIST));
  3342. return InitializeSynchronizedAccess(&GlobalMiniIconList.Lock);
  3343. }
  3344. BOOL
  3345. DestroyMiniIconList(
  3346. VOID
  3347. )
  3348. /*++
  3349. Routine Description:
  3350. This routine destroys the global mini-icon list created by a call to
  3351. InitMiniIconList.
  3352. Arguments:
  3353. None.
  3354. Return Value:
  3355. If the function succeeds, the return value is TRUE, otherwise it is FALSE.
  3356. --*/
  3357. {
  3358. if(LockMiniIconList(&GlobalMiniIconList)) {
  3359. DestroyMiniIcons();
  3360. DestroySynchronizedAccess(&GlobalMiniIconList.Lock);
  3361. return TRUE;
  3362. }
  3363. return FALSE;
  3364. }
  3365. DWORD
  3366. GetModuleEntryPoint(
  3367. IN HKEY hk, OPTIONAL
  3368. IN LPCTSTR RegistryValue,
  3369. IN LPCTSTR DefaultProcName,
  3370. OUT HINSTANCE *phinst,
  3371. OUT FARPROC *pEntryPoint,
  3372. OUT HANDLE *pFusionContext,
  3373. OUT BOOL *pMustAbort, OPTIONAL
  3374. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  3375. IN HWND Owner, OPTIONAL
  3376. IN CONST GUID *DeviceSetupClassGuid, OPTIONAL
  3377. IN SetupapiVerifyProblem Problem,
  3378. IN LPCTSTR DeviceDesc, OPTIONAL
  3379. IN DWORD DriverSigningPolicy,
  3380. IN DWORD NoUI,
  3381. IN OUT HCATADMIN *hCatAdmin OPTIONAL
  3382. )
  3383. /*++
  3384. Routine Description:
  3385. This routine is used to retrieve the procedure address of a specified
  3386. function in a specified module.
  3387. Arguments:
  3388. hk - Optionally, supplies an open registry key that contains a value entry
  3389. specifying the module (and optionally, the entry point) to be retrieved.
  3390. If this parameter is not specified (set to INVALID_HANDLE_VALUE), then
  3391. the RegistryValue parameter is interpreted as the data itself, instead
  3392. of the value containing the entry.
  3393. RegistryValue - If hk is supplied, this specifies the name of the registry
  3394. value that contains the module and entry point information. Otherwise,
  3395. it contains the actual data specifying the module/entry point to be
  3396. used.
  3397. DefaultProcName - Supplies the name of a default procedure to use if one
  3398. is not specified in the registry value.
  3399. phinst - Supplies the address of a variable that receives a handle to the
  3400. specified module, if it is successfully loaded and the entry point found.
  3401. pEntryPoint - Supplies the address of a function pointer that receives the
  3402. specified entry point in the loaded module.
  3403. pFusionContext - Supplies a handle to a fusion context for the dll
  3404. if the dll has a manifest, NULL otherwise.
  3405. pMustAbort - Optionally, supplies the address of a boolean variable that is
  3406. set upon return to indicate whether a failure (i.e., return code other
  3407. than NO_ERROR) should abort the device installer action underway. This
  3408. variable is always set to FALSE when the function succeeds.
  3409. If this argument is not supplied, then the arguments below are ignored.
  3410. LogContext - Optionally, supplies the log context to be used when logging
  3411. entries into the setupapi logfile. Not used if pMustAbort isn't
  3412. specified.
  3413. Owner - Optionally, supplies window to own driver signing dialogs, if any.
  3414. Not used if pMustAbort isn't specified.
  3415. DeviceSetupClassGuid - Optionally, supplies the address of a GUID that
  3416. indicates the device setup class associated with this operation. This
  3417. is used for retrieval of validation platform information, as well as
  3418. for retrieval of the DeviceDesc to be used for driver signing errors
  3419. (if the caller doesn't specify a DeviceDesc). Not used if pMustAbort
  3420. isn't specified.
  3421. Problem - Supplies the problem type to use if driver signing error occurs.
  3422. Not used if pMustAbort isn't specified.
  3423. DeviceDesc - Optionally, supplies the device description to use if driver
  3424. signing error occurs. Not used if pMustAbort isn't specified.
  3425. DriverSigningPolicy - Supplies policy to be employed if a driver signing
  3426. error is encountered. Not used if pMustAbort isn't specified.
  3427. NoUI - Set to true if driver signing popups are to be suppressed (e.g.,
  3428. because the user has previously responded to a warning dialog and
  3429. elected to proceed. Not used if pMustAbort isn't specified.
  3430. hCatAdmin - optionally, supplies the address of an HCATADMIN handle. If
  3431. the handle pointed to is NULL, a handle will be acquired (if possible)
  3432. via CryptCATAdminAcquireContext and returned to the caller. If the
  3433. handle pointed to is non-NULL, then that handle will be used for any
  3434. validation done via this routine. If the pointer itself is NULL, then
  3435. an hCatAdmin will be acquired for the duration of this call, and
  3436. released before returning.
  3437. NOTE: it is the caller's responsibility to free the crypto context
  3438. handle returned by this routine by calling CryptCATAdminReleaseContext.
  3439. This handle may be opened in either success or failure cases, so the
  3440. caller must check for non-NULL returned handle in both cases.
  3441. Return Value:
  3442. If the function succeeds, the return value is NO_ERROR.
  3443. If the specified value entry could not be found, the return value is
  3444. ERROR_DI_DO_DEFAULT.
  3445. If any other error is encountered, an ERROR_* code is returned.
  3446. Remarks:
  3447. This function is useful for loading a class installer or property provider,
  3448. and receiving the procedure address specified. The syntax of the registry
  3449. entry is: value=dll[,proc name] where dll is the name of the module to load,
  3450. and proc name is an optional procedure to search for. If proc name is not
  3451. specified, the procedure specified by DefaultProcName will be used.
  3452. --*/
  3453. {
  3454. DWORD Err = ERROR_INVALID_DATA; // relevent only if we execute 'finally' due to exception
  3455. DWORD RegDataType, BufferSize;
  3456. TCHAR TempBuffer[MAX_PATH];
  3457. TCHAR ModulePath[MAX_PATH];
  3458. SPFUSIONINSTANCE spFusionInstance;
  3459. #if UNICODE
  3460. //
  3461. // this used to be ModulePath reused... to reduce chance of breaking anything, kept size the same
  3462. // I've seperated this out as we want ModulePath for logging
  3463. //
  3464. CHAR ProcBuffer[MAX_PATH*sizeof(TCHAR)];
  3465. #endif
  3466. PTSTR StringPtr;
  3467. PSTR ProcName; // ANSI-only, because it's used for GetProcAddress.
  3468. PSP_ALTPLATFORM_INFO_V2 ValidationPlatform;
  3469. PTSTR LocalDeviceDesc;
  3470. *phinst = NULL;
  3471. *pEntryPoint = NULL;
  3472. *pFusionContext = NULL;
  3473. if(pMustAbort) {
  3474. *pMustAbort = FALSE;
  3475. }
  3476. if(hk != INVALID_HANDLE_VALUE) {
  3477. //
  3478. // See if the specified value entry is present (and of the right data type).
  3479. //
  3480. BufferSize = sizeof(TempBuffer);
  3481. if((RegQueryValueEx(hk,
  3482. RegistryValue,
  3483. NULL,
  3484. &RegDataType,
  3485. (PBYTE)TempBuffer,
  3486. &BufferSize) != ERROR_SUCCESS) ||
  3487. (RegDataType != REG_SZ)) {
  3488. return ERROR_DI_DO_DEFAULT;
  3489. }
  3490. } else {
  3491. //
  3492. // Copy the specified data into the buffer as if we'd just retrieved it from
  3493. // the registry.
  3494. //
  3495. BufferSize = (lstrlen(RegistryValue) + 1) * sizeof(TCHAR);
  3496. CopyMemory(TempBuffer, RegistryValue, BufferSize);
  3497. }
  3498. lstrcpyn(ModulePath, SystemDirectory, MAX_PATH);
  3499. //
  3500. // Find the beginning of the entry point name, if present.
  3501. //
  3502. for(StringPtr = TempBuffer + ((BufferSize / sizeof(TCHAR)) - 2);
  3503. StringPtr >= TempBuffer;
  3504. StringPtr--) {
  3505. if(*StringPtr == TEXT(',')) {
  3506. *(StringPtr++) = TEXT('\0');
  3507. break;
  3508. }
  3509. //
  3510. // If we hit a double-quote mark, then set the character pointer
  3511. // to the beginning of the string so we'll terminate the search.
  3512. //
  3513. if(*StringPtr == TEXT('\"')) {
  3514. StringPtr = TempBuffer;
  3515. }
  3516. }
  3517. if(StringPtr > TempBuffer) {
  3518. //
  3519. // We encountered a comma in the string. Scan forward from that point
  3520. // to ensure that there aren't any leading spaces in the entry point
  3521. // name.
  3522. //
  3523. for(; (*StringPtr && IsWhitespace(StringPtr)); StringPtr++);
  3524. if(!(*StringPtr)) {
  3525. //
  3526. // Then there was no entry point given after all.
  3527. //
  3528. StringPtr = TempBuffer;
  3529. }
  3530. }
  3531. pSetupConcatenatePaths(ModulePath, TempBuffer, MAX_PATH, NULL);
  3532. //
  3533. // If requested, check the digital signature of this module before loading
  3534. // it.
  3535. //
  3536. if(pMustAbort) {
  3537. //
  3538. // Retrieve validation information relevant to this device setup class.
  3539. //
  3540. LocalDeviceDesc = NULL;
  3541. IsInfForDeviceInstall(LogContext,
  3542. DeviceSetupClassGuid,
  3543. NULL,
  3544. DeviceDesc ? NULL : &LocalDeviceDesc,
  3545. &ValidationPlatform,
  3546. NULL,
  3547. NULL
  3548. );
  3549. Err = _VerifyFile(LogContext,
  3550. hCatAdmin,
  3551. NULL,
  3552. NULL,
  3553. NULL,
  3554. 0,
  3555. pSetupGetFileTitle(ModulePath),
  3556. ModulePath,
  3557. NULL,
  3558. NULL,
  3559. FALSE,
  3560. ValidationPlatform,
  3561. (VERIFY_FILE_USE_OEM_CATALOGS | VERIFY_FILE_NO_DRIVERBLOCKED_CHECK),
  3562. NULL,
  3563. NULL,
  3564. NULL,
  3565. NULL
  3566. );
  3567. if(Err != NO_ERROR) {
  3568. if(!pSetupHandleFailedVerification(Owner,
  3569. Problem,
  3570. ModulePath,
  3571. DeviceDesc ? DeviceDesc : LocalDeviceDesc,
  3572. DriverSigningPolicy,
  3573. NoUI,
  3574. Err,
  3575. LogContext,
  3576. NULL,
  3577. NULL)) {
  3578. //
  3579. // The operation should be aborted.
  3580. //
  3581. *pMustAbort = TRUE;
  3582. }
  3583. }
  3584. //
  3585. // Free buffers we may have retrieved when calling
  3586. // IsInfForDeviceInstall().
  3587. //
  3588. if(LocalDeviceDesc) {
  3589. MyFree(LocalDeviceDesc);
  3590. }
  3591. if(ValidationPlatform) {
  3592. MyFree(ValidationPlatform);
  3593. }
  3594. if(*pMustAbort) {
  3595. MYASSERT(Err != NO_ERROR);
  3596. return Err;
  3597. }
  3598. }
  3599. try {
  3600. *pFusionContext = spFusionContextFromModule(ModulePath);
  3601. spFusionEnterContext(*pFusionContext,&spFusionInstance);
  3602. if(!(*phinst = LoadLibrary(ModulePath))) {
  3603. Err = GetLastError();
  3604. if (LogContext) {
  3605. WriteLogEntry(
  3606. LogContext,
  3607. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  3608. MSG_LOG_MOD_LOADFAIL_ERROR,
  3609. NULL,
  3610. ModulePath);
  3611. WriteLogError(
  3612. LogContext,
  3613. DRIVER_LOG_ERROR,
  3614. Err);
  3615. }
  3616. leave;
  3617. }
  3618. //
  3619. // We've successfully loaded the module, now get the entry point.
  3620. // (GetProcAddress is an ANSI-only API, so if we're compiled UNICODE,
  3621. // we have to convert the proc name to ANSI here.
  3622. //
  3623. #ifdef UNICODE
  3624. ProcName = ProcBuffer;
  3625. #endif
  3626. if(StringPtr > TempBuffer) {
  3627. //
  3628. // An entry point was specified in the value entry--use it instead
  3629. // of the default provided.
  3630. //
  3631. #ifdef UNICODE
  3632. WideCharToMultiByte(CP_ACP,
  3633. 0,
  3634. StringPtr,
  3635. -1,
  3636. ProcName,
  3637. sizeof(ProcBuffer),
  3638. NULL,
  3639. NULL
  3640. );
  3641. #else // !UNICODE
  3642. ProcName = StringPtr;
  3643. #endif // !UNICODE
  3644. } else {
  3645. //
  3646. // No entry point was specified--use default.
  3647. //
  3648. #ifdef UNICODE
  3649. WideCharToMultiByte(CP_ACP,
  3650. 0,
  3651. DefaultProcName,
  3652. -1,
  3653. ProcName,
  3654. sizeof(ProcBuffer),
  3655. NULL,
  3656. NULL
  3657. );
  3658. #else // !UNICODE
  3659. ProcName = (PSTR)DefaultProcName;
  3660. #endif // !UNICODE
  3661. }
  3662. if(!(*pEntryPoint = (FARPROC)GetProcAddress(*phinst, ProcName))) {
  3663. Err = GetLastError();
  3664. FreeLibrary(*phinst);
  3665. *phinst = NULL;
  3666. if (LogContext) {
  3667. WriteLogEntry(
  3668. LogContext,
  3669. DRIVER_LOG_ERROR | SETUP_LOG_BUFFER,
  3670. MSG_LOG_MOD_PROCFAIL_ERROR,
  3671. NULL,
  3672. ModulePath,
  3673. (StringPtr > TempBuffer ? StringPtr : DefaultProcName));
  3674. WriteLogError(
  3675. LogContext,
  3676. DRIVER_LOG_ERROR,
  3677. Err);
  3678. }
  3679. leave;
  3680. }
  3681. if (LogContext) {
  3682. WriteLogEntry(
  3683. LogContext,
  3684. DRIVER_LOG_VERBOSE1,
  3685. MSG_LOG_MOD_LIST_PROC,
  3686. NULL,
  3687. ModulePath,
  3688. (StringPtr > TempBuffer ? StringPtr : DefaultProcName));
  3689. }
  3690. Err = NO_ERROR;
  3691. } finally {
  3692. if(Err && *phinst) {
  3693. FreeLibrary(*phinst);
  3694. *phinst = NULL;
  3695. }
  3696. spFusionLeaveContext(&spFusionInstance);
  3697. if(Err != NO_ERROR) {
  3698. spFusionKillContext(*pFusionContext);
  3699. *pFusionContext = NULL;
  3700. }
  3701. }
  3702. return Err;
  3703. }
  3704. DWORD
  3705. pSetupGuidFromString(
  3706. IN PCTSTR GuidString,
  3707. OUT LPGUID Guid
  3708. )
  3709. /*++
  3710. Routine Description:
  3711. This routine converts the character representation of a GUID into its binary
  3712. form (a GUID struct). The GUID is in the following form:
  3713. {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
  3714. where 'x' is a hexadecimal digit.
  3715. Arguments:
  3716. GuidString - Supplies a pointer to the null-terminated GUID string. The
  3717. Guid - Supplies a pointer to the variable that receives the GUID structure.
  3718. Return Value:
  3719. If the function succeeds, the return value is NO_ERROR.
  3720. If the function fails, the return value is RPC_S_INVALID_STRING_UUID.
  3721. --*/
  3722. {
  3723. TCHAR UuidBuffer[GUID_STRING_LEN - 1];
  3724. //
  3725. // Since we're using a RPC UUID routine, we need to strip off the surrounding
  3726. // curly braces first.
  3727. //
  3728. if(*GuidString++ != TEXT('{')) {
  3729. return RPC_S_INVALID_STRING_UUID;
  3730. }
  3731. lstrcpyn(UuidBuffer, GuidString, SIZECHARS(UuidBuffer));
  3732. if((lstrlen(UuidBuffer) != GUID_STRING_LEN - 2) ||
  3733. (UuidBuffer[GUID_STRING_LEN - 3] != TEXT('}'))) {
  3734. return RPC_S_INVALID_STRING_UUID;
  3735. }
  3736. UuidBuffer[GUID_STRING_LEN - 3] = TEXT('\0');
  3737. return ((UuidFromString(UuidBuffer, Guid) == RPC_S_OK) ? NO_ERROR : RPC_S_INVALID_STRING_UUID);
  3738. }
  3739. DWORD
  3740. pSetupStringFromGuid(
  3741. IN CONST GUID *Guid,
  3742. OUT PTSTR GuidString,
  3743. IN DWORD GuidStringSize
  3744. )
  3745. /*++
  3746. Routine Description:
  3747. This routine converts a GUID into a null-terminated string which represents
  3748. it. This string is of the form:
  3749. {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
  3750. where x represents a hexadecimal digit.
  3751. This routine comes from ole32\common\ccompapi.cxx. It is included here to avoid linking
  3752. to ole32.dll. (The RPC version allocates memory, so it was avoided as well.)
  3753. Arguments:
  3754. Guid - Supplies a pointer to the GUID whose string representation is
  3755. to be retrieved.
  3756. GuidString - Supplies a pointer to character buffer that receives the
  3757. string. This buffer must be _at least_ 39 (GUID_STRING_LEN) characters
  3758. long.
  3759. Return Value:
  3760. If success, the return value is NO_ERROR.
  3761. if failure, the return value is
  3762. --*/
  3763. {
  3764. CONST BYTE *GuidBytes;
  3765. INT i;
  3766. if(GuidStringSize < GUID_STRING_LEN) {
  3767. return ERROR_INSUFFICIENT_BUFFER;
  3768. }
  3769. GuidBytes = (CONST BYTE *)Guid;
  3770. *GuidString++ = TEXT('{');
  3771. for(i = 0; i < sizeof(GuidMap); i++) {
  3772. if(GuidMap[i] == '-') {
  3773. *GuidString++ = TEXT('-');
  3774. } else {
  3775. *GuidString++ = szDigits[ (GuidBytes[GuidMap[i]] & 0xF0) >> 4 ];
  3776. *GuidString++ = szDigits[ (GuidBytes[GuidMap[i]] & 0x0F) ];
  3777. }
  3778. }
  3779. *GuidString++ = TEXT('}');
  3780. *GuidString = TEXT('\0');
  3781. return NO_ERROR;
  3782. }
  3783. BOOL
  3784. pSetupIsGuidNull(
  3785. IN CONST GUID *Guid
  3786. )
  3787. {
  3788. return IsEqualGUID(Guid, &GUID_NULL);
  3789. }
  3790. VOID
  3791. GetRegSubkeysFromDeviceInterfaceName(
  3792. IN OUT PTSTR DeviceInterfaceName,
  3793. OUT PTSTR *SubKeyName
  3794. )
  3795. /*++
  3796. Routine Description:
  3797. This routine breaks up a device interface path into 2 parts--the symbolic link
  3798. name and the (optional) reference string. It then munges the symbolic link
  3799. name part into the subkey name as it appears under the interface class key.
  3800. NOTE: The algorithm for parsing the device interface name must be kept in sync
  3801. with the kernel-mode implementation of IoOpenDeviceInterfaceRegistryKey.
  3802. Arguments:
  3803. DeviceInterfaceName - Supplies the name of the device interface to be parsed
  3804. into registry subkey names. Upon return, this name will have been terminated
  3805. at the backslash preceding the reference string (if there is one), and all
  3806. backslashes will have been replaced with '#' characters.
  3807. SubKeyName - Supplies the address of a character pointer that receives the
  3808. address of the reference string (within the DeviceInterfaceName string).
  3809. If there is no reference string, this parameter will be filled in with NULL.
  3810. Return Value:
  3811. none
  3812. --*/
  3813. {
  3814. PTSTR p;
  3815. //
  3816. // Scan across the name to find the beginning of the refstring component (if
  3817. // there is one). The format of the symbolic link name is:
  3818. //
  3819. // \\?\munged_name[\refstring]
  3820. //
  3821. MYASSERT(DeviceInterfaceName[0] == TEXT('\\'));
  3822. MYASSERT(DeviceInterfaceName[1] == TEXT('\\'));
  3823. //
  3824. // Allow both '\\.\' and '\\?\' for now, since Memphis currently uses the former.
  3825. //
  3826. MYASSERT((DeviceInterfaceName[2] == TEXT('?')) || (DeviceInterfaceName[2] == TEXT('.')));
  3827. MYASSERT(DeviceInterfaceName[3] == TEXT('\\'));
  3828. p = _tcschr(&(DeviceInterfaceName[4]), TEXT('\\'));
  3829. if(p) {
  3830. *p = TEXT('\0');
  3831. *SubKeyName = p + 1;
  3832. } else {
  3833. *SubKeyName = NULL;
  3834. }
  3835. for(p = DeviceInterfaceName; *p; p++) {
  3836. if(*p == TEXT('\\')) {
  3837. *p = TEXT('#');
  3838. }
  3839. }
  3840. }
  3841. LONG
  3842. OpenDeviceInterfaceSubKey(
  3843. IN HKEY hKeyInterfaceClass,
  3844. IN PCTSTR DeviceInterfaceName,
  3845. IN REGSAM samDesired,
  3846. OUT PHKEY phkResult,
  3847. OUT PTSTR OwningDevInstName, OPTIONAL
  3848. IN OUT PDWORD OwningDevInstNameSize OPTIONAL
  3849. )
  3850. /*++
  3851. Routine Description:
  3852. This routine munges the specified device interface symbolic link name into
  3853. a subkey name that is then opened underneath the specified interface class key.
  3854. NOTE: This munging algorithm must be kept in sync with the kernel-mode routines
  3855. that generate these keys (e.g., IoRegisterDeviceInterface).
  3856. Arguments:
  3857. hKeyInterfaceClass - Supplies the handle of the currently-open interface class key
  3858. under which the device interface subkey is to be opened.
  3859. DeviceInterfaceName - Supplies the symbolic link name ('\\?\' form) of the device
  3860. interface for which the subkey is to be opened.
  3861. samDesired - Specifies the access desired on the key to be opened.
  3862. phkResult - Supplies the address of a variable that receives the registry handle,
  3863. if successfully opened.
  3864. OwningDevInstName - Optionally, supplies a character buffer that receives the name
  3865. of the device instance that owns this interface.
  3866. OwningDevInstNameSize - Optionally, supplies the address of a variable that, on input,
  3867. contains the size of the OwningDevInstName buffer (in bytes). Upon return, it
  3868. receives that actual number of bytes stored in OwningDevInstName (including
  3869. terminating NULL).
  3870. Return Value:
  3871. If success, the return value is ERROR_SUCCESS.
  3872. if failure, the return value is either ERROR_NOT_ENOUGH_MEMORY, ERROR_MORE_DATA, or
  3873. ERROR_NO_SUCH_INTERFACE_DEVICE.
  3874. --*/
  3875. {
  3876. DWORD BufferLength;
  3877. LONG Err;
  3878. PTSTR TempBuffer = NULL, RefString;
  3879. TCHAR NoRefStringSubKeyName[2];
  3880. HKEY hKey;
  3881. DWORD RegDataType;
  3882. Err = ERROR_SUCCESS;
  3883. hKey = INVALID_HANDLE_VALUE;
  3884. try {
  3885. //
  3886. // We need to allocate a temporary buffer to hold the symbolic link name while we munge it.
  3887. //
  3888. BufferLength = (lstrlen(DeviceInterfaceName) + 1) * sizeof(TCHAR);
  3889. if(!(TempBuffer = MyMalloc(BufferLength))) {
  3890. Err = ERROR_NOT_ENOUGH_MEMORY;
  3891. goto clean0;
  3892. }
  3893. memcpy(TempBuffer, DeviceInterfaceName, BufferLength);
  3894. //
  3895. // Parse this device interface name into the (munged) symbolic link name and
  3896. // (optional) refstring.
  3897. //
  3898. GetRegSubkeysFromDeviceInterfaceName(TempBuffer, &RefString);
  3899. //
  3900. // Now open the symbolic link subkey under the interface class key.
  3901. //
  3902. if(ERROR_SUCCESS != RegOpenKeyEx(hKeyInterfaceClass,
  3903. TempBuffer,
  3904. 0,
  3905. KEY_READ,
  3906. &hKey)) {
  3907. //
  3908. // Ensure the key handle is still invalid, so we won't try to free it.
  3909. //
  3910. hKey = INVALID_HANDLE_VALUE;
  3911. Err = ERROR_NO_SUCH_DEVICE_INTERFACE;
  3912. goto clean0;
  3913. }
  3914. //
  3915. // If the caller requested it, retrieve the device instance that owns this interface.
  3916. //
  3917. if(OwningDevInstName) {
  3918. Err = RegQueryValueEx(hKey,
  3919. pszDeviceInstance,
  3920. NULL,
  3921. &RegDataType,
  3922. (LPBYTE)OwningDevInstName,
  3923. OwningDevInstNameSize
  3924. );
  3925. if((Err != ERROR_SUCCESS) || (RegDataType != REG_SZ)) {
  3926. if(Err != ERROR_MORE_DATA) {
  3927. Err = ERROR_NO_SUCH_DEVICE_INTERFACE;
  3928. }
  3929. goto clean0;
  3930. }
  3931. }
  3932. //
  3933. // Now open up the subkey representing the particular 'instance' of this interface
  3934. // (this is based on the refstring).
  3935. //
  3936. if(RefString) {
  3937. //
  3938. // Back up the pointer one character. We know we're somewhere within TempBuffer
  3939. // (but not at the beginning) so this is safe.
  3940. //
  3941. RefString--;
  3942. } else {
  3943. RefString = NoRefStringSubKeyName;
  3944. NoRefStringSubKeyName[1] = TEXT('\0');
  3945. }
  3946. *RefString = TEXT('#');
  3947. if(ERROR_SUCCESS != RegOpenKeyEx(hKey,
  3948. RefString,
  3949. 0,
  3950. samDesired,
  3951. phkResult)) {
  3952. Err = ERROR_NO_SUCH_DEVICE_INTERFACE;
  3953. goto clean0;
  3954. }
  3955. clean0:
  3956. ; // Nothing to do.
  3957. } except(EXCEPTION_EXECUTE_HANDLER) {
  3958. Err = ERROR_INVALID_PARAMETER;
  3959. //
  3960. // Access the following variables so that the compiler will respect statement
  3961. // ordering w.r.t. their assignment.
  3962. //
  3963. TempBuffer = TempBuffer;
  3964. hKey = hKey;
  3965. }
  3966. if(TempBuffer) {
  3967. MyFree(TempBuffer);
  3968. }
  3969. if(hKey != INVALID_HANDLE_VALUE) {
  3970. RegCloseKey(hKey);
  3971. }
  3972. return Err;
  3973. }
  3974. LONG
  3975. AddOrGetGuidTableIndex(
  3976. IN PDEVICE_INFO_SET DeviceInfoSet,
  3977. IN CONST GUID *ClassGuid,
  3978. IN BOOL AddIfNotPresent
  3979. )
  3980. /*++
  3981. Routine Description:
  3982. This routine retrieves the index of a class GUID within the devinfo set's GUID
  3983. list (optionally, adding the GUID if not already present).
  3984. This is used to allow DWORD comparisons instead of 16-byte GUID comparisons
  3985. (and to save space).
  3986. Arguments:
  3987. DeviceInfoSet - Supplies a pointer to the device information set containing the
  3988. list of class GUIDs for which an index is to be retrieved.
  3989. InterfaceClassGuid - Supplies a pointer to the GUID for which an index is to
  3990. be added/retrieved.
  3991. AddIfNotPresent - If TRUE, the class GUID will be added to the list if it's not
  3992. already there.
  3993. Return Value:
  3994. If success, the return value is an index into the devinfo set's GuidTable array.
  3995. If failure, the return value is -1. If adding, this indicates an out-of-memory
  3996. condition. If simply retrieving, then this indicates that the GUID is not in
  3997. the list.
  3998. --*/
  3999. {
  4000. LONG i;
  4001. LPGUID NewGuidList;
  4002. for(i = 0; (DWORD)i < DeviceInfoSet->GuidTableSize; i++) {
  4003. if(IsEqualGUID(ClassGuid, &(DeviceInfoSet->GuidTable[i]))) {
  4004. return i;
  4005. }
  4006. }
  4007. if(AddIfNotPresent) {
  4008. if(DeviceInfoSet->GuidTable) {
  4009. NewGuidList = MyRealloc(DeviceInfoSet->GuidTable, (i + 1) * sizeof(GUID));
  4010. } else {
  4011. NewGuidList = MyMalloc(sizeof(GUID));
  4012. }
  4013. if(NewGuidList) {
  4014. CopyMemory(&(NewGuidList[i]),
  4015. ClassGuid,
  4016. sizeof(GUID)
  4017. );
  4018. DeviceInfoSet->GuidTable = NewGuidList;
  4019. DeviceInfoSet->GuidTableSize = i + 1;
  4020. return i;
  4021. } else {
  4022. //
  4023. // We couldn't allocate/grow the list; return -1 indicating an out-of-memory condition.
  4024. //
  4025. return -1;
  4026. }
  4027. } else {
  4028. //
  4029. // We didn't find the interface class GUID in our list, and we aren't supposed
  4030. // to add it.
  4031. //
  4032. return -1;
  4033. }
  4034. }
  4035. PINTERFACE_CLASS_LIST
  4036. AddOrGetInterfaceClassList(
  4037. IN PDEVICE_INFO_SET DeviceInfoSet,
  4038. IN PDEVINFO_ELEM DevInfoElem,
  4039. IN LONG InterfaceClassGuidIndex,
  4040. IN BOOL AddIfNotPresent
  4041. )
  4042. /*++
  4043. Routine Description:
  4044. This routine retrieves the interface device list of the specified class that
  4045. is 'owned' by the specified devinfo element. This list can optionally be
  4046. created if it doesn't already exist.
  4047. Arguments:
  4048. DeviceInfoSet - Supplies a pointer to the device information set containing the
  4049. devinfo element for which an interface device list is to be retrieved.
  4050. DevInfoElem - Supplies a pointer to the devinfo element for which an interface
  4051. device list is to be retrieved.
  4052. InterfaceClassGuidIndex - Supplies the index of the interface class GUID within
  4053. the hdevinfo set's InterfaceClassGuidList array.
  4054. AddIfNotPresent - If TRUE, then a new interface device list of the specified class
  4055. will be created for this devinfo element, if it doesn't already exist.
  4056. Return Value:
  4057. If successful, the return value is a pointer to the requested interface device list
  4058. for this devinfo element.
  4059. If failure, the return value is NULL. If AddIfNotPresent is TRUE, then this
  4060. indicates an out-of-memory condition, otherwise, it indicates that the requested
  4061. interface class list was not present for the devinfo element.
  4062. --*/
  4063. {
  4064. DWORD i;
  4065. PINTERFACE_CLASS_LIST NewClassList;
  4066. for(i = 0; i < DevInfoElem->InterfaceClassListSize; i++) {
  4067. if(DevInfoElem->InterfaceClassList[i].GuidIndex == InterfaceClassGuidIndex) {
  4068. return (&(DevInfoElem->InterfaceClassList[i]));
  4069. }
  4070. }
  4071. //
  4072. // The requested interface class list doesn't presently exist for this devinfo element.
  4073. //
  4074. if(AddIfNotPresent) {
  4075. if(DevInfoElem->InterfaceClassList) {
  4076. NewClassList = MyRealloc(DevInfoElem->InterfaceClassList, (i + 1) * sizeof(INTERFACE_CLASS_LIST));
  4077. } else {
  4078. NewClassList = MyMalloc(sizeof(INTERFACE_CLASS_LIST));
  4079. }
  4080. if(NewClassList) {
  4081. ZeroMemory(&(NewClassList[i]), sizeof(INTERFACE_CLASS_LIST));
  4082. NewClassList[i].GuidIndex = InterfaceClassGuidIndex;
  4083. DevInfoElem->InterfaceClassList = NewClassList;
  4084. DevInfoElem->InterfaceClassListSize = i + 1;
  4085. return (&(DevInfoElem->InterfaceClassList[i]));
  4086. } else {
  4087. //
  4088. // We couldn't allocate/grow this list; return NULL indicating an out-of-memory condition.
  4089. //
  4090. return NULL;
  4091. }
  4092. } else {
  4093. //
  4094. // We aren't supposed to add the class list if it doesn't already exist.
  4095. //
  4096. return NULL;
  4097. }
  4098. }
  4099. BOOL
  4100. InterfaceDeviceDataFromNode(
  4101. IN PINTERFACE_DEVICE_NODE InterfaceDeviceNode,
  4102. IN CONST GUID *InterfaceClassGuid,
  4103. OUT PSP_DEVICE_INTERFACE_DATA InterfaceDeviceData
  4104. )
  4105. /*++
  4106. Routine Description:
  4107. This routine fills in a PSP_DEVICE_INTERFACE_DATA structure based
  4108. on the information in the supplied interface device node.
  4109. Note: The supplied InterfaceDeviceData structure must have its cbSize
  4110. field filled in correctly, or the call will fail.
  4111. Arguments:
  4112. InterfaceDeviceNode - Supplies the address of the interface device node
  4113. to be used in filling in the interface device data buffer.
  4114. InterfaceClassGuid - Supplies a pointer to the class GUID for this
  4115. interface device.
  4116. InterfaceDeviceData - Supplies the address of the buffer to retrieve
  4117. the interface device data.
  4118. Return Value:
  4119. If the function succeeds, the return value is TRUE, otherwise, it
  4120. is FALSE.
  4121. --*/
  4122. {
  4123. if(InterfaceDeviceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA)) {
  4124. return FALSE;
  4125. }
  4126. CopyMemory(&(InterfaceDeviceData->InterfaceClassGuid),
  4127. InterfaceClassGuid,
  4128. sizeof(GUID)
  4129. );
  4130. InterfaceDeviceData->Flags = InterfaceDeviceNode->Flags;
  4131. InterfaceDeviceData->Reserved = (ULONG_PTR)InterfaceDeviceNode;
  4132. return TRUE;
  4133. }
  4134. PDEVINFO_ELEM
  4135. FindDevInfoElemForInterfaceDevice(
  4136. IN PDEVICE_INFO_SET DeviceInfoSet,
  4137. IN PSP_DEVICE_INTERFACE_DATA InterfaceDeviceData
  4138. )
  4139. /*++
  4140. Routine Description:
  4141. This routine searches through all elements of a device information
  4142. set, looking for one that corresponds to the devinfo element pointer
  4143. stored in the OwningDevInfoElem backpointer of the interface device
  4144. node referenced in the Reserved field of the interface device data. If a
  4145. match is found, a pointer to the device information element is returned.
  4146. Arguments:
  4147. DeviceInfoSet - Specifies the set to be searched.
  4148. InterfaceDeviceData - Supplies a pointer to the interface device data
  4149. for which the corresponding devinfo element is to be returned.
  4150. Return Value:
  4151. If a device information element is found, the return value is a
  4152. pointer to that element, otherwise, the return value is NULL.
  4153. --*/
  4154. {
  4155. PDEVINFO_ELEM DevInfoElem;
  4156. PINTERFACE_DEVICE_NODE InterfaceDeviceNode;
  4157. if(InterfaceDeviceData->cbSize != sizeof(SP_DEVICE_INTERFACE_DATA)) {
  4158. return NULL;
  4159. }
  4160. //
  4161. // The Reserved field contains a pointer to the underlying interface device node.
  4162. //
  4163. InterfaceDeviceNode = (PINTERFACE_DEVICE_NODE)(InterfaceDeviceData->Reserved);
  4164. for(DevInfoElem = DeviceInfoSet->DeviceInfoHead;
  4165. DevInfoElem;
  4166. DevInfoElem = DevInfoElem->Next) {
  4167. if(DevInfoElem == InterfaceDeviceNode->OwningDevInfoElem) {
  4168. return DevInfoElem;
  4169. }
  4170. }
  4171. return NULL;
  4172. }
  4173. DWORD
  4174. MapCrToSpError(
  4175. IN CONFIGRET CmReturnCode,
  4176. IN DWORD Default
  4177. )
  4178. /*++
  4179. Routine Description:
  4180. This routine maps some CM error return codes to setup api (Win32) return codes,
  4181. and maps everything else to the value specied by Default.
  4182. Arguments:
  4183. CmReturnCode - Specifies the ConfigMgr return code to be mapped.
  4184. Default - Specifies the default value to use if no explicit mapping applies.
  4185. Return Value:
  4186. Setup API (Win32) error code.
  4187. --*/
  4188. {
  4189. switch(CmReturnCode) {
  4190. case CR_SUCCESS :
  4191. return NO_ERROR;
  4192. case CR_CALL_NOT_IMPLEMENTED :
  4193. return ERROR_CALL_NOT_IMPLEMENTED;
  4194. case CR_OUT_OF_MEMORY :
  4195. return ERROR_NOT_ENOUGH_MEMORY;
  4196. case CR_INVALID_POINTER :
  4197. return ERROR_INVALID_USER_BUFFER;
  4198. case CR_INVALID_DEVINST :
  4199. return ERROR_NO_SUCH_DEVINST;
  4200. case CR_INVALID_DEVICE_ID :
  4201. return ERROR_INVALID_DEVINST_NAME;
  4202. case CR_ALREADY_SUCH_DEVINST :
  4203. return ERROR_DEVINST_ALREADY_EXISTS;
  4204. case CR_INVALID_REFERENCE_STRING :
  4205. return ERROR_INVALID_REFERENCE_STRING;
  4206. case CR_INVALID_MACHINENAME :
  4207. return ERROR_INVALID_MACHINENAME;
  4208. case CR_REMOTE_COMM_FAILURE :
  4209. return ERROR_REMOTE_COMM_FAILURE;
  4210. case CR_MACHINE_UNAVAILABLE :
  4211. return ERROR_MACHINE_UNAVAILABLE;
  4212. case CR_NO_CM_SERVICES :
  4213. return ERROR_NO_CONFIGMGR_SERVICES;
  4214. case CR_ACCESS_DENIED :
  4215. return ERROR_ACCESS_DENIED;
  4216. case CR_NOT_DISABLEABLE:
  4217. return ERROR_NOT_DISABLEABLE;
  4218. default :
  4219. return Default;
  4220. }
  4221. }
  4222. LPQUERY_SERVICE_LOCK_STATUS GetServiceLockStatus(
  4223. IN SC_HANDLE SCMHandle
  4224. )
  4225. /*++
  4226. Routine Description:
  4227. Obtain service lock status - called when service is locked
  4228. Arguments:
  4229. SCMHandle - supplies a handle to the SCM to lock
  4230. Return Value:
  4231. NULL if failed (GetLastError contains error) otherwise buffer
  4232. allocated by MyMalloc
  4233. --*/
  4234. {
  4235. PBYTE Buffer = NULL;
  4236. LPQUERY_SERVICE_LOCK_STATUS LockStatus = NULL;
  4237. DWORD BufferSize = sizeof(QUERY_SERVICE_LOCK_STATUS)+MAX_PATH;
  4238. DWORD ReqBufferSize = 0;
  4239. Buffer = MyMalloc(BufferSize);
  4240. while(Buffer) {
  4241. LockStatus = (LPQUERY_SERVICE_LOCK_STATUS)Buffer;
  4242. if(QueryServiceLockStatus(SCMHandle,LockStatus,BufferSize,&ReqBufferSize)) {
  4243. return LockStatus;
  4244. }
  4245. if(GetLastError()!=ERROR_INSUFFICIENT_BUFFER) {
  4246. MyFree(LockStatus);
  4247. return NULL;
  4248. }
  4249. Buffer = MyRealloc(LockStatus,ReqBufferSize);
  4250. }
  4251. if(LockStatus) {
  4252. MyFree(LockStatus);
  4253. }
  4254. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  4255. return NULL;
  4256. }
  4257. DWORD
  4258. pAcquireSCMLock(
  4259. IN SC_HANDLE SCMHandle,
  4260. OUT SC_LOCK *pSCMLock,
  4261. IN PSETUP_LOG_CONTEXT LogContext
  4262. )
  4263. /*++
  4264. Routine Description:
  4265. This routine attempts to lock the SCM database. If it is already locked it will retry
  4266. ACQUIRE_SCM_LOCK_ATTEMPTS times at intervals of ACQUIRE_SCM_LOCK_INTERVAL.
  4267. Arguments:
  4268. SCMHandle - supplies a handle to the SCM to lock
  4269. pSCMLock - receives the lock handle
  4270. Return Value:
  4271. NO_ERROR if the lock is acquired, otherwise a Win32 error code
  4272. Remarks:
  4273. The value of *pSCMLock is guaranteed to be NULL if the lock is not acquired
  4274. --*/
  4275. {
  4276. DWORD Err;
  4277. ULONG Attempts = ACQUIRE_SCM_LOCK_ATTEMPTS;
  4278. LPQUERY_SERVICE_LOCK_STATUS LockStatus = NULL;
  4279. MYASSERT(pSCMLock);
  4280. *pSCMLock = NULL;
  4281. retry:
  4282. while((*pSCMLock = LockServiceDatabase(SCMHandle)) == NULL && Attempts > 0) {
  4283. //
  4284. // Check if the error is that someone else has locked the SCM
  4285. //
  4286. if((Err = GetLastError()) == ERROR_SERVICE_DATABASE_LOCKED) {
  4287. Attempts--;
  4288. //
  4289. // Sleep for specified time
  4290. //
  4291. Sleep(ACQUIRE_SCM_LOCK_INTERVAL);
  4292. } else {
  4293. //
  4294. // Unrecoverable error occured
  4295. //
  4296. break;
  4297. }
  4298. }
  4299. if(!*pSCMLock) {
  4300. Err = GetLastError();
  4301. if(Err == ERROR_SERVICE_DATABASE_LOCKED) {
  4302. LockStatus = GetServiceLockStatus(SCMHandle);
  4303. if(LockStatus && !LockStatus->fIsLocked) {
  4304. MYASSERT(LockStatus->fIsLocked);
  4305. MyFree(LockStatus);
  4306. //
  4307. // just became free, may as well try again
  4308. //
  4309. goto retry;
  4310. } else if(LockStatus) {
  4311. WriteLogEntry(LogContext,
  4312. SETUP_LOG_ERROR,
  4313. MSG_LOG_SCM_LOCKED_INFO,
  4314. NULL,
  4315. LockStatus->lpLockOwner,
  4316. LockStatus->dwLockDuration);
  4317. MyFree(LockStatus);
  4318. } else {
  4319. WriteLogEntry(LogContext,
  4320. SETUP_LOG_ERROR,
  4321. MSG_LOG_SCM_LOCKED_INFO,
  4322. NULL,
  4323. TEXT("?"),
  4324. 0);
  4325. }
  4326. }
  4327. //
  4328. // We have been unable to lock the SCM
  4329. //
  4330. return Err;
  4331. }
  4332. return NO_ERROR;
  4333. }
  4334. DWORD
  4335. pSetupAcquireSCMLock(
  4336. IN SC_HANDLE SCMHandle,
  4337. OUT SC_LOCK *pSCMLock
  4338. )
  4339. /*++
  4340. Routine Description:
  4341. variation of pAcquireSCMLock used by SysSetup
  4342. See pAcquireSCMLock
  4343. --*/
  4344. {
  4345. return pAcquireSCMLock(SCMHandle,pSCMLock,NULL);
  4346. }
  4347. DWORD
  4348. InvalidateHelperModules(
  4349. IN HDEVINFO DeviceInfoSet,
  4350. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  4351. IN DWORD Flags
  4352. )
  4353. /*++
  4354. Routine Description:
  4355. This routine resets the list of 'helper modules' (class installer, property
  4356. page providers, and co-installers), and either frees them immediately or
  4357. migrates the module handles to the devinfo set's list of things to clean up
  4358. when the HDEVINFO is destroyed.
  4359. Arguments:
  4360. DeviceInfoSet - Supplies a handle to the device information set containing
  4361. a list of 'helper' modules to be invalidated.
  4362. DeviceInfoData - Optionally, specifies a particular device information
  4363. element containing a list of 'helper' modules to be invalidated. If
  4364. this parameter is not specified, then the list of modules for the
  4365. set itself will be invalidated.
  4366. Flags - Supplies flags that control the behavior of this routine. May be
  4367. a combination of the following values:
  4368. IHM_COINSTALLERS_ONLY - If this flag is set, only the co-installers list
  4369. will be invalidated. Otherwise, the class
  4370. installer and property page providers will also
  4371. be invalidated.
  4372. IHM_FREE_IMMEDIATELY - If this flag is set, then the modules will be
  4373. freed immediately. Otherwise, the modules will
  4374. be added to the HDEVINFO set's list of things to
  4375. clean up at handle close time.
  4376. Return Value:
  4377. If successful, the return value is NO_ERROR, otherwise it is ERROR_NOT_ENOUGH_MEMORY.
  4378. (This routine cannot fail if the IHM_FREE_IMMEDIATELY flag is set.)
  4379. --*/
  4380. {
  4381. PDEVICE_INFO_SET pDeviceInfoSet;
  4382. DWORD Err, i;
  4383. PDEVINFO_ELEM DevInfoElem;
  4384. PDEVINSTALL_PARAM_BLOCK InstallParamBlock;
  4385. DWORD NumModulesToInvalidate;
  4386. PMODULE_HANDLE_LIST_NODE NewModuleHandleNode;
  4387. BOOL UnlockDevInfoElem;
  4388. LONG CoInstallerIndex;
  4389. SPFUSIONINSTANCE spFusionInstance;
  4390. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  4391. //
  4392. // The handle's no longer valid--the user must've already destroyed the
  4393. // set. We have nothing to do.
  4394. //
  4395. return NO_ERROR;
  4396. }
  4397. Err = NO_ERROR;
  4398. UnlockDevInfoElem = FALSE;
  4399. DevInfoElem = NULL;
  4400. NewModuleHandleNode = NULL;
  4401. try {
  4402. //
  4403. // If we're invalidating helper modules for a particular devinfo element,
  4404. // then find that element.
  4405. //
  4406. if(DeviceInfoData) {
  4407. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  4408. DeviceInfoData,
  4409. NULL))) {
  4410. //
  4411. // The element must've been deleted--we've nothing to do.
  4412. //
  4413. goto clean0;
  4414. }
  4415. InstallParamBlock = &(DevInfoElem->InstallParamBlock);
  4416. } else {
  4417. InstallParamBlock = &(pDeviceInfoSet->InstallParamBlock);
  4418. }
  4419. //
  4420. // Count the number of module handles we need to free/migrate.
  4421. //
  4422. if(InstallParamBlock->CoInstallerCount == -1) {
  4423. NumModulesToInvalidate = 0;
  4424. } else {
  4425. MYASSERT(InstallParamBlock->CoInstallerCount >= 0);
  4426. NumModulesToInvalidate = (DWORD)(InstallParamBlock->CoInstallerCount);
  4427. }
  4428. if(!(Flags & IHM_COINSTALLERS_ONLY)) {
  4429. if(InstallParamBlock->hinstClassInstaller) {
  4430. NumModulesToInvalidate++;
  4431. }
  4432. if(InstallParamBlock->hinstClassPropProvider) {
  4433. NumModulesToInvalidate++;
  4434. }
  4435. if(InstallParamBlock->hinstDevicePropProvider) {
  4436. NumModulesToInvalidate++;
  4437. }
  4438. if(InstallParamBlock->hinstBasicPropProvider) {
  4439. NumModulesToInvalidate++;
  4440. }
  4441. }
  4442. if(NumModulesToInvalidate) {
  4443. //
  4444. // If we can't unload these modules at this time, then create a node to store
  4445. // these module handles until the devinfo set is destroyed.
  4446. //
  4447. if(!(Flags & IHM_FREE_IMMEDIATELY)) {
  4448. NewModuleHandleNode = MyMalloc(offsetof(MODULE_HANDLE_LIST_NODE, ModuleList)
  4449. + (NumModulesToInvalidate * sizeof(MODULE_HANDLE_LIST_INSTANCE))
  4450. );
  4451. if(!NewModuleHandleNode) {
  4452. Err = ERROR_NOT_ENOUGH_MEMORY;
  4453. goto clean0;
  4454. }
  4455. }
  4456. //
  4457. // Give the class installers/co-installers a DIF_DESTROYPRIVATEDATA
  4458. // notification. NOTE: We don't unlock the HDEVINFO set here, so the
  4459. // class/co-installers can't make any calls where nesting level > 1
  4460. // is disallowed. This means that SetupDiSelectDevice, for example,
  4461. // will fail if the class installer tries to call it now. This is
  4462. // necessary, because otherwise it would deadlock.
  4463. //
  4464. if(DevInfoElem) {
  4465. //
  4466. // (Also, lock down the devinfo element, so that the class/co-installers
  4467. // can't make any 'dangerous' calls (e.g., SetupDiDeleteDeviceInfo),
  4468. // during the clean-up notification.)
  4469. //
  4470. if(!(DevInfoElem->DiElemFlags & DIE_IS_LOCKED)) {
  4471. DevInfoElem->DiElemFlags |= DIE_IS_LOCKED;
  4472. UnlockDevInfoElem = TRUE;
  4473. }
  4474. }
  4475. _SetupDiCallClassInstaller(DIF_DESTROYPRIVATEDATA,
  4476. DeviceInfoSet,
  4477. DeviceInfoData,
  4478. CALLCI_CALL_HELPERS
  4479. );
  4480. //
  4481. // Clear the flag we set above...
  4482. //
  4483. if(UnlockDevInfoElem) {
  4484. DevInfoElem->DiElemFlags &= ~DIE_IS_LOCKED;
  4485. UnlockDevInfoElem = FALSE;
  4486. }
  4487. //
  4488. // Store the module handles in the node we allocated, and link it into the
  4489. // list of module handles associated with this devinfo set.
  4490. //
  4491. i = 0;
  4492. if(!(Flags & IHM_COINSTALLERS_ONLY)) {
  4493. //
  4494. // Either free the modules now, or store them in our 'to do' list...
  4495. //
  4496. if(Flags & IHM_FREE_IMMEDIATELY) {
  4497. if(InstallParamBlock->hinstClassInstaller) {
  4498. spFusionEnterContext(InstallParamBlock->ClassInstallerFusionContext,
  4499. &spFusionInstance);
  4500. FreeLibrary(InstallParamBlock->hinstClassInstaller);
  4501. spFusionLeaveContext(&spFusionInstance);
  4502. spFusionKillContext(InstallParamBlock->ClassInstallerFusionContext);
  4503. }
  4504. if(InstallParamBlock->hinstClassPropProvider) {
  4505. spFusionEnterContext(InstallParamBlock->ClassEnumPropPagesFusionContext,
  4506. &spFusionInstance);
  4507. FreeLibrary(InstallParamBlock->hinstClassPropProvider);
  4508. spFusionLeaveContext(&spFusionInstance);
  4509. spFusionKillContext(InstallParamBlock->ClassEnumPropPagesFusionContext);
  4510. }
  4511. if(InstallParamBlock->hinstDevicePropProvider) {
  4512. spFusionEnterContext(InstallParamBlock->DeviceEnumPropPagesFusionContext,
  4513. &spFusionInstance);
  4514. FreeLibrary(InstallParamBlock->hinstDevicePropProvider);
  4515. spFusionLeaveContext(&spFusionInstance);
  4516. spFusionKillContext(InstallParamBlock->DeviceEnumPropPagesFusionContext);
  4517. }
  4518. if(InstallParamBlock->hinstBasicPropProvider) {
  4519. spFusionEnterContext(InstallParamBlock->EnumBasicPropertiesFusionContext,
  4520. &spFusionInstance);
  4521. FreeLibrary(InstallParamBlock->hinstBasicPropProvider);
  4522. spFusionLeaveContext(&spFusionInstance);
  4523. spFusionKillContext(InstallParamBlock->EnumBasicPropertiesFusionContext);
  4524. }
  4525. } else {
  4526. if(InstallParamBlock->hinstClassInstaller) {
  4527. NewModuleHandleNode->ModuleList[i].ModuleHandle = InstallParamBlock->hinstClassInstaller;
  4528. NewModuleHandleNode->ModuleList[i++].FusionContext = InstallParamBlock->ClassInstallerFusionContext;
  4529. }
  4530. if(InstallParamBlock->hinstClassPropProvider) {
  4531. NewModuleHandleNode->ModuleList[i].ModuleHandle = InstallParamBlock->hinstClassPropProvider;
  4532. NewModuleHandleNode->ModuleList[i++].FusionContext = InstallParamBlock->ClassEnumPropPagesFusionContext;
  4533. }
  4534. if(InstallParamBlock->hinstDevicePropProvider) {
  4535. NewModuleHandleNode->ModuleList[i].ModuleHandle = InstallParamBlock->hinstDevicePropProvider;
  4536. NewModuleHandleNode->ModuleList[i++].FusionContext = InstallParamBlock->DeviceEnumPropPagesFusionContext;
  4537. }
  4538. if(InstallParamBlock->hinstBasicPropProvider) {
  4539. NewModuleHandleNode->ModuleList[i].ModuleHandle = InstallParamBlock->hinstBasicPropProvider;
  4540. NewModuleHandleNode->ModuleList[i++].FusionContext = InstallParamBlock->EnumBasicPropertiesFusionContext;
  4541. }
  4542. }
  4543. }
  4544. for(CoInstallerIndex = 0;
  4545. CoInstallerIndex < InstallParamBlock->CoInstallerCount;
  4546. CoInstallerIndex++)
  4547. {
  4548. if(Flags & IHM_FREE_IMMEDIATELY) {
  4549. spFusionEnterContext(InstallParamBlock->CoInstallerList[CoInstallerIndex].CoInstallerFusionContext,
  4550. &spFusionInstance);
  4551. FreeLibrary(InstallParamBlock->CoInstallerList[CoInstallerIndex].hinstCoInstaller);
  4552. spFusionLeaveContext(&spFusionInstance);
  4553. spFusionKillContext(InstallParamBlock->CoInstallerList[CoInstallerIndex].CoInstallerFusionContext);
  4554. } else {
  4555. NewModuleHandleNode->ModuleList[i].ModuleHandle =
  4556. InstallParamBlock->CoInstallerList[CoInstallerIndex].hinstCoInstaller;
  4557. NewModuleHandleNode->ModuleList[i++].FusionContext =
  4558. InstallParamBlock->CoInstallerList[CoInstallerIndex].CoInstallerFusionContext;
  4559. }
  4560. }
  4561. //
  4562. // Unless we're freeing these modules immediately, our modules-to-free list
  4563. // index should now match the number of modules we're supposed to be
  4564. // invalidating.
  4565. //
  4566. MYASSERT((Flags & IHM_FREE_IMMEDIATELY) || (i == NumModulesToInvalidate));
  4567. if(!(Flags & IHM_FREE_IMMEDIATELY)) {
  4568. NewModuleHandleNode->ModuleCount = NumModulesToInvalidate;
  4569. NewModuleHandleNode->Next = pDeviceInfoSet->ModulesToFree;
  4570. pDeviceInfoSet->ModulesToFree = NewModuleHandleNode;
  4571. //
  4572. // Now, clear the node pointer, so we won't try to free it if we hit an exception.
  4573. //
  4574. NewModuleHandleNode = NULL;
  4575. }
  4576. //
  4577. // Clear all the module handles (and entry points). They will be retrieved
  4578. // anew the next time they're needed.
  4579. //
  4580. if(!(Flags & IHM_COINSTALLERS_ONLY)) {
  4581. InstallParamBlock->hinstClassInstaller = NULL;
  4582. InstallParamBlock->ClassInstallerEntryPoint = NULL;
  4583. InstallParamBlock->ClassInstallerFusionContext = NULL;
  4584. InstallParamBlock->hinstClassPropProvider = NULL;
  4585. InstallParamBlock->ClassEnumPropPagesEntryPoint = NULL;
  4586. InstallParamBlock->ClassEnumPropPagesFusionContext = NULL;
  4587. InstallParamBlock->hinstDevicePropProvider = NULL;
  4588. InstallParamBlock->DeviceEnumPropPagesEntryPoint = NULL;
  4589. InstallParamBlock->DeviceEnumPropPagesFusionContext = NULL;
  4590. InstallParamBlock->hinstBasicPropProvider = NULL;
  4591. InstallParamBlock->EnumBasicPropertiesEntryPoint = NULL;
  4592. InstallParamBlock->EnumBasicPropertiesFusionContext = NULL;
  4593. }
  4594. if(InstallParamBlock->CoInstallerCount != -1) {
  4595. if(InstallParamBlock->CoInstallerList) {
  4596. MyFree(InstallParamBlock->CoInstallerList);
  4597. InstallParamBlock->CoInstallerList = NULL;
  4598. }
  4599. }
  4600. }
  4601. //
  4602. // Set the co-installer count back to -1, even if their weren't any co-installers
  4603. // to unload. That will ensure that we'll re-load the co-installers for the next
  4604. // class installer request we receive.
  4605. //
  4606. InstallParamBlock->CoInstallerCount = -1;
  4607. clean0: ; // nothing to do.
  4608. } except(EXCEPTION_EXECUTE_HANDLER) {
  4609. //
  4610. // We should never encounter an exception, but if we do, just make sure we
  4611. // do any necessary clean-up. Don't return an error in this case--the only
  4612. // error this routine is supposed to return is out-of-memory.
  4613. //
  4614. if(UnlockDevInfoElem) {
  4615. MYASSERT(DevInfoElem);
  4616. DevInfoElem->DiElemFlags &= ~DIE_IS_LOCKED;
  4617. }
  4618. if(NewModuleHandleNode) {
  4619. MyFree(NewModuleHandleNode);
  4620. }
  4621. }
  4622. UnlockDeviceInfoSet(pDeviceInfoSet);
  4623. return Err;
  4624. }
  4625. DWORD
  4626. DoInstallActionWithParams(
  4627. IN DI_FUNCTION InstallFunction,
  4628. IN HDEVINFO DeviceInfoSet,
  4629. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  4630. IN OUT PSP_CLASSINSTALL_HEADER ClassInstallParams, OPTIONAL
  4631. IN DWORD ClassInstallParamsSize,
  4632. IN DWORD Flags
  4633. )
  4634. /*++
  4635. Routine Description:
  4636. This routine performs a requested installation action, using the specified
  4637. class install parameters. Any existing class install parameters are
  4638. preserved.
  4639. Arguments:
  4640. InstallFunction - Specifies the DIF_* action to be performed.
  4641. DeviceInfoSet - Supplies a handle to the device information set for which
  4642. the installation action is to be performed.
  4643. DeviceInfoData - Optionally, supplies the address of a device information
  4644. structure specifying a particular element for which the installation
  4645. action is to be performed.
  4646. ClassInstallParams - Optionally, supplies the address of a class install
  4647. parameter buffer to be used for this action. If this parameter is not
  4648. specified, then no class install params will be available to the class
  4649. installer during this call (even if there were pre-existing parameters
  4650. coming into this function).
  4651. ClassInstallParamsSize - Supplies the size, in bytes, of the ClassInstallParams
  4652. buffer, or zero if ClassInstallParams is not specified.
  4653. Flags - Supplies flags that control the behavior of this routine. May be
  4654. a combination of the following values:
  4655. INSTALLACTION_CALL_CI - Call the class installer for this action request.
  4656. INSTALLACTION_NO_DEFAULT - Don't perform the default action (if this flag
  4657. is specified without INSTALLACTION_CALL_CI, then this routine is a
  4658. no-op).
  4659. Return Value:
  4660. If the request was handled successfully, the return value is NO_ERROR.
  4661. If the request was not handled (but no error occurred), the return value is
  4662. ERROR_DI_DO_DEFAULT.
  4663. Otherwise, the return value is a Win32 error code indicating the cause of
  4664. failure.
  4665. --*/
  4666. {
  4667. PBYTE OldCiParams;
  4668. DWORD OldCiParamsSize, Err;
  4669. SP_PROPCHANGE_PARAMS PropChangeParams;
  4670. SP_DEVINSTALL_PARAMS DevInstallParams;
  4671. DWORD FlagsToClear;
  4672. //
  4673. // Retrieve any existing class install parameters, then write out
  4674. // parameters for DIF_PROPERTYCHANGE.
  4675. //
  4676. OldCiParams = NULL;
  4677. OldCiParamsSize = 0;
  4678. while(!SetupDiGetClassInstallParams(DeviceInfoSet,
  4679. DeviceInfoData,
  4680. (PSP_CLASSINSTALL_HEADER)OldCiParams,
  4681. OldCiParamsSize,
  4682. &OldCiParamsSize)) {
  4683. Err = GetLastError();
  4684. //
  4685. // Before going any further, free our existing buffer (if there is one).
  4686. //
  4687. if(OldCiParams) {
  4688. MyFree(OldCiParams);
  4689. OldCiParams = NULL;
  4690. }
  4691. if(Err == ERROR_INSUFFICIENT_BUFFER) {
  4692. //
  4693. // Allocate a buffer of the size required, and try again.
  4694. //
  4695. MYASSERT(OldCiParamsSize >= sizeof(SP_CLASSINSTALL_HEADER));
  4696. if(!(OldCiParams = MyMalloc(OldCiParamsSize))) {
  4697. Err = ERROR_NOT_ENOUGH_MEMORY;
  4698. goto clean0;
  4699. }
  4700. ((PSP_CLASSINSTALL_HEADER)OldCiParams)->cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  4701. } else {
  4702. //
  4703. // Treat any other error as if there are no class install params
  4704. // (since ERROR_NO_CLASSINSTALL_PARAMS is really the only error
  4705. // we should ever see here anyway).
  4706. //
  4707. OldCiParamsSize = 0;
  4708. break;
  4709. }
  4710. }
  4711. //
  4712. // Retrieve the device install params for the set or element we're working with.
  4713. //
  4714. DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  4715. if(!SetupDiGetDeviceInstallParams(DeviceInfoSet,
  4716. DeviceInfoData,
  4717. &DevInstallParams)) {
  4718. Err = GetLastError();
  4719. goto clean0;
  4720. }
  4721. FlagsToClear = 0;
  4722. //
  4723. // It's possible that the class install params we just retrieved are 'turned off'
  4724. // (i.e., the DI_CLASSINSTALLPARAMS bit is cleared). Check for that condition now,
  4725. // so we can restore the parameters to the same state later.
  4726. //
  4727. if(OldCiParams && !(DevInstallParams.Flags & DI_CLASSINSTALLPARAMS)) {
  4728. FlagsToClear |= DI_CLASSINSTALLPARAMS;
  4729. }
  4730. //
  4731. // If the caller doesn't want us to do the default action, then check to see whether
  4732. // we need to temporarily set the DI_NODI_DEFAULTACTION flag.
  4733. //
  4734. if((Flags & INSTALLACTION_NO_DEFAULT) &&
  4735. !(DevInstallParams.Flags & DI_NODI_DEFAULTACTION)) {
  4736. FlagsToClear |= DI_NODI_DEFAULTACTION;
  4737. DevInstallParams.Flags |= DI_NODI_DEFAULTACTION;
  4738. if(!SetupDiSetDeviceInstallParams(DeviceInfoSet,
  4739. DeviceInfoData,
  4740. &DevInstallParams)) {
  4741. Err = GetLastError();
  4742. goto clean0;
  4743. }
  4744. }
  4745. if(!SetupDiSetClassInstallParams(DeviceInfoSet,
  4746. DeviceInfoData,
  4747. ClassInstallParams,
  4748. ClassInstallParamsSize)) {
  4749. Err = GetLastError();
  4750. goto clean1;
  4751. }
  4752. //
  4753. // OK, now call the class installer.
  4754. //
  4755. if(_SetupDiCallClassInstaller(InstallFunction,
  4756. DeviceInfoSet,
  4757. DeviceInfoData,
  4758. (Flags & INSTALLACTION_CALL_CI) ? (CALLCI_LOAD_HELPERS | CALLCI_CALL_HELPERS) : 0)) {
  4759. //
  4760. // mission accomplished
  4761. //
  4762. Err = NO_ERROR;
  4763. } else {
  4764. Err = GetLastError();
  4765. }
  4766. //
  4767. // Save the class install params results in the ClassInstallParams
  4768. // value that was passed in.
  4769. //
  4770. if (ClassInstallParams) {
  4771. SetupDiGetClassInstallParams(DeviceInfoSet,
  4772. DeviceInfoData,
  4773. ClassInstallParams,
  4774. ClassInstallParamsSize,
  4775. NULL);
  4776. }
  4777. //
  4778. // Restore the previous class install params.
  4779. //
  4780. SetupDiSetClassInstallParams(DeviceInfoSet,
  4781. DeviceInfoData,
  4782. (PSP_CLASSINSTALL_HEADER)OldCiParams,
  4783. OldCiParamsSize
  4784. );
  4785. clean1:
  4786. if(FlagsToClear) {
  4787. if(SetupDiGetDeviceInstallParams(DeviceInfoSet,
  4788. DeviceInfoData,
  4789. &DevInstallParams)) {
  4790. DevInstallParams.Flags &= ~FlagsToClear;
  4791. SetupDiSetDeviceInstallParams(DeviceInfoSet,
  4792. DeviceInfoData,
  4793. &DevInstallParams
  4794. );
  4795. }
  4796. }
  4797. clean0:
  4798. if(OldCiParams) {
  4799. MyFree(OldCiParams);
  4800. }
  4801. return Err;
  4802. }
  4803. BOOL
  4804. GetBestDeviceDesc(
  4805. IN HDEVINFO DeviceInfoSet,
  4806. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  4807. OUT PTSTR DeviceDescBuffer
  4808. )
  4809. /*++
  4810. Routine Description:
  4811. This routine retrieves the best possible description to be displayed for
  4812. the specified devinfo set or element (e.g., for driver signing popups). We
  4813. will try to retrieve this string by doing the following things (in order)
  4814. until one of them succeeds:
  4815. 1. If there's a selected driver, retrieve the DeviceDesc in that
  4816. driver node.
  4817. 2. If this is for a device information element, then use devnode's
  4818. DeviceDesc property.
  4819. 3. Retrieve the description of the class (via
  4820. SetupDiGetClassDescription).
  4821. 4. Use the (localized) string "Unknown driver software package".
  4822. ASSUMES THAT THE CALLING ROUTINE HAS ALREADY ACQUIRED THE LOCK!
  4823. Arguments:
  4824. DeviceInfoSet - Supplies a handle to the device information set for which
  4825. a description is to be retrieved (unless DeviceInfoData is also
  4826. supplied, in which case we retrieve the description for that particular
  4827. element instead.
  4828. DeviceInfoData - Optionally, supplies the device information element for
  4829. which a description is to be retrieved.
  4830. DeviceDescBuffer - Supplies the address of a character buffer that must be
  4831. at least LINE_LEN characters long. Upon successful return, this buffer
  4832. will be filled in with a device description
  4833. Return Value:
  4834. TRUE if some description was retrieved, FALSE otherwise.
  4835. --*/
  4836. {
  4837. SP_DRVINFO_DATA DriverInfoData;
  4838. GUID ClassGuid;
  4839. BOOL b;
  4840. //
  4841. // First, see if there's a selected driver for this device information set
  4842. // or element.
  4843. //
  4844. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  4845. if(SetupDiGetSelectedDriver(DeviceInfoSet, DeviceInfoData, &DriverInfoData)) {
  4846. //
  4847. // Copy the description into the caller-supplied buffer and return.
  4848. //
  4849. lstrcpy(DeviceDescBuffer, DriverInfoData.Description);
  4850. return TRUE;
  4851. }
  4852. //
  4853. // OK, next try to retrieve the DeviceDesc property (if we're working on a
  4854. // device information element.
  4855. //
  4856. if(DeviceInfoData) {
  4857. if(SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
  4858. DeviceInfoData,
  4859. SPDRP_DEVICEDESC,
  4860. NULL,
  4861. (PBYTE)DeviceDescBuffer,
  4862. LINE_LEN * sizeof(TCHAR),
  4863. NULL)) {
  4864. return TRUE;
  4865. }
  4866. }
  4867. //
  4868. // Next, try to retrieve the class's friendly name.
  4869. //
  4870. if(DeviceInfoData) {
  4871. CopyMemory(&ClassGuid, &(DeviceInfoData->ClassGuid), sizeof(GUID));
  4872. } else {
  4873. b = SetupDiGetDeviceInfoListClass(DeviceInfoSet, &ClassGuid);
  4874. MYASSERT(b);
  4875. if(!b) {
  4876. return FALSE;
  4877. }
  4878. }
  4879. if(SetupDiGetClassDescription(&ClassGuid,
  4880. DeviceDescBuffer,
  4881. LINE_LEN,
  4882. NULL)) {
  4883. return TRUE;
  4884. } else {
  4885. //
  4886. // We have a class that isn't already installed. Therefore, we just
  4887. // give it a generic description.
  4888. //
  4889. if(LoadString(MyDllModuleHandle,
  4890. IDS_UNKNOWN_DRIVER,
  4891. DeviceDescBuffer,
  4892. LINE_LEN)) {
  4893. return TRUE;
  4894. }
  4895. }
  4896. return FALSE;
  4897. }
  4898. BOOL
  4899. GetDecoratedModelsSection(
  4900. IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
  4901. IN PLOADED_INF Inf,
  4902. IN PINF_LINE MfgListLine,
  4903. IN PSP_ALTPLATFORM_INFO_V2 AltPlatformInfo, OPTIONAL
  4904. OUT PTSTR DecoratedModelsSection OPTIONAL
  4905. )
  4906. /*++
  4907. Routine Description:
  4908. This routine examines each (optional) TargetDecoration field within the
  4909. specified manufacturer's entry in the [Manufacturer] section, to see if any
  4910. are applicable to the current OS. If so, the most-appropriate one (based
  4911. on OS major and minor version) is chosen, and the TargetDecoration string
  4912. is appended to the manufacturer's models section name, and returned to the
  4913. caller.
  4914. The format of the TargetDecoration field is as follows:
  4915. NT[architecture][.[OSMajorVer][.[OSMinorVer][.[ProductType][.[SuiteMask]]]]]
  4916. Where:
  4917. architecture may be x86, IA64, AXP64, or AMD64.
  4918. OSMajorVer is the OS major version (e.g., for Whistler, it's 5)
  4919. OSMinorVer is the OS minor version (e.g., for Whistler, it's 1)
  4920. ProductType indicates the type of product, and may be one of the following
  4921. values (as defined in winnt.h):
  4922. VER_NT_WORKSTATION 0x0000001
  4923. VER_NT_DOMAIN_CONTROLLER 0x0000002
  4924. VER_NT_SERVER 0x0000003
  4925. SuiteMask is a combination of the following flags identifying the product
  4926. suites available on the system (as defined in winnt.h):
  4927. VER_SUITE_SMALLBUSINESS 0x00000001
  4928. VER_SUITE_ENTERPRISE 0x00000002
  4929. VER_SUITE_BACKOFFICE 0x00000004
  4930. VER_SUITE_COMMUNICATIONS 0x00000008
  4931. VER_SUITE_TERMINAL 0x00000010
  4932. VER_SUITE_SMALLBUSINESS_RESTRICTED 0x00000020
  4933. VER_SUITE_EMBEDDEDNT 0x00000040
  4934. VER_SUITE_DATACENTER 0x00000080
  4935. VER_SUITE_SINGLEUSERTS 0x00000100
  4936. Refer to the discussion in the SDK for the OSVERSIONINFOEX structure for
  4937. more information.
  4938. THIS ROUTINE DOES NOT DO LOCKING ON THE INF!!!
  4939. Arguments:
  4940. LogContext - optionally, supplies the log context to use if an error is
  4941. encountered (e.g., decorated section name is too long)
  4942. Inf - supplies a pointer to the inf descriptor for the loaded device INF.
  4943. MfgListLine - supplies a pointer to the line descriptor for the
  4944. manufacturer's entry within the [Manufacturer] section. THIS LINE MUST
  4945. BE CONTAINED WITHIN THE SPECIFIED INF!!
  4946. AltPlatformInfo - optionally, supplies alternate platform information to be
  4947. used when selecting the most-appropriate models section.
  4948. NOTE: If this parameter is supplied, then we must do our own version
  4949. comparisons, as VerifyVersionInfo() has no clue about non-native
  4950. matters. This also means that we do not take into account either
  4951. ProductType or SuiteMask in our comparison.
  4952. DecoratedModelsSection - upon successful return, receives the decorated
  4953. models section name based on the most-appropriate TargetDecoration
  4954. field in the manufacturer's entry.
  4955. This character buffer must be at least MAX_SECT_NAME_LEN characters.
  4956. Return Value:
  4957. If an applicable TargetDecoration entry was found (thus
  4958. DecoratedModelsSection was filled in), the return value is TRUE.
  4959. Otherwise, the return value is FALSE.
  4960. --*/
  4961. {
  4962. #define DEC_INCLUDES_ARCHITECTURE 4
  4963. #define DEC_INCLUDES_PRODUCTTYPE 2
  4964. #define DEC_INCLUDES_SUITEMASK 1
  4965. DWORD CurFieldIndex;
  4966. PCTSTR CurTargetDecoration, ModelsSectionName;
  4967. PCTSTR BestTargetDecoration = NULL;
  4968. INT SectionNameLen;
  4969. TCHAR DecBuffer[MAX_SECT_NAME_LEN];
  4970. PTSTR CurDecPtr, NextDecPtr;
  4971. DWORD BestMajorVer = 0, BestMinorVer = 0;
  4972. DWORD BestDecIncludesMask = 0;
  4973. DWORD CurMajorVer, CurMinorVer;
  4974. BYTE ProductType;
  4975. WORD SuiteMask;
  4976. INT TempInt;
  4977. DWORD CurDecIncludesMask;
  4978. BOOL NewBestFound;
  4979. OSVERSIONINFOEX OsVersionInfoEx;
  4980. DWORDLONG ConditionMask;
  4981. DWORD TypeMask;
  4982. DWORD Platform;
  4983. PCTSTR NtArchSuffix;
  4984. //
  4985. // Set OsVersionInfoEx size field to zero as a flag to indicate that
  4986. // structure initialization is necessary if we end up needing to call
  4987. // VerifyVersionInfo later.
  4988. //
  4989. OsVersionInfoEx.dwOSVersionInfoSize = 0;
  4990. //
  4991. // Determine which platform we should be looking for...
  4992. //
  4993. Platform = AltPlatformInfo ? AltPlatformInfo->Platform
  4994. : OSVersionInfo.dwPlatformId;
  4995. //
  4996. // ...as well as which OS/architecture decoration. (Note that we skip the
  4997. // first character of the platform suffix, since we don't want the
  4998. // leading '.')
  4999. //
  5000. if(AltPlatformInfo) {
  5001. switch(AltPlatformInfo->ProcessorArchitecture) {
  5002. case PROCESSOR_ARCHITECTURE_INTEL :
  5003. NtArchSuffix = &(pszNtX86Suffix[1]);
  5004. break;
  5005. case PROCESSOR_ARCHITECTURE_ALPHA :
  5006. NtArchSuffix = &(pszNtAlphaSuffix[1]);
  5007. break;
  5008. case PROCESSOR_ARCHITECTURE_IA64 :
  5009. NtArchSuffix = &(pszNtIA64Suffix[1]);
  5010. break;
  5011. case PROCESSOR_ARCHITECTURE_ALPHA64 :
  5012. NtArchSuffix = &(pszNtAXP64Suffix[1]);
  5013. break;
  5014. case PROCESSOR_ARCHITECTURE_AMD64 :
  5015. NtArchSuffix = &(pszNtAMD64Suffix[1]);
  5016. break;
  5017. default:
  5018. //
  5019. // Unknown/invalid architecture
  5020. //
  5021. return FALSE;
  5022. }
  5023. } else {
  5024. NtArchSuffix = &(pszNtPlatformSuffix[1]);
  5025. }
  5026. //
  5027. // TargetDecoration fields start at field index 2...
  5028. //
  5029. for(CurFieldIndex = 2;
  5030. CurTargetDecoration = InfGetField(Inf, MfgListLine, CurFieldIndex, NULL);
  5031. CurFieldIndex++)
  5032. {
  5033. //
  5034. // Copy the TargetDecoration into a scratch buffer so we can extract
  5035. // the various fields from it.
  5036. //
  5037. lstrcpyn(DecBuffer, CurTargetDecoration, SIZECHARS(DecBuffer));
  5038. //
  5039. // First part is traditional per-OS/architecture decoration.
  5040. //
  5041. CurMajorVer = CurMinorVer = 0;
  5042. CurDecIncludesMask = 0;
  5043. CurDecPtr = _tcschr(DecBuffer, TEXT('.'));
  5044. if(CurDecPtr) {
  5045. *CurDecPtr = TEXT('\0');
  5046. }
  5047. if(Platform == VER_PLATFORM_WIN32_NT) {
  5048. //
  5049. // We're on NT, so first try the NT architecture-specific
  5050. // extension, then the generic NT extension.
  5051. //
  5052. if(!lstrcmpi(DecBuffer, NtArchSuffix)) {
  5053. CurDecIncludesMask |= DEC_INCLUDES_ARCHITECTURE;
  5054. } else if(lstrcmpi(DecBuffer, &(pszNtSuffix[1]))) {
  5055. //
  5056. // TargetDecoration isn't applicable for this OS/architecture.
  5057. // Skip it and continue on to the next one.
  5058. //
  5059. continue;
  5060. }
  5061. } else {
  5062. //
  5063. // We're on Win9x, so try the Windows-specific extension
  5064. //
  5065. if(lstrcmpi(DecBuffer, &(pszWinSuffix[1]))) {
  5066. //
  5067. // TargetDecoration isn't applicable for this OS.
  5068. // Skip it and continue on to the next one.
  5069. //
  5070. continue;
  5071. }
  5072. }
  5073. //
  5074. // If we get to here, then the decoration is applicable to the
  5075. // OS/architecture under which we're running (or for which alt platform
  5076. // info was specified)
  5077. //
  5078. if(CurDecPtr) {
  5079. //
  5080. // Version info is included--extract the supplied components and
  5081. // use VerifyVersionInfo to see if they're valid for the OS version
  5082. // under which we're running.
  5083. //
  5084. //
  5085. // Get major version...
  5086. //
  5087. NextDecPtr = _tcschr(++CurDecPtr, TEXT('.'));
  5088. if(NextDecPtr) {
  5089. *NextDecPtr = TEXT('\0');
  5090. }
  5091. if(!pAToI(CurDecPtr, &TempInt) || (TempInt < 0)) {
  5092. continue;
  5093. }
  5094. CurMajorVer = (DWORD)TempInt;
  5095. if(NextDecPtr) {
  5096. CurDecPtr = NextDecPtr + 1;
  5097. } else {
  5098. //
  5099. // No more fields to retrieve--assume minor version of 0.
  5100. //
  5101. CurMinorVer = 0;
  5102. goto AllFieldsRetrieved;
  5103. }
  5104. //
  5105. // Get minor version...
  5106. //
  5107. NextDecPtr = _tcschr(CurDecPtr, TEXT('.'));
  5108. if(NextDecPtr) {
  5109. *NextDecPtr = TEXT('\0');
  5110. }
  5111. if(!pAToI(CurDecPtr, &TempInt) || (TempInt < 0)) {
  5112. continue;
  5113. }
  5114. CurMinorVer = (DWORD)TempInt;
  5115. //
  5116. // If minor version is supplied, then major version must be
  5117. // supplied as well.
  5118. //
  5119. if(CurMinorVer && !CurMajorVer) {
  5120. continue;
  5121. }
  5122. if(NextDecPtr && !AltPlatformInfo) {
  5123. CurDecPtr = NextDecPtr + 1;
  5124. } else {
  5125. //
  5126. // No more fields to retrieve
  5127. //
  5128. goto AllFieldsRetrieved;
  5129. }
  5130. //
  5131. // Get product type
  5132. //
  5133. NextDecPtr = _tcschr(CurDecPtr, TEXT('.'));
  5134. if(NextDecPtr) {
  5135. *NextDecPtr = TEXT('\0');
  5136. }
  5137. if(!pAToI(CurDecPtr, &TempInt) ||
  5138. (TempInt < 0) || (TempInt > 0xff)) {
  5139. continue;
  5140. }
  5141. ProductType = (BYTE)TempInt;
  5142. if(ProductType) {
  5143. CurDecIncludesMask |= DEC_INCLUDES_PRODUCTTYPE;
  5144. }
  5145. if(NextDecPtr) {
  5146. CurDecPtr = NextDecPtr + 1;
  5147. } else {
  5148. //
  5149. // No more fields to retrieve
  5150. //
  5151. goto AllFieldsRetrieved;
  5152. }
  5153. //
  5154. // Get suite mask. If we find another '.' in the TargetDecoration
  5155. // field, this indicates additional fields we don't know about
  5156. // (e.g., a future version of setupapi has added more fields, say,
  5157. // for service pack info). Since we don't know how to interpret
  5158. // these additional fields, an entry containing them must be
  5159. // skipped.
  5160. //
  5161. if(_tcschr(CurDecPtr, TEXT('.'))) {
  5162. continue;
  5163. }
  5164. if(!pAToI(CurDecPtr, &TempInt) ||
  5165. (TempInt < 0) || (TempInt > 0xffff)) {
  5166. continue;
  5167. }
  5168. SuiteMask = (WORD)TempInt;
  5169. if(SuiteMask) {
  5170. CurDecIncludesMask |= DEC_INCLUDES_SUITEMASK;
  5171. }
  5172. AllFieldsRetrieved :
  5173. if(AltPlatformInfo) {
  5174. //
  5175. // We're doing a non-native driver search, so we're on our own
  5176. // to do version comparison...
  5177. //
  5178. if((AltPlatformInfo->MajorVersion < CurMajorVer) ||
  5179. ((AltPlatformInfo->MajorVersion == CurMajorVer) &&
  5180. (AltPlatformInfo->MinorVersion < CurMinorVer))) {
  5181. //
  5182. // The alternate platform info is for an older (lower-
  5183. // versioned) OS than the current TargetDecoration.
  5184. //
  5185. continue;
  5186. }
  5187. } else {
  5188. //
  5189. // We're doing native driver searching, we can use the handy
  5190. // API, VerifyVersionInfo.
  5191. //
  5192. if(!OsVersionInfoEx.dwOSVersionInfoSize) {
  5193. //
  5194. // First time we've needed to call VerifyVersionInfo--must
  5195. // initialize the structure first...
  5196. //
  5197. ZeroMemory(&OsVersionInfoEx, sizeof(OsVersionInfoEx));
  5198. OsVersionInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  5199. }
  5200. TypeMask = 0;
  5201. ConditionMask = 0;
  5202. OsVersionInfoEx.dwMajorVersion = CurMajorVer;
  5203. OsVersionInfoEx.dwMinorVersion = CurMinorVer;
  5204. if(CurMajorVer) {
  5205. TypeMask |= (VER_MAJORVERSION | VER_MINORVERSION);
  5206. VER_SET_CONDITION(ConditionMask,
  5207. VER_MAJORVERSION,
  5208. VER_GREATER_EQUAL
  5209. );
  5210. VER_SET_CONDITION(ConditionMask,
  5211. VER_MINORVERSION,
  5212. VER_GREATER_EQUAL
  5213. );
  5214. }
  5215. if(CurDecIncludesMask & DEC_INCLUDES_PRODUCTTYPE) {
  5216. OsVersionInfoEx.wProductType = ProductType;
  5217. TypeMask |= VER_PRODUCT_TYPE;
  5218. VER_SET_CONDITION(ConditionMask,
  5219. VER_PRODUCT_TYPE,
  5220. VER_EQUAL
  5221. );
  5222. } else {
  5223. OsVersionInfoEx.wProductType = 0;
  5224. }
  5225. if(CurDecIncludesMask & DEC_INCLUDES_SUITEMASK) {
  5226. OsVersionInfoEx.wSuiteMask = SuiteMask;
  5227. TypeMask |= VER_SUITENAME;
  5228. VER_SET_CONDITION(ConditionMask,
  5229. VER_SUITENAME,
  5230. VER_AND
  5231. );
  5232. } else {
  5233. OsVersionInfoEx.wSuiteMask = 0;
  5234. }
  5235. //
  5236. // Only call VerifyVersionInfo if one or more criteria were
  5237. // supplied (otherwise, assume this TargetDecoration is applicable)
  5238. //
  5239. if(TypeMask) {
  5240. if(!VerifyVersionInfo(&OsVersionInfoEx, TypeMask, ConditionMask)) {
  5241. //
  5242. // TargetDecoration isn't applicable to current OS version.
  5243. //
  5244. continue;
  5245. }
  5246. }
  5247. }
  5248. }
  5249. //
  5250. // If we get to here, we have an applicable TargetDecoration--see if
  5251. // it's the best one we've seen thus far...
  5252. //
  5253. NewBestFound = FALSE;
  5254. if((CurMajorVer > BestMajorVer) ||
  5255. ((CurMajorVer == BestMajorVer) && (CurMinorVer > BestMinorVer))) {
  5256. //
  5257. // Newer version
  5258. //
  5259. NewBestFound = TRUE;
  5260. } else if((CurMajorVer == BestMajorVer) && (CurMinorVer == BestMinorVer)) {
  5261. //
  5262. // Version is same as current best. Is it as-specific or more so?
  5263. // NOTE: we update on "as-specific" (i.e., equal) matches to catch
  5264. // the case where our only applicable decoration is "NT". In that
  5265. // case, our best and current version is "0.0", and our masks are
  5266. // both zero as well.
  5267. //
  5268. if(CurDecIncludesMask >= BestDecIncludesMask) {
  5269. NewBestFound = TRUE;
  5270. }
  5271. }
  5272. if(NewBestFound) {
  5273. BestTargetDecoration = CurTargetDecoration;
  5274. BestMajorVer = CurMajorVer;
  5275. BestMinorVer = CurMinorVer;
  5276. BestDecIncludesMask = CurDecIncludesMask;
  5277. }
  5278. }
  5279. if(!BestTargetDecoration) {
  5280. //
  5281. // No applicable TargetDecoration was found.
  5282. //
  5283. return FALSE;
  5284. }
  5285. //
  5286. // Construct the decorated section name by appending the TargetDecoration
  5287. // to the models section name.
  5288. //
  5289. if(!(ModelsSectionName = InfGetField(Inf, MfgListLine, 1, NULL))) {
  5290. //
  5291. // Should never happen
  5292. //
  5293. MYASSERT(ModelsSectionName);
  5294. return FALSE;
  5295. }
  5296. lstrcpyn(DecoratedModelsSection, ModelsSectionName, MAX_SECT_NAME_LEN);
  5297. SectionNameLen = lstrlen(DecoratedModelsSection);
  5298. //
  5299. // Do we have enough space left for decoration + '.' + terminating NULL?
  5300. //
  5301. if((MAX_SECT_NAME_LEN - SectionNameLen) < (lstrlen(BestTargetDecoration) + 2)) {
  5302. //
  5303. // Decorated section name exceeds maximum length of a section name!
  5304. //
  5305. WriteLogEntry(
  5306. LogContext,
  5307. DRIVER_LOG_ERROR,
  5308. MSG_LOG_DEC_MODELS_SEC_TOO_LONG,
  5309. NULL,
  5310. ModelsSectionName,
  5311. BestTargetDecoration,
  5312. MAX_SECT_NAME_LEN
  5313. );
  5314. return FALSE;
  5315. }
  5316. DecoratedModelsSection[SectionNameLen++] = TEXT('.');
  5317. lstrcpy(&(DecoratedModelsSection[SectionNameLen]), BestTargetDecoration);
  5318. return TRUE;
  5319. }