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.

760 lines
27 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. devoem.c
  5. Abstract:
  6. Device Installer functions for dealing with OEM drivers.
  7. Author:
  8. Lonny McMichael (lonnym) 10-Aug-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. BOOL
  14. WINAPI
  15. SetupDiAskForOEMDisk(
  16. IN HDEVINFO DeviceInfoSet,
  17. IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  18. )
  19. /*++
  20. Routine Description:
  21. This routine displays a dialog asking for the path to an OEM install disk.
  22. Arguments:
  23. DeviceInfoSet - Supplies a handle to the device information set containing
  24. the device being installed.
  25. DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
  26. structure for the device being installed. If this parameter is not
  27. specified, then the driver being installed is associated with the
  28. global class driver list of the device information set itself.
  29. Return Value:
  30. If the function succeeds, the return value is TRUE.
  31. If the user cancels the dialog, the return value is FALSE, and GetLastError
  32. will return ERROR_CANCELLED.
  33. If the function fails, the return value is FALSE, and GetLastError returns
  34. a Win32 error code indicating the cause of the failure.
  35. Remarks:
  36. This routine will allow browsing of local and network drives for OEM
  37. install files.
  38. --*/
  39. {
  40. PDEVICE_INFO_SET pDeviceInfoSet = NULL;
  41. DWORD Err;
  42. PDEVINFO_ELEM DevInfoElem;
  43. TCHAR Title[MAX_TITLE_LEN];
  44. PDEVINSTALL_PARAM_BLOCK dipb;
  45. TCHAR PathBuffer[MAX_PATH];
  46. UINT PromptResult;
  47. LONG DriverPathId;
  48. //
  49. // Make sure we're running interactively.
  50. //
  51. try {
  52. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  53. Err = ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION;
  54. leave;
  55. }
  56. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  57. Err = ERROR_INVALID_HANDLE;
  58. leave;
  59. }
  60. if(DeviceInfoData) {
  61. //
  62. // Then we are to prompt for an OEM driver for a particular device.
  63. //
  64. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  65. DeviceInfoData,
  66. NULL))) {
  67. Err = ERROR_INVALID_PARAMETER;
  68. leave;
  69. }
  70. dipb = &(DevInfoElem->InstallParamBlock);
  71. } else {
  72. dipb = &(pDeviceInfoSet->InstallParamBlock);
  73. }
  74. if(!LoadString(MyDllModuleHandle,
  75. IDS_OEMTITLE,
  76. Title,
  77. SIZECHARS(Title))) {
  78. Title[0] = TEXT('\0');
  79. }
  80. PromptResult = SetupPromptForDisk(dipb->hwndParent,
  81. (*Title) ? Title : NULL,
  82. NULL,
  83. pszOemInfDefaultPath,
  84. pszInfWildcard,
  85. NULL,
  86. IDF_OEMDISK | IDF_NOCOMPRESSED | IDF_NOSKIP,
  87. PathBuffer,
  88. SIZECHARS(PathBuffer),
  89. NULL
  90. );
  91. if(PromptResult == DPROMPT_CANCEL) {
  92. Err = ERROR_CANCELLED;
  93. } else if(PromptResult == DPROMPT_OUTOFMEMORY) {
  94. Err = ERROR_NOT_ENOUGH_MEMORY;
  95. } else {
  96. //
  97. // A choice was made--replace old path with new one.
  98. //
  99. if((DriverPathId = pStringTableAddString(
  100. pDeviceInfoSet->StringTable,
  101. PathBuffer,
  102. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  103. NULL,0)) == -1) {
  104. Err = ERROR_NOT_ENOUGH_MEMORY;
  105. } else {
  106. dipb->DriverPath = DriverPathId;
  107. Err = NO_ERROR;
  108. }
  109. }
  110. } except(pSetupExceptionFilter(GetExceptionCode())) {
  111. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  112. }
  113. if(pDeviceInfoSet) {
  114. UnlockDeviceInfoSet(pDeviceInfoSet);
  115. }
  116. SetLastError(Err);
  117. return (Err == NO_ERROR);
  118. }
  119. BOOL
  120. WINAPI
  121. SetupDiSelectOEMDrv(
  122. IN HWND hwndParent, OPTIONAL
  123. IN HDEVINFO DeviceInfoSet,
  124. IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  125. )
  126. /*++
  127. Routine Description:
  128. This routine selects a driver for a device using an OEM path supplied by
  129. the user.
  130. Arguments:
  131. hwndParent - Optionally, supplies a window handle that will be the parent
  132. of any dialogs created during this routine. This parameter may be
  133. used to override the hwndParent field in the install parameters block
  134. of the specified device information set or element.
  135. DeviceInfoSet - Supplies a handle to the device information set containing
  136. the device being installed.
  137. DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
  138. structure for the device being installed. If this parameter is not
  139. specified, then the driver being installed is associated with the
  140. global class driver list of the device information set itself.
  141. This is an IN OUT parameter because the class GUID of this device
  142. information element will be updated upon return to reflect the class
  143. of the most-compatible driver found, if a compatible driver list was
  144. built.
  145. Return Value:
  146. If the function succeeds (i.e., a driver is selected successfully), the
  147. return value is TRUE.
  148. If the function fails, the return value is FALSE. To get extended error
  149. information, call GetLastError.
  150. Remarks:
  151. This routine will first ask the user for the OEM path, and will then call
  152. the class installer to select a driver from that OEM path.
  153. --*/
  154. {
  155. DWORD Err;
  156. try {
  157. //
  158. // Make sure we're running interactively.
  159. //
  160. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  161. Err = ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION;
  162. leave;
  163. }
  164. Err = SelectOEMDriver(hwndParent, DeviceInfoSet, DeviceInfoData, FALSE);
  165. } except(pSetupExceptionFilter(GetExceptionCode())) {
  166. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  167. }
  168. SetLastError(Err);
  169. return (Err == NO_ERROR);
  170. }
  171. DWORD
  172. SelectOEMDriver(
  173. IN HWND hwndParent, OPTIONAL
  174. IN HDEVINFO DeviceInfoSet,
  175. IN OUT PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  176. IN BOOL IsWizard
  177. )
  178. /*++
  179. Routine Description:
  180. This is the worker routine that actually allows for the selection of an OEM
  181. driver.
  182. Arguments:
  183. hwndParent - Optionally, supplies the window handle that is to be the
  184. parent for any selection UI. If this parameter is not supplied, then
  185. the hwndParent field of the devinfo set or element will be used.
  186. DeviceInfoSet - Supplies the handle of the device info set for which an
  187. OEM driver selection is to be performed.
  188. DeviceInfoData - Optionally, supplies the address of the device information
  189. element to select a driver for. If this parameter is not supplied,
  190. then an OEM driver for the global class driver list will be selected.
  191. If a compatible driver was found for this device, the device
  192. information element will have its class GUID updated upon return to
  193. reflect the device's new class.
  194. IsWizard - Specifies whether this routine is being called in the context of
  195. a select device wizard page.
  196. Return Value:
  197. If successful, the return value is NO_ERROR. Otherwise, it is a Win32
  198. error code indicating the cause of failure.
  199. Note that it is possible to get an error code of ERROR_DI_DO_DEFAULT. This
  200. will happen more often for the wizard case, where we suppress invocation of
  201. the default handler for DIF_SELECTDEVICE.
  202. --*/
  203. {
  204. PDEVICE_INFO_SET pDeviceInfoSet = NULL;
  205. PDEVINFO_ELEM DevInfoElem = NULL;
  206. PDEVINSTALL_PARAM_BLOCK dipb;
  207. DWORD Err = NO_ERROR;
  208. HWND hwndSave;
  209. LONG DriverPathSave;
  210. DWORD DriverPathFlagsSave;
  211. BOOL bRestoreHwnd = FALSE, bRestoreDriverPath = FALSE, bUnlockDevInfoElem = FALSE;
  212. BOOL bDontSave = FALSE;
  213. UINT NewClassDriverCount;
  214. UINT NewCompatDriverCount;
  215. BOOL bAskAgain = TRUE;
  216. TCHAR Title[MAX_TITLE_LEN];
  217. DWORD SavedFlags;
  218. HCURSOR hOldCursor;
  219. PDRIVER_NODE lpOrgCompat;
  220. PDRIVER_NODE lpOrgCompatTail;
  221. UINT OrgCompatCount;
  222. PDRIVER_NODE lpOrgClass;
  223. PDRIVER_NODE lpOrgClassTail;
  224. UINT OrgClassCount;
  225. PDRIVER_NODE lpOrgSel;
  226. DWORD dwOrgSelType;
  227. DWORD dwOrgFlags;
  228. DWORD dwOrgFlagsEx;
  229. BOOL bRestoreDeviceInfo = FALSE;
  230. try {
  231. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  232. Err = ERROR_INVALID_HANDLE;
  233. leave;
  234. }
  235. if(DeviceInfoData) {
  236. //
  237. // Then we're working with a particular device.
  238. //
  239. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  240. DeviceInfoData,
  241. NULL))) {
  242. Err = ERROR_INVALID_PARAMETER;
  243. leave;
  244. }
  245. //
  246. // If the DevInfoElem isn't already locked, then lock it now, because
  247. // we're going to be calling the class installer, and we don't want to
  248. // allow it to delete this element!
  249. //
  250. if(!(DevInfoElem->DiElemFlags & DIE_IS_LOCKED)) {
  251. DevInfoElem->DiElemFlags |= DIE_IS_LOCKED;
  252. bUnlockDevInfoElem = TRUE;
  253. }
  254. dipb = &(DevInfoElem->InstallParamBlock);
  255. } else {
  256. dipb = &(pDeviceInfoSet->InstallParamBlock);
  257. }
  258. //
  259. // Make this selection window the parent window for OEM stuff
  260. //
  261. if(hwndParent) {
  262. hwndSave = dipb->hwndParent;
  263. dipb->hwndParent = hwndParent;
  264. bRestoreHwnd = TRUE;
  265. }
  266. //
  267. // Don't assume there is no old OEM path. Save old one and
  268. // pretend there is no old one in case of cancel.
  269. //
  270. DriverPathSave = dipb->DriverPath;
  271. dipb->DriverPath = -1;
  272. //
  273. // Clear the DI_ENUMSINGLEINF flag, because we're going to be getting
  274. // a path to a directory, _not_ to an individual INF. Also, clear the
  275. // DI_COMPAT_FROM_CLASS flag, because we don't want to build the compatible
  276. // driver list based on any class driver list.
  277. //
  278. DriverPathFlagsSave = dipb->Flags & (DI_ENUMSINGLEINF | DI_COMPAT_FROM_CLASS);
  279. dipb->Flags &= ~(DI_ENUMSINGLEINF | DI_COMPAT_FROM_CLASS);
  280. bRestoreDriverPath = TRUE;
  281. while(bAskAgain &&
  282. (NO_ERROR == (Err = GLE_FN_CALL(FALSE, SetupDiAskForOEMDisk(
  283. DeviceInfoSet,
  284. DeviceInfoData)))))
  285. {
  286. bAskAgain = FALSE;
  287. //
  288. // Save the Original List info, in case we get
  289. // an empty list on the user's selected path.
  290. //
  291. // (Note: we don't attempt to save/restore our driver enumeration
  292. // hints.)
  293. //
  294. if(!bDontSave) {
  295. if(DevInfoElem) {
  296. lpOrgCompat = DevInfoElem->CompatDriverHead;
  297. lpOrgCompatTail = DevInfoElem->CompatDriverTail;
  298. OrgCompatCount = DevInfoElem->CompatDriverCount;
  299. lpOrgClass = DevInfoElem->ClassDriverHead;
  300. lpOrgClassTail = DevInfoElem->ClassDriverTail;
  301. OrgClassCount = DevInfoElem->ClassDriverCount;
  302. lpOrgSel = DevInfoElem->SelectedDriver;
  303. dwOrgSelType = DevInfoElem->SelectedDriverType;
  304. } else {
  305. lpOrgClass = pDeviceInfoSet->ClassDriverHead;
  306. lpOrgClassTail = pDeviceInfoSet->ClassDriverTail;
  307. OrgClassCount = pDeviceInfoSet->ClassDriverCount;
  308. lpOrgSel = pDeviceInfoSet->SelectedClassDriver;
  309. dwOrgSelType = lpOrgSel ? SPDIT_CLASSDRIVER : SPDIT_NODRIVER;
  310. }
  311. dwOrgFlags = dipb->Flags;
  312. dwOrgFlagsEx = dipb->FlagsEx;
  313. bRestoreDeviceInfo = TRUE;
  314. }
  315. if(DevInfoElem) {
  316. DevInfoElem->CompatDriverHead = DevInfoElem->CompatDriverTail = NULL;
  317. DevInfoElem->CompatDriverCount = 0;
  318. DevInfoElem->CompatDriverEnumHint = NULL;
  319. DevInfoElem->CompatDriverEnumHintIndex = INVALID_ENUM_INDEX;
  320. DevInfoElem->ClassDriverHead = DevInfoElem->ClassDriverTail = NULL;
  321. DevInfoElem->ClassDriverCount = 0;
  322. DevInfoElem->ClassDriverEnumHint = NULL;
  323. DevInfoElem->ClassDriverEnumHintIndex = INVALID_ENUM_INDEX;
  324. DevInfoElem->SelectedDriver = NULL;
  325. DevInfoElem->SelectedDriverType = SPDIT_NODRIVER;
  326. } else {
  327. lpOrgCompat = NULL; // just so we won't ever try to free this list.
  328. pDeviceInfoSet->ClassDriverHead = pDeviceInfoSet->ClassDriverTail = NULL;
  329. pDeviceInfoSet->ClassDriverCount = 0;
  330. pDeviceInfoSet->ClassDriverEnumHint = NULL;
  331. pDeviceInfoSet->ClassDriverEnumHintIndex = INVALID_ENUM_INDEX;
  332. pDeviceInfoSet->SelectedClassDriver = NULL;
  333. }
  334. SavedFlags = dipb->Flags & (DI_SHOWOEM | DI_NODI_DEFAULTACTION);
  335. dipb->Flags &= ~(DI_DIDCOMPAT | DI_DIDCLASS | DI_MULTMFGS | DI_SHOWOEM);
  336. dipb->FlagsEx &= ~(DI_FLAGSEX_DIDINFOLIST | DI_FLAGSEX_DIDCOMPATINFO);
  337. if(IsWizard) {
  338. //
  339. // We don't want default action taken in the wizard case.
  340. //
  341. dipb->Flags |= DI_NODI_DEFAULTACTION;
  342. }
  343. //
  344. // Unlock the HDEVINFO before handling the Select Device.
  345. // Otherwise, our multi-threaded dialog will deadlock!
  346. //
  347. UnlockDeviceInfoSet(pDeviceInfoSet);
  348. pDeviceInfoSet = NULL;
  349. Err = _SetupDiCallClassInstaller(
  350. DIF_SELECTDEVICE,
  351. DeviceInfoSet,
  352. DeviceInfoData,
  353. CALLCI_LOAD_HELPERS | CALLCI_CALL_HELPERS
  354. );
  355. //
  356. // Now, re-acquire the lock on our device information set.
  357. //
  358. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  359. //
  360. // we should never get here - could be indicative of
  361. // class/co-installer messing up
  362. //
  363. MYASSERT(pDeviceInfoSet);
  364. if(Err == NO_ERROR) {
  365. Err = ERROR_INVALID_HANDLE;
  366. }
  367. leave;
  368. }
  369. //
  370. // Restore the saved flags.
  371. //
  372. dipb->Flags = (dipb->Flags & ~(DI_SHOWOEM | DI_NODI_DEFAULTACTION)) | SavedFlags;
  373. //
  374. // If the class installer returned ERROR_DI_DO_DEFAULT, then
  375. // they either did not process the DIF_SELECTDEVICE, or they
  376. // have setup our device info structure with an OEM INF.
  377. //
  378. switch(Err) {
  379. case ERROR_DI_DO_DEFAULT :
  380. //
  381. // This case is only handled if we're in a wizard.
  382. // Otherwise, send it down for default processing.
  383. //
  384. if(!IsWizard) {
  385. goto DefaultHandling;
  386. }
  387. //
  388. // This will be the most likely return, since we are not
  389. // allowing the default handler to be called. So we will
  390. // build a new class Drv list If it is empty we will ask
  391. // again, otherwise we will accept the new selection and go
  392. // on.
  393. //
  394. hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  395. SetupDiBuildDriverInfoList(DeviceInfoSet,
  396. DeviceInfoData,
  397. SPDIT_CLASSDRIVER
  398. );
  399. SetupDiBuildDriverInfoList(DeviceInfoSet,
  400. DeviceInfoData,
  401. SPDIT_COMPATDRIVER
  402. );
  403. SetCursor(hOldCursor);
  404. if(DevInfoElem) {
  405. NewClassDriverCount = DevInfoElem->ClassDriverCount;
  406. NewCompatDriverCount = DevInfoElem->CompatDriverCount;
  407. } else {
  408. NewClassDriverCount = pDeviceInfoSet->ClassDriverCount;
  409. NewCompatDriverCount = 0;
  410. }
  411. if(!NewClassDriverCount && !NewCompatDriverCount) {
  412. //
  413. // Error.
  414. //
  415. if(!LoadString(MyDllModuleHandle,
  416. IDS_SELECT_DEVICE,
  417. Title,
  418. SIZECHARS(Title))) {
  419. *Title = TEXT('\0');
  420. }
  421. FormatMessageBox(MyDllModuleHandle,
  422. NULL,
  423. MSG_NO_DEVICEINFO_ERROR,
  424. Title,
  425. MB_OK | MB_TASKMODAL
  426. );
  427. bDontSave = TRUE;
  428. //
  429. // Clean up anything that happened to get put in here.
  430. //
  431. if(DevInfoElem &&
  432. (DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDCOMPATINFO)) {
  433. //
  434. // The class installer built a compatible driver list--kill it here.
  435. //
  436. DestroyDriverNodes(DevInfoElem->CompatDriverHead, pDeviceInfoSet);
  437. DevInfoElem->CompatDriverHead = DevInfoElem->CompatDriverTail = NULL;
  438. DevInfoElem->CompatDriverCount = 0;
  439. DevInfoElem->InstallParamBlock.Flags &= ~DI_DIDCOMPAT;
  440. DevInfoElem->InstallParamBlock.FlagsEx &= ~DI_FLAGSEX_DIDCOMPATINFO;
  441. DevInfoElem->SelectedDriver = NULL;
  442. DevInfoElem->SelectedDriverType = SPDIT_NODRIVER;
  443. }
  444. dipb->DriverPath = -1;
  445. bAskAgain = TRUE;
  446. break;
  447. }
  448. //
  449. // Successfully retrieved one or more class and/or compat
  450. // drivers. Drop on through into processing of NO_ERROR
  451. // case...
  452. //
  453. case NO_ERROR :
  454. //
  455. // Destroy the original lists
  456. //
  457. if(bRestoreDeviceInfo) {
  458. DestroyDriverNodes(lpOrgCompat, pDeviceInfoSet);
  459. DereferenceClassDriverList(pDeviceInfoSet, lpOrgClass);
  460. bRestoreDeviceInfo = FALSE;
  461. }
  462. bRestoreDriverPath = FALSE;
  463. break;
  464. case ERROR_DI_BAD_PATH :
  465. //
  466. // Pop up an error messagebox, then go try again.
  467. //
  468. if(!LoadString(MyDllModuleHandle,
  469. IDS_SELECT_DEVICE,
  470. Title,
  471. SIZECHARS(Title))) {
  472. *Title = TEXT('\0');
  473. }
  474. FormatMessageBox(MyDllModuleHandle,
  475. NULL,
  476. MSG_NO_DEVICEINFO_ERROR,
  477. Title,
  478. MB_OK | MB_TASKMODAL
  479. );
  480. bDontSave = TRUE;
  481. dipb->DriverPath = -1;
  482. bAskAgain = TRUE;
  483. //
  484. // Allow to fall through to default processing to delete
  485. // the current driver list(s).
  486. //
  487. default :
  488. DefaultHandling:
  489. //
  490. // Destroy the current driver list(s).
  491. //
  492. if(DevInfoElem) {
  493. DestroyDriverNodes(DevInfoElem->CompatDriverHead, pDeviceInfoSet);
  494. DevInfoElem->CompatDriverHead = DevInfoElem->CompatDriverTail = NULL;
  495. DevInfoElem->CompatDriverCount = 0;
  496. DereferenceClassDriverList(pDeviceInfoSet, DevInfoElem->ClassDriverHead);
  497. DevInfoElem->ClassDriverHead = DevInfoElem->ClassDriverTail = NULL;
  498. DevInfoElem->ClassDriverCount = 0;
  499. DevInfoElem->SelectedDriver = NULL;
  500. DevInfoElem->SelectedDriverType = SPDIT_NODRIVER;
  501. } else if(pDeviceInfoSet) {
  502. DereferenceClassDriverList(pDeviceInfoSet, pDeviceInfoSet->ClassDriverHead);
  503. pDeviceInfoSet->ClassDriverHead = pDeviceInfoSet->ClassDriverTail = NULL;
  504. pDeviceInfoSet->ClassDriverCount = 0;
  505. pDeviceInfoSet->SelectedClassDriver = NULL;
  506. }
  507. }
  508. }
  509. } except(pSetupExceptionFilter(GetExceptionCode())) {
  510. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  511. }
  512. //
  513. // If we need to restore any state, then we must make sure that we have the
  514. // HDEVINFO locked.
  515. //
  516. try {
  517. if(bRestoreDeviceInfo || bUnlockDevInfoElem || bRestoreHwnd || bRestoreDriverPath) {
  518. if(!pDeviceInfoSet && !(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  519. //
  520. // shouldn't get here, indicative of class/co-installer messing
  521. // up
  522. //
  523. MYASSERT(pDeviceInfoSet);
  524. if(Err == NO_ERROR) {
  525. Err = ERROR_INVALID_HANDLE;
  526. }
  527. leave;
  528. } else {
  529. //
  530. // If we locked the DevInfoElem just for this API, then unlock
  531. // it now.
  532. //
  533. if(bUnlockDevInfoElem) {
  534. MYASSERT(DevInfoElem);
  535. DevInfoElem->DiElemFlags &= ~DIE_IS_LOCKED;
  536. }
  537. //
  538. // If the install param block needs its parent hwnd restored,
  539. // do so now.
  540. //
  541. if(bRestoreHwnd) {
  542. dipb->hwndParent = hwndSave;
  543. }
  544. //
  545. // Likewise, restore the old driver path if necessary.
  546. //
  547. if(bRestoreDriverPath) {
  548. dipb->DriverPath = DriverPathSave;
  549. dipb->Flags |= DriverPathFlagsSave;
  550. }
  551. //
  552. // If necessary, restore the original list(s).
  553. //
  554. if(bRestoreDeviceInfo) {
  555. if(DevInfoElem) {
  556. DestroyDriverNodes(DevInfoElem->CompatDriverHead, pDeviceInfoSet);
  557. DevInfoElem->CompatDriverHead = lpOrgCompat;
  558. DevInfoElem->CompatDriverTail = lpOrgCompatTail;
  559. DevInfoElem->CompatDriverCount = OrgCompatCount;
  560. lpOrgCompat = NULL;
  561. DereferenceClassDriverList(pDeviceInfoSet, DevInfoElem->ClassDriverHead);
  562. DevInfoElem->ClassDriverHead = lpOrgClass;
  563. DevInfoElem->ClassDriverTail = lpOrgClassTail;
  564. DevInfoElem->ClassDriverCount = OrgClassCount;
  565. lpOrgClass = NULL;
  566. DevInfoElem->SelectedDriver = lpOrgSel;
  567. DevInfoElem->SelectedDriverType = dwOrgSelType;
  568. } else {
  569. DereferenceClassDriverList(pDeviceInfoSet, pDeviceInfoSet->ClassDriverHead);
  570. pDeviceInfoSet->ClassDriverHead = lpOrgClass;
  571. pDeviceInfoSet->ClassDriverTail = lpOrgClassTail;
  572. pDeviceInfoSet->ClassDriverCount = OrgClassCount;
  573. lpOrgClass = NULL;
  574. pDeviceInfoSet->SelectedClassDriver = lpOrgSel;
  575. }
  576. dipb->Flags = dwOrgFlags;
  577. dipb->FlagsEx = dwOrgFlagsEx;
  578. }
  579. }
  580. }
  581. } except(pSetupExceptionFilter(GetExceptionCode())) {
  582. pSetupExceptionHandler(GetExceptionCode(),
  583. ERROR_INVALID_PARAMETER,
  584. (Err == NO_ERROR) ? &Err : NULL
  585. );
  586. if(pDeviceInfoSet && bRestoreDeviceInfo) {
  587. //
  588. // If we hit an exception before we got a chance to restore any of
  589. // our stored-away driver lists, then clean those up here.
  590. //
  591. if(DevInfoElem) {
  592. if(lpOrgCompat) {
  593. DestroyDriverNodes(lpOrgCompat, pDeviceInfoSet);
  594. }
  595. if(lpOrgClass) {
  596. DereferenceClassDriverList(pDeviceInfoSet, lpOrgClass);
  597. }
  598. } else {
  599. if(lpOrgClass) {
  600. DereferenceClassDriverList(pDeviceInfoSet, lpOrgClass);
  601. }
  602. }
  603. }
  604. }
  605. if(pDeviceInfoSet) {
  606. UnlockDeviceInfoSet(pDeviceInfoSet);
  607. }
  608. return Err;
  609. }