Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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