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

758 lines
26 KiB

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