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.

6112 lines
220 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. devwiz.c
  5. Abstract:
  6. Device Installer functions for install wizard support.
  7. Author:
  8. Lonny McMichael (lonnym) 22-Sep-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // Define some macros to make the code a little cleaner.
  15. //
  16. //
  17. // BOOL
  18. // USE_CI_SELSTRINGS(
  19. // IN PDEVINSTALL_PARAM_BLOCK p
  20. // );
  21. //
  22. // This macro checks all the appropriate values to determine whether the
  23. // class-installer provided strings may be used in the wizard.
  24. //
  25. #define USE_CI_SELSTRINGS(p) \
  26. \
  27. (((((p)->Flags) & (DI_USECI_SELECTSTRINGS | DI_CLASSINSTALLPARAMS)) == \
  28. (DI_USECI_SELECTSTRINGS | DI_CLASSINSTALLPARAMS)) && \
  29. (((p)->ClassInstallHeader->InstallFunction) == DIF_SELECTDEVICE))
  30. //
  31. // PTSTR
  32. // GET_CI_SELSTRING(
  33. // IN PDEVINSTALL_PARAM_BLOCK p,
  34. // IN <FieldName> f
  35. // );
  36. //
  37. // This macro retrieves a pointer to the specified string in a
  38. // SP_SELECTDEVICE_PARAMS structure.
  39. //
  40. #define GET_CI_SELSTRINGS(p, f) \
  41. \
  42. (((PSP_SELECTDEVICE_PARAMS)((p)->ClassInstallHeader))->f)
  43. //
  44. // Definitions for timer used in device selection listboxes.
  45. //
  46. #define SELECTMFG_TIMER_ID 1
  47. #define SELECTMFG_TIMER_DELAY 250
  48. //
  49. // Define a message sent from our auxilliary class driver search thread.
  50. //
  51. #define WMX_CLASSDRVLIST_DONE (WM_USER+131)
  52. #define WMX_NO_DRIVERS_IN_LIST (WM_USER+132)
  53. //
  54. // HELP ID's
  55. //
  56. static const DWORD SelectDeviceShowAllHelpIDs[]=
  57. {
  58. IDC_NDW_PICKDEV_MFGLIST, IDH_DEVMGR_SELECTDEVICE_MANUFACTURER,
  59. IDC_NDW_PICKDEV_ONEMFG_DRVLIST, IDH_DEVMGR_SELECTDEVICE_MODEL,
  60. IDC_NDW_PICKDEV_DRVLIST, IDH_DEVMGR_SELECTDEVICE_MODEL,
  61. IDC_NDW_STATUS_TEXT, IDH_NOHELP,
  62. IDC_CLASSICON, IDH_NOHELP,
  63. IDC_NDW_PICKDEV_COMPAT, IDH_DEVMGR_SELECTDEVICE_SHOWCOMPATIBLE,
  64. IDC_NDW_PICKDEV_WINDOWSUPDATE, IDH_DEVMGR_SELECTDEVICE_WINDOWSUPDATE,
  65. IDC_NDW_PICKDEV_HAVEDISK, IDH_DEVMGR_SELECTDEVICE_HAVEDISK,
  66. IDC_NDW_TEXT, IDH_NOHELP,
  67. IDD_DEVINSLINE, IDH_NOHELP,
  68. 0, 0
  69. };
  70. static const DWORD SelectDeviceShowSimilarHelpIDs[]=
  71. {
  72. IDC_NDW_PICKDEV_MFGLIST, IDH_DEVMGR_SELECTDEVICE_MANUFACTURER,
  73. IDC_NDW_PICKDEV_ONEMFG_DRVLIST, IDH_DEVMGR_SELECTDEVICE_MODEL,
  74. IDC_NDW_PICKDEV_DRVLIST, IDH_DEVMGR_SELECTDEVICE_MODEL,
  75. IDC_NDW_STATUS_TEXT, IDH_NOHELP,
  76. IDC_CLASSICON, IDH_NOHELP,
  77. IDC_NDW_PICKDEV_COMPAT, IDH_DEVMGR_SELECTDEVICE_SHOWCOMPATIBLE,
  78. IDC_NDW_PICKDEV_WINDOWSUPDATE, IDH_DEVMGR_SELECTDEVICE_WINDOWSUPDATE,
  79. IDC_NDW_PICKDEV_HAVEDISK, IDH_DEVMGR_SELECTDEVICE_HAVEDISK,
  80. IDC_NDW_TEXT, IDH_NOHELP,
  81. IDD_DEVINSLINE, IDH_NOHELP,
  82. 0, 0
  83. };
  84. #define SELECTDEVICE_HELP TEXT("devmgr.hlp")
  85. //
  86. // Define structure containing class driver search context that is passed to
  87. // an auxilliary thread while a Select Device dialog is displayed.
  88. //
  89. typedef struct _CLASSDRV_THREAD_CONTEXT {
  90. HDEVINFO DeviceInfoSet;
  91. SP_DEVINFO_DATA DeviceInfoData;
  92. HWND NotificationWindow;
  93. } CLASSDRV_THREAD_CONTEXT, *PCLASSDRV_THREAD_CONTEXT;
  94. //
  95. // Private function prototypes
  96. //
  97. DWORD
  98. pSetupCreateNewDevWizData(
  99. IN PSP_INSTALLWIZARD_DATA InstallWizardData,
  100. OUT PNEWDEVWIZ_DATA *NewDeviceWizardData
  101. );
  102. UINT
  103. CALLBACK
  104. SelectDevicePropSheetPageProc(
  105. IN HWND hwnd,
  106. IN UINT uMsg,
  107. IN LPPROPSHEETPAGE ppsp
  108. );
  109. INT_PTR
  110. CALLBACK
  111. SelectDeviceDlgProc(
  112. IN HWND hwndDlg,
  113. IN UINT uMsg,
  114. IN WPARAM wParam,
  115. IN LPARAM lParam
  116. );
  117. BOOL
  118. InitSelectDeviceDlg(
  119. IN HWND hwndDlg,
  120. IN OUT PNEWDEVWIZ_DATA ndwData
  121. );
  122. VOID
  123. _OnSysColorChange(
  124. HWND hWnd,
  125. WPARAM wParam,
  126. LPARAM lParam
  127. );
  128. BOOL
  129. OnSetActive(
  130. IN HWND hwndDlg,
  131. IN OUT PNEWDEVWIZ_DATA ndwData
  132. );
  133. DWORD
  134. HandleSelectOEM(
  135. IN HWND hwndDlg,
  136. IN OUT PNEWDEVWIZ_DATA ndwData
  137. );
  138. DWORD
  139. HandleWindowsUpdate(
  140. IN HWND hwndDlg,
  141. IN OUT PNEWDEVWIZ_DATA ndwData
  142. );
  143. DWORD
  144. FillInDeviceList(
  145. IN HWND hwndDlg,
  146. IN PSP_DIALOGDATA lpdd
  147. );
  148. VOID
  149. ShowListForMfg(
  150. IN PSP_DIALOGDATA lpdd,
  151. IN PDEVICE_INFO_SET DeviceInfoSet,
  152. IN PDEVINSTALL_PARAM_BLOCK InstallParamBlock,
  153. IN PDRIVER_NODE DriverNode, OPTIONAL
  154. IN INT iMfg
  155. );
  156. VOID
  157. LockAndShowListForMfg(
  158. IN PSP_DIALOGDATA lpdd,
  159. IN INT iMfg
  160. );
  161. PDRIVER_NODE
  162. GetDriverNodeFromLParam(
  163. IN PDEVICE_INFO_SET DeviceInfoSet,
  164. IN PSP_DIALOGDATA lpdd,
  165. IN LPARAM lParam
  166. );
  167. BOOL
  168. pSetupIsSelectedHardwareIdValid(
  169. IN HWND hWnd,
  170. IN PSP_DIALOGDATA lpdd,
  171. IN INT iCur
  172. );
  173. VOID
  174. SetSelectedDriverNode(
  175. IN PSP_DIALOGDATA lpdd,
  176. IN INT iCur
  177. );
  178. BOOL
  179. bNoDevsToShow(
  180. IN PDEVINFO_ELEM DevInfoElem
  181. );
  182. PNEWDEVWIZ_DATA
  183. GetNewDevWizDataFromPsPage(
  184. LPPROPSHEETPAGE ppsp
  185. );
  186. LONG
  187. GetCurDesc(
  188. IN PSP_DIALOGDATA lpdd
  189. );
  190. VOID
  191. OnCancel(
  192. IN PNEWDEVWIZ_DATA ndwData
  193. );
  194. VOID
  195. __cdecl
  196. ClassDriverSearchThread(
  197. IN PVOID Context
  198. );
  199. BOOL
  200. pSetupIsClassDriverListBuilt(
  201. IN PSP_DIALOGDATA lpdd
  202. );
  203. VOID
  204. pSetupDevInfoDataFromDialogData(
  205. IN PSP_DIALOGDATA lpdd,
  206. OUT PSP_DEVINFO_DATA DeviceInfoData
  207. );
  208. VOID
  209. ToggleDialogControls(
  210. IN HWND hwndDlg,
  211. IN OUT PNEWDEVWIZ_DATA ndwData,
  212. IN BOOL Enable
  213. );
  214. void
  215. CleanupDriverLists(
  216. IN OUT PNEWDEVWIZ_DATA ndwData
  217. );
  218. BOOL
  219. CDMIsInternetAvailable(
  220. void
  221. );
  222. HPROPSHEETPAGE
  223. WINAPI
  224. SetupDiGetWizardPage(
  225. IN HDEVINFO DeviceInfoSet,
  226. IN PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  227. IN PSP_INSTALLWIZARD_DATA InstallWizardData,
  228. IN DWORD PageType,
  229. IN DWORD Flags
  230. )
  231. /*++
  232. Routine Description:
  233. This routine retrieves a handle to one of the Setup API-provided wizard
  234. pages, for an application to include in its own wizard.
  235. Arguments:
  236. DeviceInfoSet - Supplies the handle of the device information set to
  237. retrieve a wizard page for.
  238. DeviceInfoData - Optionally, supplies the address of a device information
  239. element with which the wizard page will be associated. This parameter
  240. is only used if the flags parameter includes DIWP_FLAG_USE_DEVINFO_DATA.
  241. If that flag is set, and if this parameter is not specified, then the
  242. wizard page will be associated with the global class driver list.
  243. InstallWizardData - Supplies the address of a PSP_INSTALLWIZARD_DATA
  244. structure containing parameters to be used by this wizard page. The
  245. cbSize field must be set to the size of the structure, in bytes, or the
  246. structure will be considered invalid.
  247. PageType - Supplies an ordinal indicating the type of wizard page to be
  248. retreived. May be one of the following values:
  249. SPWPT_SELECTDEVICE - Retrieve a select device wizard page.
  250. Flags - Supplies flags that specify how the wizard page is to be created.
  251. May be a combination of the following values:
  252. SPWP_USE_DEVINFO_DATA - Use the device information element specified
  253. by DeviceInfoData, or use the global class
  254. driver list if DeviceInfoData is not supplied.
  255. If this flag is not supplied, the wizard page
  256. will act upon the currently selected device
  257. (as selected by SetupDiSetSelectedDevice), or
  258. upon the global class driver list if no device
  259. is selected.
  260. Return Value:
  261. If the function succeeds, the return value is the handle to the requested
  262. wizard page.
  263. If the function fails, the return value is NULL. To get extended error
  264. information, call GetLastError.
  265. Remarks:
  266. A device information set may not be destroyed as long as there are any
  267. active wizard pages using it. In addition, if the wizard page is
  268. associated with a particular device information element, then that element
  269. will not be deletable as long as it is being used by a wizard page.
  270. --*/
  271. {
  272. PDEVICE_INFO_SET pDeviceInfoSet = NULL;
  273. PDEVINFO_ELEM DevInfoElem;
  274. DWORD Err = NO_ERROR;
  275. HPROPSHEETPAGE hPage = NULL;
  276. PNEWDEVWIZ_DATA ndwData = NULL;
  277. PWIZPAGE_OBJECT WizPageObject = NULL;
  278. //
  279. // Store the address of the corresponding wizard object at the
  280. // end of the PROPSHEETPAGE buffer.
  281. //
  282. BYTE pspBuffer[sizeof(PROPSHEETPAGE) + sizeof(PVOID)];
  283. LPPROPSHEETPAGE Page = (LPPROPSHEETPAGE)pspBuffer;
  284. try {
  285. //
  286. // Make sure we're running interactively.
  287. //
  288. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  289. Err = ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION;
  290. leave;
  291. }
  292. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  293. Err = ERROR_INVALID_HANDLE;
  294. leave;
  295. }
  296. switch(PageType) {
  297. case SPWPT_SELECTDEVICE :
  298. Page->pszTemplate = MAKEINTRESOURCE(IDD_DYNAWIZ_SELECTDEV_PAGE);
  299. Page->pfnDlgProc = SelectDeviceDlgProc;
  300. Page->pfnCallback = SelectDevicePropSheetPageProc;
  301. Page->pszHeaderTitle = MAKEINTRESOURCE(IDS_NDW_SELECTDEVICE);
  302. Page->pszHeaderSubTitle = NULL;
  303. break;
  304. default :
  305. Err = ERROR_INVALID_PARAMETER;
  306. leave;
  307. }
  308. //
  309. // Validate the supplied InstallWizardData structure, and create a
  310. // private storage buffer for internal use by the wizard page.
  311. //
  312. if((Err = pSetupCreateNewDevWizData(InstallWizardData, &ndwData)) != NO_ERROR) {
  313. leave;
  314. }
  315. //
  316. // Store the device information set handle in the dialogdata structure
  317. // embedded in the New Device Wizard buffer.
  318. //
  319. ndwData->ddData.DevInfoSet = DeviceInfoSet;
  320. //
  321. // If the caller specified the SPWP_USE_DEVINFO_DATA flag, then store information
  322. // in the dialog data structure about the specified devinfo element (if supplied).
  323. //
  324. if(Flags & SPWP_USE_DEVINFO_DATA) {
  325. if(DeviceInfoData) {
  326. //
  327. // Verify that the specified device information element is a valid one.
  328. //
  329. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  330. DeviceInfoData,
  331. NULL))) {
  332. Err = ERROR_INVALID_PARAMETER;
  333. leave;
  334. } else if(DevInfoElem->DiElemFlags & DIE_IS_LOCKED) {
  335. //
  336. // Device information element cannot be explicitly used by more than
  337. // one wizard page at a time.
  338. //
  339. Err = ERROR_DEVINFO_DATA_LOCKED;
  340. leave;
  341. }
  342. DevInfoElem->DiElemFlags |= DIE_IS_LOCKED;
  343. ndwData->ddData.DevInfoElem = DevInfoElem;
  344. }
  345. ndwData->ddData.flags = DD_FLAG_USE_DEVINFO_ELEM;
  346. }
  347. //
  348. // We've successfully created and initialized the devwiz data structure.
  349. // Now create a wizpage object so we can keep track of it.
  350. //
  351. if(WizPageObject = MyMalloc(sizeof(WIZPAGE_OBJECT))) {
  352. WizPageObject->RefCount = 0;
  353. WizPageObject->ndwData = ndwData;
  354. //
  355. // Insert this new object into the devinfo set's wizard object list.
  356. //
  357. WizPageObject->Next = pDeviceInfoSet->WizPageList;
  358. pDeviceInfoSet->WizPageList = WizPageObject;
  359. } else {
  360. Err = ERROR_NOT_ENOUGH_MEMORY;
  361. leave;
  362. }
  363. Page->dwSize = sizeof(pspBuffer);
  364. Page->dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE | PSP_USECALLBACK | PSP_USEFUSIONCONTEXT;
  365. Page->hActCtx = NULL;
  366. Page->hInstance = MyDllModuleHandle;
  367. Page->lParam = (LPARAM)DeviceInfoSet;
  368. *((PVOID *)(&(pspBuffer[sizeof(PROPSHEETPAGE)]))) = WizPageObject;
  369. if(!(hPage = CreatePropertySheetPage(Page))) {
  370. Err = ERROR_INVALID_DATA;
  371. }
  372. } except(pSetupExceptionFilter(GetExceptionCode())) {
  373. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  374. }
  375. if(pDeviceInfoSet) {
  376. UnlockDeviceInfoSet(pDeviceInfoSet);
  377. }
  378. if(Err != NO_ERROR) {
  379. if(ndwData) {
  380. MyFree(ndwData);
  381. }
  382. if(WizPageObject) {
  383. MyFree(WizPageObject);
  384. }
  385. }
  386. SetLastError(Err);
  387. return hPage;
  388. }
  389. BOOL
  390. WINAPI
  391. SetupDiGetSelectedDevice(
  392. IN HDEVINFO DeviceInfoSet,
  393. OUT PSP_DEVINFO_DATA DeviceInfoData
  394. )
  395. /*++
  396. Routine Description:
  397. This routine retrieves the currently-selected device for the specified
  398. device information set. This is typically used during an installation
  399. wizard.
  400. Arguments:
  401. DeviceInfoSet - Supplies a handle to the device information set for
  402. which the selected device is to be retrieved.
  403. DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure
  404. that receives the currently-selected device. If there is no device
  405. currently selected, then the routine will fail, and GetLastError
  406. will return ERROR_NO_DEVICE_SELECTED.
  407. Return Value:
  408. If the function succeeds, the return value is TRUE.
  409. If the function fails, the return value is FALSE. To get extended error
  410. information, call GetLastError.
  411. --*/
  412. {
  413. PDEVICE_INFO_SET pDeviceInfoSet = NULL;
  414. DWORD Err = NO_ERROR;
  415. try {
  416. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  417. Err = ERROR_INVALID_HANDLE;
  418. leave;
  419. }
  420. if(pDeviceInfoSet->SelectedDevInfoElem) {
  421. if(!(DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
  422. pDeviceInfoSet->SelectedDevInfoElem,
  423. DeviceInfoData))) {
  424. Err = ERROR_INVALID_USER_BUFFER;
  425. }
  426. } else {
  427. Err = ERROR_NO_DEVICE_SELECTED;
  428. }
  429. } except(pSetupExceptionFilter(GetExceptionCode())) {
  430. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  431. }
  432. if(pDeviceInfoSet) {
  433. UnlockDeviceInfoSet(pDeviceInfoSet);
  434. }
  435. SetLastError(Err);
  436. return (Err == NO_ERROR);
  437. }
  438. BOOL
  439. WINAPI
  440. SetupDiSetSelectedDevice(
  441. IN HDEVINFO DeviceInfoSet,
  442. IN PSP_DEVINFO_DATA DeviceInfoData
  443. )
  444. /*++
  445. Routine Description:
  446. This routine sets the specified device information element to be the
  447. currently selected member of a device information set. This is typically
  448. used during an installation wizard.
  449. Arguments:
  450. DeviceInfoSet - Supplies a handle to the device information set for
  451. which the selected device is to be set.
  452. DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure
  453. specifying the device information element to be selected.
  454. Return Value:
  455. If the function succeeds, the return value is TRUE.
  456. If the function fails, the return value is FALSE. To get extended error
  457. information, call GetLastError.
  458. --*/
  459. {
  460. PDEVICE_INFO_SET pDeviceInfoSet = NULL;
  461. DWORD Err = NO_ERROR;
  462. PDEVINFO_ELEM DevInfoElem;
  463. try {
  464. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  465. Err = ERROR_INVALID_HANDLE;
  466. leave;
  467. }
  468. DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  469. DeviceInfoData,
  470. NULL
  471. );
  472. if(DevInfoElem) {
  473. pDeviceInfoSet->SelectedDevInfoElem = DevInfoElem;
  474. } else {
  475. Err = ERROR_INVALID_PARAMETER;
  476. }
  477. } except(pSetupExceptionFilter(GetExceptionCode())) {
  478. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  479. }
  480. if(pDeviceInfoSet) {
  481. UnlockDeviceInfoSet(pDeviceInfoSet);
  482. }
  483. SetLastError(Err);
  484. return (Err == NO_ERROR);
  485. }
  486. DWORD
  487. pSetupCreateNewDevWizData(
  488. IN PSP_INSTALLWIZARD_DATA InstallWizardData,
  489. OUT PNEWDEVWIZ_DATA *NewDeviceWizardData
  490. )
  491. /*++
  492. Routine Description:
  493. This routine validates an InstallWizardData buffer, then allocates and
  494. fills in a NEWDEVWIZ_DATA buffer based on information supplied therein.
  495. Arguments:
  496. InstallWizardData - Supplies the address of an installation wizard data
  497. structure to be validated and used in building the private buffer.
  498. NewDeviceWizardData - Supplies the address of a variable that receives a
  499. pointer to the newly-allocated install wizard data buffer. This buffer
  500. will not be modified unless the NEWDEVWIZ_DATA buffer was successfully
  501. built.
  502. Return Value:
  503. If the function succeeds, the return value is NO_ERROR, otherwise, it is
  504. a Win32 error code.
  505. --*/
  506. {
  507. PNEWDEVWIZ_DATA ndwData = NULL;
  508. DWORD Err = NO_ERROR;
  509. if((InstallWizardData->ClassInstallHeader.cbSize != sizeof(SP_CLASSINSTALL_HEADER)) ||
  510. (InstallWizardData->ClassInstallHeader.InstallFunction != DIF_INSTALLWIZARD)) {
  511. return ERROR_INVALID_USER_BUFFER;
  512. }
  513. //
  514. // The dynamic page entries are currently ignored, as are the Private
  515. // fields. Also, the hwndWizardDlg is not validated.
  516. //
  517. try {
  518. if(ndwData = MyMalloc(sizeof(NEWDEVWIZ_DATA))) {
  519. ZeroMemory(ndwData, sizeof(NEWDEVWIZ_DATA));
  520. } else {
  521. Err = ERROR_NOT_ENOUGH_MEMORY;
  522. leave;
  523. }
  524. //
  525. // Initialize the Current Description string table index in the dialog
  526. // data to -1, so that it will get updated when the wizard page is
  527. // first entered.
  528. //
  529. ndwData->ddData.iCurDesc = -1;
  530. //
  531. // Copy the installwizard data.
  532. //
  533. CopyMemory(&(ndwData->InstallData),
  534. InstallWizardData,
  535. sizeof(SP_INSTALLWIZARD_DATA)
  536. );
  537. } except(pSetupExceptionFilter(GetExceptionCode())) {
  538. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  539. }
  540. if((Err != NO_ERROR) && ndwData) {
  541. MyFree(ndwData);
  542. } else {
  543. *NewDeviceWizardData = ndwData;
  544. }
  545. return Err;
  546. }
  547. UINT
  548. CALLBACK
  549. SelectDevicePropSheetPageProc(
  550. IN HWND hwnd,
  551. IN UINT uMsg,
  552. IN LPPROPSHEETPAGE ppsp
  553. )
  554. /*++
  555. Routine Description:
  556. This routine is called when the Select Device wizard page is created or
  557. destroyed.
  558. Arguments:
  559. hwnd - Reserved
  560. uMsg - Action flag, either PSPCB_CREATE or PSPCB_RELEASE
  561. ppsp - Supplies the address of the PROPSHEETPAGE structure being created or
  562. destroyed.
  563. Return Value:
  564. If uMsg is PSPCB_CREATE, then return non-zero to allow the page to be
  565. created, or zero to prevent it.
  566. if uMsg is PSPCB_RELEASE, the return value is ignored.
  567. --*/
  568. {
  569. PDEVICE_INFO_SET pDeviceInfoSet;
  570. PDEVINFO_ELEM DevInfoElem;
  571. UINT ret;
  572. PVOID WizObjectId;
  573. PWIZPAGE_OBJECT CurWizObject, PrevWizObject;
  574. //
  575. // Access the device info set handle stored in the propsheetpage's lParam.
  576. //
  577. if(!(pDeviceInfoSet = AccessDeviceInfoSet((HDEVINFO)(ppsp->lParam)))) {
  578. return FALSE;
  579. }
  580. ret = TRUE;
  581. try {
  582. //
  583. // The ObjectID (pointer, actually) for the corresponding wizard
  584. // object for this page is stored at the end of the ppsp structure.
  585. // Retrieve this now, and look for it in the devinfo set's list of
  586. // wizard objects.
  587. //
  588. WizObjectId = *((PVOID *)(&(((PBYTE)ppsp)[sizeof(PROPSHEETPAGE)])));
  589. for(CurWizObject = pDeviceInfoSet->WizPageList, PrevWizObject = NULL;
  590. CurWizObject;
  591. PrevWizObject = CurWizObject, CurWizObject = CurWizObject->Next) {
  592. if(WizObjectId == CurWizObject) {
  593. //
  594. // We found our object.
  595. //
  596. break;
  597. }
  598. }
  599. if(!CurWizObject) {
  600. ret = FALSE;
  601. leave;
  602. }
  603. switch(uMsg) {
  604. case PSPCB_CREATE :
  605. //
  606. // Fail the create if we've already been created once
  607. // (hopefully, this will never happen).
  608. //
  609. if(CurWizObject->RefCount) {
  610. ret = FALSE;
  611. leave;
  612. } else {
  613. CurWizObject->RefCount++;
  614. }
  615. break;
  616. case PSPCB_RELEASE :
  617. //
  618. // Decrement the wizard object refcount. If it goes to zero
  619. // (or if it already was zero because we never got a
  620. // PSPCB_CREATE message), then remove the object from the
  621. // linked list, and free all associated memory.
  622. //
  623. if(CurWizObject->RefCount) {
  624. CurWizObject->RefCount--;
  625. }
  626. MYASSERT(!CurWizObject->RefCount);
  627. if(!CurWizObject->RefCount) {
  628. //
  629. // Remove the object from the object list.
  630. //
  631. if(PrevWizObject) {
  632. PrevWizObject->Next = CurWizObject->Next;
  633. } else {
  634. pDeviceInfoSet->WizPageList = CurWizObject->Next;
  635. }
  636. //
  637. // If this wizard object was explicitly tied to a
  638. // particular device information element, then unlock that
  639. // element now.
  640. //
  641. if((CurWizObject->ndwData->ddData.flags & DD_FLAG_USE_DEVINFO_ELEM) &&
  642. (DevInfoElem = CurWizObject->ndwData->ddData.DevInfoElem)) {
  643. MYASSERT(DevInfoElem->DiElemFlags & DIE_IS_LOCKED);
  644. DevInfoElem->DiElemFlags ^= DIE_IS_LOCKED;
  645. }
  646. MyFree(CurWizObject->ndwData);
  647. MyFree(CurWizObject);
  648. }
  649. }
  650. } except(pSetupExceptionFilter(GetExceptionCode())) {
  651. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  652. ret = FALSE;
  653. }
  654. UnlockDeviceInfoSet(pDeviceInfoSet);
  655. return ret;
  656. }
  657. INT_PTR
  658. CALLBACK
  659. SelectDeviceDlgProc(
  660. IN HWND hwndDlg,
  661. IN UINT uMsg,
  662. IN WPARAM wParam,
  663. IN LPARAM lParam
  664. )
  665. /*++
  666. Routine Description:
  667. This is the dialog proc for the Select Device wizard page.
  668. --*/
  669. {
  670. INT iCur;
  671. HICON hicon;
  672. PNEWDEVWIZ_DATA ndwData;
  673. PSP_INSTALLWIZARD_DATA iwd;
  674. LV_ITEM lvItem;
  675. TCHAR TempString[LINE_LEN];
  676. PCLASSDRV_THREAD_CONTEXT ClassDrvThreadContext;
  677. HCURSOR hOldCursor;
  678. OSVERSIONINFOEX osVersionInfoEx;
  679. DWORD Err;
  680. if(uMsg == WM_INITDIALOG) {
  681. LPPROPSHEETPAGE Page = (LPPROPSHEETPAGE)lParam;
  682. //
  683. // Retrieve a pointer to the device wizard data associated with
  684. // this wizard page.
  685. //
  686. ndwData = GetNewDevWizDataFromPsPage(Page);
  687. SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)ndwData);
  688. if(ndwData) {
  689. ndwData->bInit = TRUE;
  690. ndwData->idTimer = 0;
  691. ndwData->bInit = FALSE;
  692. } else {
  693. //
  694. // This is really bad--we can't simply call EndDialog() since we
  695. // don't know whether we're a dialog or a wizard page. This should
  696. // never happen.
  697. //
  698. return TRUE; // we didn't set the focus
  699. }
  700. if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
  701. //
  702. // For the stand-alone dialog box version, we initialize here.
  703. //
  704. ndwData->bInit = TRUE; // Still doing some init stuff
  705. //
  706. // Make sure our "waiting for class list" static text control is
  707. // hidden!
  708. //
  709. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_STATUS_TEXT), SW_HIDE);
  710. if(!InitSelectDeviceDlg(hwndDlg, ndwData)) {
  711. //
  712. // We don't have any items displayed so ask the user if they
  713. // want to go directly to Have Disk, or just cancel.
  714. //
  715. PostMessage(hwndDlg, WMX_NO_DRIVERS_IN_LIST, 0, 0);
  716. }
  717. ndwData->bInit = FALSE; // Done with init stuff
  718. return FALSE; // we already set the focus.
  719. } else {
  720. return TRUE; // we didn't set the focus
  721. }
  722. } else {
  723. //
  724. // For the small set of messages that we get before WM_INITDIALOG, we
  725. // won't have a devwizdata pointer!
  726. //
  727. if(ndwData = (PNEWDEVWIZ_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER)) {
  728. iwd = &(ndwData->InstallData);
  729. } else {
  730. //
  731. // If we haven't gotten a WM_INITDIALOG message yet, or if for some
  732. // reason we weren't able to retrieve the ndwData pointer when we
  733. // did, then we simply return FALSE for all messages.
  734. //
  735. // (If we ever need to process messages before WM_INITDIALOG (e.g.,
  736. // set font), then we'll need to modify this approach.)
  737. //
  738. return FALSE;
  739. }
  740. }
  741. switch(uMsg) {
  742. case WMX_CLASSDRVLIST_DONE :
  743. MYASSERT(ndwData->ddData.AuxThreadRunning);
  744. ndwData->ddData.AuxThreadRunning = FALSE;
  745. //
  746. // wParam is a boolean indicating the result of the class driver
  747. // search.
  748. //
  749. // lParam is NO_ERROR upon success, or a Win32 error code
  750. // indicating cause of failure.
  751. //
  752. switch(ndwData->ddData.PendingAction) {
  753. case PENDING_ACTION_NONE :
  754. //
  755. // Then the thread has completed, but the user is still
  756. // mulling over the choices on the compatible driver list.
  757. // If the class driver list was successfully built, then
  758. // there's nothing to do here. If it failed for some
  759. // reason (highly unlikely), then we (silently) disable the
  760. // 'show compatible devices' check box.
  761. if(!wParam) {
  762. ndwData->ddData.flags |= DD_FLAG_CLASSLIST_FAILED;
  763. EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), FALSE);
  764. }
  765. break;
  766. case PENDING_ACTION_SELDONE :
  767. //
  768. // In this case, we don't care what happened in the other
  769. // thread. The user has made their selection, and we're
  770. // ready to return success.
  771. //
  772. SetSelectedDriverNode(&(ndwData->ddData),
  773. ndwData->ddData.CurSelectionForSuccess
  774. );
  775. EndDialog(hwndDlg, NO_ERROR);
  776. break;
  777. case PENDING_ACTION_SHOWCLASS :
  778. //
  779. // Then we've been waiting on the class driver search to
  780. // complete, so that we can show the list. Hopefully, the
  781. // search was successful. If not, we'll give the user a
  782. // popup saying that the list could not be shown, and then
  783. // leave them in the compatible list view (with the class
  784. // list radio button now disabled).
  785. //
  786. ndwData->ddData.PendingAction = PENDING_ACTION_NONE;
  787. if(wParam) {
  788. //
  789. // The class driver list was built successfully.
  790. //
  791. if(ndwData->ddData.CurSelectionForSuccess != LB_ERR) {
  792. lvItem.mask = LVIF_TEXT;
  793. lvItem.iItem = ndwData->ddData.CurSelectionForSuccess;
  794. lvItem.iSubItem = 0;
  795. lvItem.pszText = TempString;
  796. lvItem.cchTextMax = SIZECHARS(TempString);
  797. if(ListView_GetItem((ndwData->ddData).hwndDrvList, &lvItem)) {
  798. //
  799. // Now retrieve the (case-insensitive) string
  800. // ID of this string, and store it as the
  801. // current description ID.
  802. //
  803. (ndwData->ddData).iCurDesc = LookUpStringInDevInfoSet(
  804. (ndwData->ddData).DevInfoSet,
  805. TempString,
  806. FALSE
  807. );
  808. }
  809. }
  810. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_STATUS_TEXT), SW_HIDE);
  811. if(FillInDeviceList(hwndDlg, &(ndwData->ddData)) == NO_ERROR) {
  812. //
  813. // Enable the OK/Next button
  814. //
  815. if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
  816. EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE);
  817. } else {
  818. if(((ndwData->InstallData).Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) &&
  819. ((ndwData->InstallData).Flags & NDW_INSTALLFLAG_EXPRESSINTRO) &&
  820. !((ndwData->InstallData).DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
  821. //
  822. // No back if we skipped the Class list, and are in express mode
  823. //
  824. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
  825. } else {
  826. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
  827. }
  828. }
  829. break;
  830. }
  831. }
  832. //
  833. // Inform the user that the class driver search failed.
  834. //
  835. if(!LoadString(MyDllModuleHandle,
  836. IDS_SELECT_DEVICE,
  837. TempString,
  838. SIZECHARS(TempString))) {
  839. *TempString = TEXT('\0');
  840. }
  841. FormatMessageBox(MyDllModuleHandle,
  842. hwndDlg,
  843. MSG_NO_CLASSDRVLIST_ERROR,
  844. TempString,
  845. MB_OK | MB_TASKMODAL
  846. );
  847. //
  848. // Check the 'Show compatible devices' check box and then
  849. // gray it out since the user cannot uncheck it since we
  850. // don't have a class list.
  851. //
  852. CheckDlgButton(hwndDlg, IDC_NDW_PICKDEV_COMPAT, BST_CHECKED);
  853. EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), FALSE);
  854. ndwData->ddData.bShowCompat = TRUE;
  855. ndwData->ddData.flags |= DD_FLAG_CLASSLIST_FAILED;
  856. //
  857. // We also must unhide the compatible driver list controls,
  858. // and re-enable the OK button.
  859. //
  860. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_STATUS_TEXT), SW_HIDE);
  861. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), SW_SHOW);
  862. if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
  863. EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE);
  864. } else {
  865. if(((ndwData->InstallData).Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) &&
  866. ((ndwData->InstallData).Flags & NDW_INSTALLFLAG_EXPRESSINTRO) &&
  867. !((ndwData->InstallData).DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
  868. //
  869. // No back if we skipped the Class list, and are in
  870. // express mode
  871. //
  872. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
  873. } else {
  874. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
  875. }
  876. }
  877. break;
  878. case PENDING_ACTION_CANCEL :
  879. //
  880. // This is an easy one. No matter what happened in the
  881. // other thread, we simply want to clean up and return.
  882. //
  883. OnCancel(ndwData);
  884. EndDialog(hwndDlg, ERROR_CANCELLED);
  885. break;
  886. case PENDING_ACTION_OEM :
  887. case PENDING_ACTION_WINDOWSUPDATE:
  888. if(ndwData->ddData.PendingAction == PENDING_ACTION_OEM) {
  889. Err = HandleSelectOEM(hwndDlg, ndwData);
  890. if (Err == NO_ERROR) {
  891. //
  892. // The class installer picked a driver for the
  893. // user automatically, so just end the dialog or
  894. // go to the next wizard page.
  895. //
  896. ndwData->ddData.PendingAction = PENDING_ACTION_NONE;
  897. if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
  898. EndDialog(hwndDlg, NO_ERROR);
  899. } else {
  900. iwd->Flags |= NDW_INSTALLFLAG_CI_PICKED_OEM;
  901. PropSheet_PressButton(GetParent(hwndDlg), PSBTN_NEXT);
  902. }
  903. break;
  904. }
  905. } else {
  906. //
  907. // Call HandleWindowsUpdate. If this API succeeds
  908. // then it will fill in the existing list control with
  909. // the Windows Update drivers.
  910. //
  911. Err = HandleWindowsUpdate(hwndDlg, ndwData);
  912. }
  913. ToggleDialogControls(hwndDlg, ndwData, TRUE);
  914. if ((Err == NO_ERROR) ||
  915. (Err == ERROR_DI_DO_DEFAULT)) {
  916. //
  917. // If HandleSelectOEM or HandleWindowsUpdate returned
  918. // NO_ERROR or ERROR_DI_DO_DEFAULT then they have
  919. // updated the existing listbox of drivers, so there
  920. // is no need to fire up the class driver list thread
  921. // again.
  922. //
  923. ndwData->ddData.PendingAction = PENDING_ACTION_NONE;
  924. } else {
  925. //
  926. // HandleSelectOEM or HandleWindowsUpdate returned some
  927. // other error, so the dialog needs to be put back to
  928. // the state it was in before the user pressed the
  929. // button. This includes starting up the class driver
  930. // search thread again, if needed.
  931. //
  932. if(ndwData->ddData.bShowCompat) {
  933. ndwData->ddData.PendingAction = PENDING_ACTION_NONE;
  934. } else {
  935. ndwData->ddData.PendingAction = PENDING_ACTION_SHOWCLASS;
  936. }
  937. ndwData->bInit = FALSE;
  938. //
  939. // We got here by aborting the class driver search.
  940. // Since we may need it after all, we must re-start the
  941. // search (unless the auxilliary thread happened to
  942. // have already finished before we sent it the abort
  943. // request).
  944. //
  945. if(!(ndwData->ddData.flags & DD_FLAG_CLASSLIST_FAILED) &&
  946. !pSetupIsClassDriverListBuilt(&(ndwData->ddData)))
  947. {
  948. //
  949. // Allocate a context structure to pass to the
  950. // auxilliary thread (the auxilliary thread will
  951. // take care of freeing the memory).
  952. //
  953. if(ClassDrvThreadContext = MyMalloc(sizeof(CLASSDRV_THREAD_CONTEXT))) {
  954. try {
  955. //
  956. // Fill in the context structure, and fire
  957. // off the thread.
  958. //
  959. ClassDrvThreadContext->DeviceInfoSet =
  960. ndwData->ddData.DevInfoSet;
  961. //
  962. // SP_DEVINFO_DATA can only be retrieved
  963. // whilst the device information set is
  964. // locked.
  965. //
  966. pSetupDevInfoDataFromDialogData(
  967. &(ndwData->ddData),
  968. &(ClassDrvThreadContext->DeviceInfoData)
  969. );
  970. ClassDrvThreadContext->NotificationWindow = hwndDlg;
  971. if(_beginthread(ClassDriverSearchThread, 0, ClassDrvThreadContext) == -1) {
  972. MyFree(ClassDrvThreadContext);
  973. ClassDrvThreadContext = NULL;
  974. } else {
  975. //
  976. // Our class driver search context has
  977. // been officially handed off to the
  978. // thread we just created. Reset our
  979. // pointer so we won't try to free this
  980. // later.
  981. //
  982. ClassDrvThreadContext = NULL;
  983. ndwData->ddData.AuxThreadRunning = TRUE;
  984. //
  985. // If we're currently in the class
  986. // driver list view, then disable the
  987. // OK/Next button, since the user can't
  988. // select a class driver yet.
  989. //
  990. if(!ndwData->ddData.bShowCompat) {
  991. if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
  992. EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
  993. } else {
  994. if(((ndwData->InstallData).Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) &&
  995. ((ndwData->InstallData).Flags & NDW_INSTALLFLAG_EXPRESSINTRO) &&
  996. !((ndwData->InstallData).DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
  997. //
  998. // No back if we skipped
  999. // the Class list, and are
  1000. // in express mode
  1001. //
  1002. PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
  1003. } else {
  1004. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
  1005. }
  1006. }
  1007. }
  1008. }
  1009. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1010. pSetupExceptionHandler(GetExceptionCode(),
  1011. ERROR_INVALID_PARAMETER,
  1012. NULL
  1013. );
  1014. if(ClassDrvThreadContext) {
  1015. MyFree(ClassDrvThreadContext);
  1016. }
  1017. }
  1018. }
  1019. if(!(ndwData->ddData.AuxThreadRunning)) {
  1020. //
  1021. // We couldn't start the class driver search
  1022. // thread. Check and disable the 'Show
  1023. // compatible devices' check box.
  1024. //
  1025. if(!ndwData->ddData.bShowCompat) {
  1026. CheckDlgButton(hwndDlg,
  1027. IDC_NDW_PICKDEV_COMPAT,
  1028. BST_CHECKED
  1029. );
  1030. }
  1031. ndwData->ddData.flags |= DD_FLAG_CLASSLIST_FAILED;
  1032. EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), FALSE);
  1033. }
  1034. }
  1035. }
  1036. break;
  1037. }
  1038. break;
  1039. case WMX_NO_DRIVERS_IN_LIST: {
  1040. TCHAR Title[LINE_LEN];
  1041. if(!LoadString(MyDllModuleHandle, IDS_SELECT_DEVICE, Title, SIZECHARS(Title))) {
  1042. Title[0]=TEXT('\0');
  1043. }
  1044. if(!LoadString(MyDllModuleHandle, IDS_NDW_NODRIVERS_WARNING, TempString, SIZECHARS(TempString))) {
  1045. TempString[0]=TEXT('\0');
  1046. }
  1047. if(IDOK == MessageBox(hwndDlg, TempString, Title, MB_OKCANCEL | MB_ICONEXCLAMATION)) {
  1048. PostMessage(hwndDlg, WM_COMMAND, IDC_NDW_PICKDEV_HAVEDISK, 0);
  1049. } else {
  1050. PostMessage(hwndDlg, WM_COMMAND, IDCANCEL, 0);
  1051. }
  1052. break;
  1053. }
  1054. case WM_DESTROY:
  1055. if(ndwData->ddData.AuxThreadRunning) {
  1056. //
  1057. // This should never happen. But just to be on the safe side,
  1058. // if it does, we'll cancel the search. We _will not_ however,
  1059. // wait for the WMX_CLASSDRVLIST_DONE message, to signal that
  1060. // the thread has terminated. This should be OK, since the
  1061. // worst that can happen is that it will try to send a message
  1062. // to a window that no longer exists.
  1063. //
  1064. SetupDiCancelDriverInfoSearch(ndwData->ddData.DevInfoSet);
  1065. }
  1066. if(ndwData->idTimer) {
  1067. ndwData->bInit = TRUE;
  1068. KillTimer(hwndDlg, SELECTMFG_TIMER_ID);
  1069. }
  1070. if(hicon = (HICON)SendDlgItemMessage(hwndDlg, IDC_CLASSICON, STM_GETICON, 0, 0)) {
  1071. DestroyIcon(hicon);
  1072. }
  1073. if(hicon = (HICON)SendDlgItemMessage(hwndDlg, IDC_NDW_PICKDEV_SIGNED_ICON, STM_GETICON, 0, 0)) {
  1074. DestroyIcon(hicon);
  1075. }
  1076. if(ndwData->ddData.hImageList) {
  1077. ImageList_Destroy(ndwData->ddData.hImageList);
  1078. }
  1079. if(ndwData->ddData.hFontNormal) {
  1080. DeleteObject(ndwData->ddData.hFontNormal);
  1081. }
  1082. if(ndwData->ddData.hFontBold) {
  1083. DeleteObject(ndwData->ddData.hFontBold);
  1084. }
  1085. break;
  1086. case WM_COMMAND:
  1087. switch(LOWORD(wParam)) {
  1088. case IDC_NDW_PICKDEV_COMPAT:
  1089. if((HIWORD(wParam) == BN_CLICKED) &&
  1090. IsWindowVisible(GetDlgItem(hwndDlg, LOWORD(wParam)))) {
  1091. ndwData->ddData.bShowCompat = IsDlgButtonChecked(hwndDlg, IDC_NDW_PICKDEV_COMPAT);
  1092. //
  1093. // Update the current description ID in the dialog data
  1094. // so that the same device will be highlighted when we
  1095. // switch from one view to the other.
  1096. //
  1097. iCur = (int)ListView_GetNextItem((ndwData->ddData).hwndDrvList,
  1098. -1,
  1099. LVNI_SELECTED
  1100. );
  1101. if(ndwData->ddData.AuxThreadRunning) {
  1102. //
  1103. // There are two possibilities here:
  1104. //
  1105. // 1. The user was looking at the compatible driver
  1106. // list, and then decided to look at the class
  1107. // driver list, which we're not done building
  1108. // yet. In that case, hide the compatible
  1109. // driver listbox, and unhide our "waiting for
  1110. // class list" static text control.
  1111. //
  1112. // 2. The user switched to the class driver list
  1113. // view, saw that we were still working on it,
  1114. // and then decided to switch back to the
  1115. // compatible list. In that case, we simply
  1116. // need to re-hide the "waiting for class list"
  1117. // static text control, and show the compatible
  1118. // driver listbox again. In this case, we don't
  1119. // want to attempt to re-initialize the listbox,
  1120. // as that will require acquiring the HDEVINFO
  1121. // lock, and we will hang.
  1122. //
  1123. if(ndwData->ddData.bShowCompat) {
  1124. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_STATUS_TEXT), SW_HIDE);
  1125. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), SW_SHOW);
  1126. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_ICON), SW_SHOW);
  1127. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), SW_SHOW);
  1128. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_LINK), SW_SHOW);
  1129. if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
  1130. EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE);
  1131. } else {
  1132. if(((ndwData->InstallData).Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) &&
  1133. ((ndwData->InstallData).Flags & NDW_INSTALLFLAG_EXPRESSINTRO) &&
  1134. !((ndwData->InstallData).DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
  1135. //
  1136. // No back if we skipped the Class
  1137. // list, and are in express mode
  1138. //
  1139. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
  1140. } else {
  1141. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
  1142. }
  1143. }
  1144. //
  1145. // We no longer have a pending action.
  1146. //
  1147. ndwData->ddData.PendingAction = PENDING_ACTION_NONE;
  1148. } else {
  1149. //
  1150. // Temporarily hide the compatible driver
  1151. // listbox, and unhide the "waiting for class
  1152. // list" static text control.
  1153. //
  1154. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), SW_HIDE);
  1155. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_ICON), SW_HIDE);
  1156. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), SW_HIDE);
  1157. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_LINK), SW_HIDE);
  1158. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_STATUS_TEXT), SW_SHOW);
  1159. if(!LoadString(MyDllModuleHandle, IDS_NDW_RETRIEVING_LIST, TempString, SIZECHARS(TempString))) {
  1160. TempString[0]=TEXT('\0');
  1161. }
  1162. SetDlgItemText(hwndDlg, IDC_NDW_STATUS_TEXT, TempString);
  1163. //
  1164. // Disable the OK/Next button, because the user
  1165. // can't select a class driver yet.
  1166. //
  1167. if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
  1168. EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
  1169. } else {
  1170. if(((ndwData->InstallData).Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) &&
  1171. ((ndwData->InstallData).Flags & NDW_INSTALLFLAG_EXPRESSINTRO) &&
  1172. !((ndwData->InstallData).DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
  1173. //
  1174. // No back if we skipped the Class
  1175. // list, and are in express mode
  1176. //
  1177. PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
  1178. } else {
  1179. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
  1180. }
  1181. }
  1182. MYASSERT(ndwData->ddData.PendingAction == PENDING_ACTION_NONE);
  1183. ndwData->ddData.PendingAction = PENDING_ACTION_SHOWCLASS;
  1184. ndwData->ddData.CurSelectionForSuccess = iCur;
  1185. }
  1186. } else {
  1187. if(iCur != LB_ERR) {
  1188. lvItem.mask = LVIF_TEXT;
  1189. lvItem.iItem = iCur;
  1190. lvItem.iSubItem = 0;
  1191. lvItem.pszText = TempString;
  1192. lvItem.cchTextMax = SIZECHARS(TempString);
  1193. if(ListView_GetItem((ndwData->ddData).hwndDrvList, &lvItem)) {
  1194. //
  1195. // Now retrieve the (case-insensitive)
  1196. // string ID of this string, and store it
  1197. // as the current description ID.
  1198. //
  1199. (ndwData->ddData).iCurDesc =
  1200. LookUpStringInDevInfoSet((ndwData->ddData).DevInfoSet,
  1201. TempString,
  1202. FALSE
  1203. );
  1204. }
  1205. }
  1206. FillInDeviceList(hwndDlg, &(ndwData->ddData));
  1207. //
  1208. // If we just filled in the compatible driver list,
  1209. // then make sure there isn't a timer waiting to
  1210. // pounce and destroy our list!
  1211. //
  1212. if((ndwData->ddData.bShowCompat) &&
  1213. (ndwData->idTimer)) {
  1214. KillTimer(hwndDlg, SELECTMFG_TIMER_ID);
  1215. ndwData->idTimer = 0;
  1216. }
  1217. }
  1218. }
  1219. break;
  1220. case IDC_NDW_PICKDEV_HAVEDISK :
  1221. //
  1222. // If we're doing a dialog box, then pressing "Have Disk"
  1223. // will popup another Select Device dialog. Disable all
  1224. // controls on this one first, to avoid user confusion.
  1225. //
  1226. ToggleDialogControls(hwndDlg, ndwData, FALSE);
  1227. //
  1228. // If HandleSelectOEM returns success, we are done, and can
  1229. // either end the dialog, or proceed to the next wizard
  1230. // page.
  1231. //
  1232. if(ndwData->ddData.AuxThreadRunning) {
  1233. //
  1234. // The auxilliary thread is still running. Set our
  1235. // cursor to an hourglass, and set our pending action
  1236. // to be OEM Select while we wait for the thread to
  1237. // respond to our cancel request.
  1238. //
  1239. MYASSERT((ndwData->ddData.PendingAction == PENDING_ACTION_NONE) ||
  1240. (ndwData->ddData.PendingAction == PENDING_ACTION_SHOWCLASS));
  1241. hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1242. try {
  1243. SetupDiCancelDriverInfoSearch(ndwData->ddData.DevInfoSet);
  1244. //
  1245. // Disable all dialog controls, so that no other
  1246. // button may be pressed until we respond to this
  1247. // pending action. Also, kill the timer, so that
  1248. // it doesn't fire in the meantime.
  1249. //
  1250. ndwData->bInit = TRUE;
  1251. if(ndwData->idTimer) {
  1252. KillTimer(hwndDlg, SELECTMFG_TIMER_ID);
  1253. ndwData->idTimer = 0;
  1254. }
  1255. ndwData->ddData.PendingAction = PENDING_ACTION_OEM;
  1256. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1257. pSetupExceptionHandler(GetExceptionCode(),
  1258. ERROR_INVALID_PARAMETER,
  1259. NULL
  1260. );
  1261. }
  1262. SetCursor(hOldCursor);
  1263. } else {
  1264. if(HandleSelectOEM(hwndDlg, ndwData) == NO_ERROR) {
  1265. if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
  1266. EndDialog(hwndDlg, NO_ERROR);
  1267. } else {
  1268. iwd->Flags |= NDW_INSTALLFLAG_CI_PICKED_OEM;
  1269. PropSheet_PressButton(GetParent(hwndDlg), PSBTN_NEXT);
  1270. }
  1271. } else {
  1272. //
  1273. // The user didn't make an OEM selection, so we
  1274. // need to re-enable the controls on our dialog or
  1275. // wizard.
  1276. //
  1277. ToggleDialogControls(hwndDlg, ndwData, TRUE);
  1278. }
  1279. }
  1280. break;
  1281. case IDC_NDW_PICKDEV_WINDOWSUPDATE:
  1282. //
  1283. // If we're doing a dialog box, then pressing "Have Disk"
  1284. // will popup another Select Device dialog. Disable all
  1285. // controls on this one first, to avoid user confusion.
  1286. //
  1287. ToggleDialogControls(hwndDlg, ndwData, FALSE);
  1288. if(ndwData->ddData.AuxThreadRunning) {
  1289. //
  1290. // The auxilliary thread is still running. Set our
  1291. // cursor to an hourglass, and set our pending action
  1292. // to be Windows Update Select while we wait for the
  1293. // thread to respond to our cancel request.
  1294. //
  1295. MYASSERT((ndwData->ddData.PendingAction == PENDING_ACTION_NONE) ||
  1296. (ndwData->ddData.PendingAction == PENDING_ACTION_SHOWCLASS));
  1297. hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1298. try {
  1299. SetupDiCancelDriverInfoSearch(ndwData->ddData.DevInfoSet);
  1300. //
  1301. // Disable all dialog controls, so that no other
  1302. // button may be pressed until we respond to this
  1303. // pending action. Also, kill the timer, so that
  1304. // it doesn't fire in the meantime.
  1305. //
  1306. ndwData->bInit = TRUE;
  1307. if(ndwData->idTimer) {
  1308. KillTimer(hwndDlg, SELECTMFG_TIMER_ID);
  1309. ndwData->idTimer = 0;
  1310. }
  1311. ndwData->ddData.PendingAction = PENDING_ACTION_WINDOWSUPDATE;
  1312. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1313. pSetupExceptionHandler(GetExceptionCode(),
  1314. ERROR_INVALID_PARAMETER,
  1315. NULL
  1316. );
  1317. }
  1318. SetCursor(hOldCursor);
  1319. } else {
  1320. //
  1321. // Call Windows Update to get an updated list of drivers
  1322. // to populate our listview control with, and then
  1323. // reenable the dialog controls.
  1324. //
  1325. HandleWindowsUpdate(hwndDlg, ndwData);
  1326. ToggleDialogControls(hwndDlg, ndwData, TRUE);
  1327. }
  1328. break;
  1329. case IDOK :
  1330. HandleOK:
  1331. iCur = (int)ListView_GetNextItem((ndwData->ddData).hwndDrvList,
  1332. -1,
  1333. LVNI_SELECTED
  1334. );
  1335. if(iCur != LB_ERR) {
  1336. //
  1337. // We have retrieved a valid selection from our listbox.
  1338. //
  1339. if(ndwData->ddData.AuxThreadRunning) {
  1340. //
  1341. // The auxilliary thread is still running. Set our
  1342. // cursor to an hourglass, while we wait for the
  1343. // thread to terminate.
  1344. //
  1345. MYASSERT((ndwData->ddData.PendingAction == PENDING_ACTION_NONE) ||
  1346. (ndwData->ddData.PendingAction == PENDING_ACTION_SHOWCLASS));
  1347. hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1348. try {
  1349. SetupDiCancelDriverInfoSearch(ndwData->ddData.DevInfoSet);
  1350. //
  1351. // Disable all dialog controls, so that no
  1352. // other button may be pressed until we respond
  1353. // to this pending action. Also, kill the
  1354. // timer, so that it doesn't fire in the
  1355. // meantime.
  1356. //
  1357. ToggleDialogControls(hwndDlg, ndwData, FALSE);
  1358. ndwData->bInit = TRUE;
  1359. if(ndwData->idTimer) {
  1360. KillTimer(hwndDlg, SELECTMFG_TIMER_ID);
  1361. ndwData->idTimer = 0;
  1362. }
  1363. ndwData->ddData.PendingAction = PENDING_ACTION_SELDONE;
  1364. ndwData->ddData.CurSelectionForSuccess = iCur;
  1365. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1366. pSetupExceptionHandler(GetExceptionCode(),
  1367. ERROR_INVALID_PARAMETER,
  1368. NULL
  1369. );
  1370. }
  1371. SetCursor(hOldCursor);
  1372. } else {
  1373. //
  1374. // The auxilliary thread has already returned. We
  1375. // can return success right here.
  1376. //
  1377. SetSelectedDriverNode(&(ndwData->ddData), iCur);
  1378. EndDialog(hwndDlg, NO_ERROR);
  1379. }
  1380. } else {
  1381. //
  1382. // If the list box is empty, then just leave. We will
  1383. // treat this just like the user canceled.
  1384. //
  1385. if(0 == ListView_GetItemCount((ndwData->ddData).hwndDrvList)) {
  1386. PostMessage(hwndDlg, WM_COMMAND, IDCANCEL, 0);
  1387. } else {
  1388. //
  1389. // Tell user to select something since there are
  1390. // items in the list
  1391. //
  1392. if(!LoadString(MyDllModuleHandle,
  1393. IDS_SELECT_DEVICE,
  1394. TempString,
  1395. SIZECHARS(TempString))) {
  1396. *TempString = TEXT('\0');
  1397. }
  1398. FormatMessageBox(MyDllModuleHandle,
  1399. hwndDlg,
  1400. MSG_SELECTDEVICE_ERROR,
  1401. TempString,
  1402. MB_OK | MB_ICONEXCLAMATION
  1403. );
  1404. }
  1405. }
  1406. break;
  1407. case IDCANCEL :
  1408. if(ndwData->ddData.AuxThreadRunning) {
  1409. //
  1410. // The auxilliary thread is running, so we have to ask
  1411. // it to cancel, and set our pending action to do the
  1412. // cancel upon the thread's termination notification.
  1413. //
  1414. MYASSERT((ndwData->ddData.PendingAction == PENDING_ACTION_NONE) ||
  1415. (ndwData->ddData.PendingAction == PENDING_ACTION_SHOWCLASS));
  1416. hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1417. try {
  1418. SetupDiCancelDriverInfoSearch(ndwData->ddData.DevInfoSet);
  1419. //
  1420. // Disable all dialog controls, so that no other
  1421. // button may be pressed until we respond to this
  1422. // pending action. Also, kill the timer, so that
  1423. // it doesn't fire in the meantime.
  1424. //
  1425. ToggleDialogControls(hwndDlg, ndwData, FALSE);
  1426. ndwData->bInit = TRUE;
  1427. if(ndwData->idTimer) {
  1428. KillTimer(hwndDlg, SELECTMFG_TIMER_ID);
  1429. ndwData->idTimer = 0;
  1430. }
  1431. ndwData->ddData.PendingAction = PENDING_ACTION_CANCEL;
  1432. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1433. pSetupExceptionHandler(GetExceptionCode(),
  1434. ERROR_INVALID_PARAMETER,
  1435. NULL
  1436. );
  1437. }
  1438. SetCursor(hOldCursor);
  1439. } else {
  1440. //
  1441. // The auxilliary thread isn't running, so we can
  1442. // return right here.
  1443. //
  1444. OnCancel(ndwData);
  1445. EndDialog(hwndDlg, ERROR_CANCELLED);
  1446. }
  1447. break;
  1448. default :
  1449. return FALSE;
  1450. }
  1451. break;
  1452. case WM_NOTIFY :
  1453. switch(((LPNMHDR)lParam)->code) {
  1454. case PSN_SETACTIVE :
  1455. //
  1456. // Init the text in set active since a class installer has
  1457. // the option of replacing it.
  1458. //
  1459. SetDlgText(hwndDlg, IDC_NDW_TEXT, IDS_NDW_PICKDEV1, IDS_NDW_PICKDEV1);
  1460. ndwData->bInit = TRUE; // Still doing some init stuff
  1461. if(!OnSetActive(hwndDlg, ndwData)) {
  1462. SetDlgMsgResult(hwndDlg, uMsg, -1);
  1463. }
  1464. ndwData->bInit = FALSE; // Done with init stuff
  1465. break;
  1466. case PSN_WIZBACK :
  1467. CleanupDriverLists(ndwData);
  1468. if(iwd->DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED) {
  1469. SetDlgMsgResult(hwndDlg, uMsg, IDD_DYNAWIZ_SELECT_PREVPAGE);
  1470. } else {
  1471. SetDlgMsgResult(hwndDlg, uMsg, IDD_DYNAWIZ_SELECTCLASS_PAGE);
  1472. }
  1473. break;
  1474. case PSN_WIZNEXT :
  1475. if(!(iwd->Flags & NDW_INSTALLFLAG_CI_PICKED_OEM)) {
  1476. iCur = (int)ListView_GetNextItem((ndwData->ddData).hwndDrvList,
  1477. -1,
  1478. LVNI_SELECTED
  1479. );
  1480. if(iCur != LB_ERR) {
  1481. //
  1482. // We have retrieved a valid selection from our
  1483. // listbox.
  1484. //
  1485. if (pSetupIsSelectedHardwareIdValid(hwndDlg, &(ndwData->ddData), iCur)) {
  1486. SetSelectedDriverNode(&(ndwData->ddData), iCur);
  1487. } else {
  1488. SetDlgMsgResult(hwndDlg, uMsg, (LRESULT)-1);
  1489. break;
  1490. }
  1491. } else { // Invalid Listview selection
  1492. //
  1493. // Fail the call and end the case
  1494. //
  1495. SetDlgMsgResult(hwndDlg, uMsg, (LRESULT)-1);
  1496. break;
  1497. }
  1498. }
  1499. //
  1500. // Update the current description in the dialog data so
  1501. // that we'll hi-lite the correct selection if the user
  1502. // comes back to this page.
  1503. //
  1504. (ndwData->ddData).iCurDesc = GetCurDesc(&(ndwData->ddData));
  1505. if(iwd->DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED) {
  1506. SetDlgMsgResult(hwndDlg, uMsg, IDD_DYNAWIZ_SELECT_NEXTPAGE);
  1507. } else {
  1508. SetDlgMsgResult(hwndDlg, uMsg, IDD_DYNAWIZ_ANALYZEDEV_PAGE);
  1509. }
  1510. break;
  1511. case LVN_ITEMCHANGED :
  1512. //
  1513. // If the idFrom is the MFG list, then update the Drv list.
  1514. //
  1515. if(((((LPNMHDR)lParam)->idFrom) == IDC_NDW_PICKDEV_MFGLIST) && !ndwData->bInit) {
  1516. if(ndwData->idTimer) {
  1517. KillTimer(hwndDlg, SELECTMFG_TIMER_ID);
  1518. }
  1519. ndwData->idTimer = SetTimer(hwndDlg,
  1520. SELECTMFG_TIMER_ID,
  1521. SELECTMFG_TIMER_DELAY,
  1522. NULL
  1523. );
  1524. if(ndwData->idTimer == 0) {
  1525. goto SelectMfgItemNow;
  1526. }
  1527. }
  1528. //
  1529. // If the idFrom is either of the model lists then update
  1530. // the digital signature icon and text.
  1531. //
  1532. if(((((LPNMHDR)lParam)->idFrom) == IDC_NDW_PICKDEV_ONEMFG_DRVLIST) ||
  1533. ((((LPNMHDR)lParam)->idFrom) == IDC_NDW_PICKDEV_DRVLIST)) {
  1534. LVITEM lviItem;
  1535. int iImage = -1;
  1536. hicon = NULL;
  1537. iCur = (int)ListView_GetNextItem((ndwData->ddData).hwndDrvList,
  1538. -1,
  1539. LVNI_SELECTED
  1540. );
  1541. if(iCur != -1) {
  1542. //
  1543. // We have retrieved a valid selection from our
  1544. // listbox.
  1545. //
  1546. lviItem.mask = LVIF_IMAGE;
  1547. lviItem.iItem = iCur;
  1548. lviItem.iSubItem = 0;
  1549. if(ListView_GetItem((ndwData->ddData).hwndDrvList, &lviItem)) {
  1550. iImage = lviItem.iImage;
  1551. }
  1552. }
  1553. if(iImage != -1) {
  1554. //
  1555. // Enable the OK/Next button, because there's
  1556. // currently an item selected in the model list.
  1557. //
  1558. if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
  1559. EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE);
  1560. } else {
  1561. if(((ndwData->InstallData).Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) &&
  1562. ((ndwData->InstallData).Flags & NDW_INSTALLFLAG_EXPRESSINTRO) &&
  1563. !((ndwData->InstallData).DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
  1564. //
  1565. // No back if we skipped the Class list,
  1566. // and are in express mode
  1567. //
  1568. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
  1569. } else {
  1570. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
  1571. }
  1572. }
  1573. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_ICON), SW_SHOW);
  1574. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), SW_SHOW);
  1575. //
  1576. // Don't show the link if we are in GUI setup
  1577. // because help center is not installed yet and so
  1578. // clicking on the link won't do anything.
  1579. //
  1580. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_LINK),
  1581. GuiSetupInProgress ? SW_HIDE : SW_SHOW);
  1582. hicon = NULL;
  1583. try {
  1584. if(iImage == IMAGE_ICON_SIGNED) {
  1585. //
  1586. // Load the digital signature icon and text
  1587. //
  1588. hicon = LoadImage(MyDllModuleHandle,
  1589. MAKEINTRESOURCE(IDI_SIGNED),
  1590. IMAGE_ICON,
  1591. GetSystemMetrics(SM_CXSMICON),
  1592. GetSystemMetrics(SM_CYSMICON),
  1593. 0
  1594. );
  1595. if(!LoadString(MyDllModuleHandle,
  1596. IDS_DRIVER_IS_SIGNED,
  1597. TempString,
  1598. SIZECHARS(TempString))) {
  1599. *TempString = TEXT('\0');
  1600. }
  1601. if((ndwData->ddData).hFontNormal) {
  1602. SetWindowFont(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), (ndwData->ddData).hFontNormal, TRUE);
  1603. }
  1604. } else if(iImage == IMAGE_ICON_AUTHENTICODE_SIGNED) {
  1605. //
  1606. // Load the digital signature icon and text
  1607. //
  1608. hicon = LoadImage(MyDllModuleHandle,
  1609. MAKEINTRESOURCE(IDI_CERT),
  1610. IMAGE_ICON,
  1611. GetSystemMetrics(SM_CXSMICON),
  1612. GetSystemMetrics(SM_CYSMICON),
  1613. 0
  1614. );
  1615. if(!LoadString(MyDllModuleHandle,
  1616. IDS_DRIVER_AUTHENTICODE_SIGNED,
  1617. TempString,
  1618. SIZECHARS(TempString))) {
  1619. *TempString = TEXT('\0');
  1620. }
  1621. if((ndwData->ddData).hFontNormal) {
  1622. SetWindowFont(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), (ndwData->ddData).hFontNormal, TRUE);
  1623. }
  1624. } else {
  1625. //
  1626. // Load the warning icon and text
  1627. //
  1628. hicon = LoadImage(MyDllModuleHandle,
  1629. MAKEINTRESOURCE(IDI_WARN),
  1630. IMAGE_ICON,
  1631. GetSystemMetrics(SM_CXSMICON),
  1632. GetSystemMetrics(SM_CYSMICON),
  1633. 0
  1634. );
  1635. if(!LoadString(MyDllModuleHandle,
  1636. IDS_DRIVER_NOT_SIGNED,
  1637. TempString,
  1638. SIZECHARS(TempString))) {
  1639. *TempString = TEXT('\0');
  1640. }
  1641. if((ndwData->ddData).hFontBold) {
  1642. SetWindowFont(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), (ndwData->ddData).hFontBold, TRUE);
  1643. }
  1644. }
  1645. if(hicon) {
  1646. hicon = (HICON)SendDlgItemMessage(hwndDlg,
  1647. IDC_NDW_PICKDEV_SIGNED_ICON,
  1648. STM_SETICON,
  1649. (WPARAM)hicon,
  1650. 0L
  1651. );
  1652. }
  1653. } except(pSetupExceptionFilter(GetExceptionCode())) {
  1654. pSetupExceptionHandler(GetExceptionCode(),
  1655. ERROR_INVALID_PARAMETER,
  1656. NULL
  1657. );
  1658. }
  1659. if(hicon) {
  1660. DestroyIcon(hicon);
  1661. }
  1662. SetDlgItemText(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT, TempString);
  1663. } else {
  1664. //
  1665. // Nothing is selected so hide the icon and the
  1666. // text.
  1667. //
  1668. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_ICON), SW_HIDE);
  1669. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), SW_HIDE);
  1670. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_LINK), SW_HIDE);
  1671. //
  1672. // Disable the OK/Next button, because the user
  1673. // can't select a class driver yet.
  1674. //
  1675. if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
  1676. EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
  1677. } else {
  1678. if(((ndwData->InstallData).Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) &&
  1679. ((ndwData->InstallData).Flags & NDW_INSTALLFLAG_EXPRESSINTRO) &&
  1680. !((ndwData->InstallData).DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
  1681. //
  1682. // No back if we skipped the Class list,
  1683. // and are in express mode
  1684. //
  1685. PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
  1686. } else {
  1687. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
  1688. }
  1689. }
  1690. }
  1691. }
  1692. break;
  1693. case NM_RETURN:
  1694. case NM_CLICK:
  1695. if((((LPNMHDR)lParam)->idFrom) == IDC_NDW_PICKDEV_SIGNED_LINK) {
  1696. //
  1697. // We need to know if this is a server machine or a
  1698. // workstation machine since there are different help
  1699. // topic structures for the different products.
  1700. //
  1701. ZeroMemory(&osVersionInfoEx, sizeof(osVersionInfoEx));
  1702. osVersionInfoEx.dwOSVersionInfoSize = sizeof(osVersionInfoEx);
  1703. if(!GetVersionEx((LPOSVERSIONINFO)&osVersionInfoEx)) {
  1704. //
  1705. // If GetVersionEx fails then assume this is a
  1706. // workstation machine.
  1707. //
  1708. osVersionInfoEx.wProductType = VER_NT_WORKSTATION;
  1709. }
  1710. ShellExecute(hwndDlg,
  1711. TEXT("open"),
  1712. TEXT("HELPCTR.EXE"),
  1713. (osVersionInfoEx.wProductType == VER_NT_WORKSTATION)
  1714. ? TEXT("HELPCTR.EXE -url hcp://services/subsite?node=TopLevelBucket_4/Hardware&topic=MS-ITS%3A%25HELP_LOCATION%25%5Csysdm.chm%3A%3A/logo_testing.htm")
  1715. : TEXT("HELPCTR.EXE -url hcp://services/subsite?node=Hardware&topic=MS-ITS%3A%25HELP_LOCATION%25%5Csysdm.chm%3A%3A/logo_testing.htm"),
  1716. NULL,
  1717. SW_SHOWNORMAL
  1718. );
  1719. }
  1720. break;
  1721. case NM_DBLCLK :
  1722. if(((((LPNMHDR)lParam)->idFrom) == IDC_NDW_PICKDEV_DRVLIST) ||
  1723. ((((LPNMHDR)lParam)->idFrom) == IDC_NDW_PICKDEV_ONEMFG_DRVLIST)) {
  1724. if(ndwData->ddData.flags & DD_FLAG_IS_DIALOGBOX) {
  1725. goto HandleOK;
  1726. } else {
  1727. PropSheet_PressButton(GetParent(hwndDlg), PSBTN_NEXT);
  1728. }
  1729. }
  1730. break;
  1731. }
  1732. break;
  1733. case WM_TIMER :
  1734. KillTimer(hwndDlg, SELECTMFG_TIMER_ID);
  1735. ndwData->idTimer = 0;
  1736. SelectMfgItemNow:
  1737. iCur = ListView_GetNextItem((ndwData->ddData).hwndMfgList,
  1738. -1,
  1739. LVNI_SELECTED
  1740. );
  1741. if(iCur != -1) {
  1742. RECT rcTo, rcFrom;
  1743. ListView_EnsureVisible((ndwData->ddData).hwndMfgList, iCur, FALSE);
  1744. UpdateWindow((ndwData->ddData).hwndMfgList);
  1745. GetWindowRect((ndwData->ddData).hwndDrvList, &rcTo);
  1746. MapWindowPoints(NULL, hwndDlg, (LPPOINT)&rcTo, 2);
  1747. ListView_GetItemRect((ndwData->ddData).hwndMfgList,
  1748. iCur,
  1749. &rcFrom,
  1750. LVIR_LABEL
  1751. );
  1752. MapWindowPoints((ndwData->ddData).hwndMfgList,
  1753. hwndDlg,
  1754. (LPPOINT)&rcFrom,
  1755. 2
  1756. );
  1757. DrawAnimatedRects(hwndDlg, IDANI_OPEN, &rcFrom, &rcTo);
  1758. LockAndShowListForMfg(&(ndwData->ddData), iCur);
  1759. }
  1760. break;
  1761. case WM_SYSCOLORCHANGE :
  1762. _OnSysColorChange(hwndDlg, wParam, lParam);
  1763. break;
  1764. case WM_HELP: // F1
  1765. WinHelp(((LPHELPINFO)lParam)->hItemHandle,
  1766. SELECTDEVICE_HELP,
  1767. HELP_WM_HELP,
  1768. (ndwData->ddData.flags & DD_FLAG_SHOWSIMILARDRIVERS) ?
  1769. (ULONG_PTR)SelectDeviceShowSimilarHelpIDs :
  1770. (ULONG_PTR)SelectDeviceShowAllHelpIDs
  1771. );
  1772. break;
  1773. case WM_CONTEXTMENU: // right mouse click
  1774. WinHelp((HWND)wParam,
  1775. SELECTDEVICE_HELP,
  1776. HELP_CONTEXTMENU,
  1777. (ndwData->ddData.flags & DD_FLAG_SHOWSIMILARDRIVERS) ?
  1778. (ULONG_PTR)SelectDeviceShowSimilarHelpIDs :
  1779. (ULONG_PTR)SelectDeviceShowAllHelpIDs
  1780. );
  1781. break;
  1782. default :
  1783. if(!g_uQueryCancelAutoPlay) {
  1784. g_uQueryCancelAutoPlay = RegisterWindowMessage(TEXT("QueryCancelAutoPlay"));
  1785. }
  1786. if(uMsg == g_uQueryCancelAutoPlay) {
  1787. SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, 1 );
  1788. return 1; // cancel auto-play
  1789. }
  1790. return FALSE;
  1791. }
  1792. return TRUE;
  1793. }
  1794. INT CALLBACK
  1795. DriverNodeCompareProc(
  1796. LPARAM lParam1,
  1797. LPARAM lParam2,
  1798. LPARAM lParamSort
  1799. )
  1800. /*++
  1801. Routine Description:
  1802. This routine is the callback for the list control sorting that is done when
  1803. ListView_SortItems is called.
  1804. The sorting this routine does is that if a DriverNode has the
  1805. DNF_INF_IS_SIGNED flag then it is considered better than a DriverNode that
  1806. does not have this flag. If both DriverNodes have, or don't have, this
  1807. flag then a simple string compare is done.
  1808. Return Value:
  1809. -1 if lParam1 is better than lParam2 (should be higher in the ListControl
  1810. +1 if lParam2 is better than lParam1 (should be higher in the ListControl
  1811. 0 if lParam1 and lParam2 are the same
  1812. --*/
  1813. {
  1814. if((((PDRIVER_NODE)lParam1)->Flags & DNF_INF_IS_SIGNED) &&
  1815. !(((PDRIVER_NODE)lParam2)->Flags & DNF_INF_IS_SIGNED)) {
  1816. return -1;
  1817. }
  1818. if((((PDRIVER_NODE)lParam2)->Flags & DNF_INF_IS_SIGNED) &&
  1819. !(((PDRIVER_NODE)lParam1)->Flags & DNF_INF_IS_SIGNED)) {
  1820. return 1;
  1821. }
  1822. //
  1823. // At this point both driver nodes are signed or both are not signed, so
  1824. // compare based on their description.
  1825. //
  1826. return (lstrcmpi(pStringTableStringFromId(((PDEVICE_INFO_SET)lParamSort)->StringTable,
  1827. ((PDRIVER_NODE)lParam1)->DevDescriptionDisplayName),
  1828. pStringTableStringFromId(((PDEVICE_INFO_SET)lParamSort)->StringTable,
  1829. ((PDRIVER_NODE)lParam2)->DevDescriptionDisplayName)));
  1830. }
  1831. VOID
  1832. _OnSysColorChange(
  1833. HWND hWnd,
  1834. WPARAM wParam,
  1835. LPARAM lParam
  1836. )
  1837. /*++
  1838. Routine Description:
  1839. This routine notifies all child windows of the specified window when there
  1840. is a system color change.
  1841. Return Value:
  1842. None.
  1843. --*/
  1844. {
  1845. HWND hChildWnd;
  1846. hChildWnd = GetWindow(hWnd, GW_CHILD);
  1847. while(hChildWnd != NULL) {
  1848. SendMessage(hChildWnd, WM_SYSCOLORCHANGE, wParam, lParam);
  1849. hChildWnd = GetWindow(hChildWnd, GW_HWNDNEXT);
  1850. }
  1851. }
  1852. DWORD
  1853. FillInDeviceList(
  1854. IN HWND hwndDlg,
  1855. IN PSP_DIALOGDATA lpdd
  1856. )
  1857. /*++
  1858. Routine Description:
  1859. This routine sets the dialog to have the appropriate description strings.
  1860. It also alternates dialog between showing the manufacturer "double list"
  1861. and the single list. This is done by showing/hiding overlapping listview.
  1862. NOTE: DO NOT CALL THIS ROUTINE WHILE ANOTHER THREAD IS BUSY BUILDING A
  1863. CLASS DRIVER LIST. WE WILL HANG HERE UNTIL THE OTHER THREAD COMPLETES!!!!
  1864. Arguments:
  1865. hwndDlg - Supplies the handle of the dialog window.
  1866. lpdd - Supplies the address of a dialog data buffer containing parameters
  1867. to be used in filling in the device list.
  1868. Return Value:
  1869. If success, the return value is NO_ERROR, otherwise, it is a Win32 code.
  1870. --*/
  1871. {
  1872. PDEVICE_INFO_SET pDeviceInfoSet;
  1873. PDEVINFO_ELEM DevInfoElem;
  1874. PDRIVER_NODE DriverNodeHead, CurDriverNode;
  1875. DWORD DriverNodeType;
  1876. LONG MfgNameId;
  1877. INT i;
  1878. LPTSTR lpszMfg;
  1879. LV_COLUMN lvcCol;
  1880. LV_ITEM lviItem;
  1881. BOOL bDidDrvList = FALSE;
  1882. PDEVINSTALL_PARAM_BLOCK dipb;
  1883. DWORD Err = NO_ERROR;
  1884. TCHAR szBuf[LINE_LEN];
  1885. TCHAR szMessage[MAX_INSTRUCTION_LEN];
  1886. TCHAR szText[SDT_MAX_TEXT];
  1887. LPTSTR lpszText;
  1888. size_t szTextSize;
  1889. CONST GUID *ClassGuid;
  1890. HRESULT hr;
  1891. BOOL TurnRedrawBackOn = FALSE;
  1892. MYASSERT(lpdd);
  1893. if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
  1894. //
  1895. // should never hit this code path
  1896. //
  1897. MYASSERT(pDeviceInfoSet);
  1898. return ERROR_INVALID_HANDLE;
  1899. }
  1900. try {
  1901. if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
  1902. DevInfoElem = lpdd->DevInfoElem;
  1903. } else {
  1904. DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
  1905. }
  1906. if(DevInfoElem) {
  1907. dipb = &(DevInfoElem->InstallParamBlock);
  1908. ClassGuid = &(DevInfoElem->ClassGuid);
  1909. if(lpdd->bShowCompat) {
  1910. DriverNodeHead = DevInfoElem->CompatDriverHead;
  1911. DriverNodeType = SPDIT_COMPATDRIVER;
  1912. } else {
  1913. DriverNodeHead = DevInfoElem->ClassDriverHead;
  1914. DriverNodeType = SPDIT_CLASSDRIVER;
  1915. }
  1916. } else {
  1917. //
  1918. // We better not be trying to display a compatible driver list if
  1919. // we don't have a devinfo element!
  1920. //
  1921. MYASSERT(!lpdd->bShowCompat);
  1922. //
  1923. // Since we don't have any compatible drivers to show, we will hide
  1924. // the show compatible checkbox.
  1925. //
  1926. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), SW_HIDE);
  1927. dipb = &(pDeviceInfoSet->InstallParamBlock);
  1928. DriverNodeHead = pDeviceInfoSet->ClassDriverHead;
  1929. DriverNodeType = SPDIT_CLASSDRIVER;
  1930. if(pDeviceInfoSet->HasClassGuid) {
  1931. ClassGuid = &(pDeviceInfoSet->ClassGuid);
  1932. } else {
  1933. ClassGuid = &GUID_DEVCLASS_UNKNOWN;
  1934. }
  1935. }
  1936. if(!DriverNodeHead) {
  1937. if(!(lpdd->flags & DD_FLAG_IS_DIALOGBOX)) {
  1938. //
  1939. // We can't just go away, so we have to do something useful.
  1940. // For now, simply display the UI as if we had a single-Mfg
  1941. // list, except that the list is empty.
  1942. //
  1943. // Hide the mult mfg controls
  1944. //
  1945. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_MFGLIST), SW_HIDE);
  1946. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_DRVLIST), SW_HIDE);
  1947. //
  1948. // Show the Single MFG controls
  1949. //
  1950. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), SW_SHOW);
  1951. //
  1952. // Set the Models string
  1953. //
  1954. lvcCol.mask = LVCF_FMT | LVCF_TEXT;
  1955. lvcCol.fmt = LVCFMT_LEFT;
  1956. if(USE_CI_SELSTRINGS(dipb)) {
  1957. lvcCol.pszText = GET_CI_SELSTRINGS(dipb, ListLabel);
  1958. ListView_SetColumn(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), 0, &lvcCol);
  1959. } else {
  1960. if(!(LoadString(MyDllModuleHandle,
  1961. IDS_NDWSEL_MODELSLABEL,
  1962. szBuf,
  1963. SIZECHARS(szBuf)))) {
  1964. *szBuf = TEXT('\0');
  1965. }
  1966. lvcCol.pszText = szBuf;
  1967. ListView_SetColumn(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), 0, &lvcCol);
  1968. }
  1969. //
  1970. // Use the single listbox view for the driver list.
  1971. //
  1972. lpdd->hwndDrvList = GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST);
  1973. ListView_DeleteAllItems(lpdd->hwndDrvList);
  1974. }
  1975. Err = ERROR_DI_BAD_PATH;
  1976. leave;
  1977. }
  1978. if((lpdd->flags & DD_FLAG_IS_DIALOGBOX) && !USE_CI_SELSTRINGS(dipb)) {
  1979. //
  1980. // If a class installer didn't supply strings for us to use in this
  1981. // dialogbox, then retrieve the instruction text to be used.
  1982. //
  1983. // First, get the class description to use for the dialog text.
  1984. //
  1985. if(!SetupDiGetClassDescription(ClassGuid, szBuf, SIZECHARS(szBuf), NULL)) {
  1986. //
  1987. // Fall back to the generic description "device"
  1988. //
  1989. if(!LoadString(MyDllModuleHandle,
  1990. IDS_GENERIC_DEVNAME,
  1991. szBuf,
  1992. SIZECHARS(szBuf))) {
  1993. *szBuf = TEXT('\0');
  1994. }
  1995. }
  1996. if(!lpdd->bShowCompat) {
  1997. //
  1998. // Show class list.
  1999. //
  2000. hr = HRESULT_FROM_WIN32(GLE_FN_CALL(0,
  2001. LoadString(MyDllModuleHandle,
  2002. IDS_INSTALLSTR1,
  2003. szMessage,
  2004. SIZECHARS(szMessage))
  2005. )
  2006. );
  2007. if(SUCCEEDED(hr)) {
  2008. hr = StringCchPrintfEx(szText,
  2009. SIZECHARS(szText),
  2010. &lpszText,
  2011. &szTextSize,
  2012. 0,
  2013. szMessage,
  2014. szBuf
  2015. );
  2016. MYASSERT(SUCCEEDED(hr));
  2017. } else {
  2018. *szText = TEXT('\0');
  2019. }
  2020. } else {
  2021. //
  2022. // Show compatible list.
  2023. //
  2024. hr = HRESULT_FROM_WIN32(GLE_FN_CALL(0,
  2025. LoadString(MyDllModuleHandle,
  2026. IDS_INSTALLSTR0,
  2027. szMessage,
  2028. SIZECHARS(szMessage))
  2029. )
  2030. );
  2031. if(SUCCEEDED(hr)) {
  2032. hr = StringCchPrintfEx(szText,
  2033. SIZECHARS(szText),
  2034. &lpszText,
  2035. &szTextSize,
  2036. 0,
  2037. szMessage,
  2038. szBuf
  2039. );
  2040. MYASSERT(SUCCEEDED(hr));
  2041. } else {
  2042. *szText = TEXT('\0');
  2043. }
  2044. if(SUCCEEDED(hr)) {
  2045. hr = HRESULT_FROM_WIN32(GLE_FN_CALL(0,
  2046. LoadString(MyDllModuleHandle,
  2047. IDS_INSTALLCLASS,
  2048. lpszText,
  2049. szTextSize)
  2050. )
  2051. );
  2052. if(SUCCEEDED(hr)) {
  2053. //
  2054. // Update our pointer to the end of the string, and the
  2055. // variable indicating the space remaining in the
  2056. // szText buffer.
  2057. //
  2058. hr = StringCchLength(szText, SIZECHARS(szText), &szTextSize);
  2059. MYASSERT(SUCCEEDED(hr));
  2060. if(SUCCEEDED(hr)) {
  2061. lpszText = szText + szTextSize;
  2062. szTextSize = SIZECHARS(szText) - szTextSize;
  2063. }
  2064. }
  2065. }
  2066. }
  2067. if(SUCCEEDED(hr)) {
  2068. if(dipb->DriverPath != -1) {
  2069. //
  2070. // Inform the user that the list they're seeing represents
  2071. // only what was found in the location they pointed us at.
  2072. //
  2073. LoadString(MyDllModuleHandle,
  2074. IDS_INSTALLOEM1,
  2075. lpszText,
  2076. szTextSize
  2077. );
  2078. } else if (dipb->Flags & DI_SHOWOEM) {
  2079. //
  2080. // Tell the user they can click "Have Disk".
  2081. //
  2082. LoadString(MyDllModuleHandle,
  2083. IDS_INSTALLOEM,
  2084. lpszText,
  2085. szTextSize
  2086. );
  2087. }
  2088. }
  2089. SetDlgItemText(hwndDlg, IDC_NDW_TEXT, szText);
  2090. }
  2091. if((!lpdd->bShowCompat) && (dipb->Flags & DI_MULTMFGS)) {
  2092. //
  2093. // Hide the Single MFG controls
  2094. //
  2095. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), SW_HIDE);
  2096. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_STATUS_TEXT), SW_HIDE);
  2097. //
  2098. // Show the Multiple MFG controls
  2099. //
  2100. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_MFGLIST), SW_SHOW);
  2101. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_DRVLIST), SW_SHOW);
  2102. //
  2103. // Set the colunm heading for the Driver list
  2104. //
  2105. lvcCol.mask = LVCF_FMT | LVCF_TEXT;
  2106. lvcCol.fmt = LVCFMT_LEFT;
  2107. if(USE_CI_SELSTRINGS(dipb)) {
  2108. lvcCol.pszText = GET_CI_SELSTRINGS(dipb, ListLabel);
  2109. ListView_SetColumn(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_DRVLIST), 0, &lvcCol);
  2110. } else {
  2111. if(!(LoadString(MyDllModuleHandle,
  2112. IDS_NDWSEL_MODELSLABEL,
  2113. szBuf,
  2114. SIZECHARS(szBuf)))) {
  2115. *szBuf = TEXT('\0');
  2116. }
  2117. lvcCol.pszText = szBuf;
  2118. ListView_SetColumn(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_DRVLIST), 0, &lvcCol);
  2119. }
  2120. //
  2121. // Use the 2nd listbox of the Manufacturers/Models view for the
  2122. // driver list.
  2123. //
  2124. lpdd->hwndDrvList = GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_DRVLIST);
  2125. ListView_SetExtendedListViewStyle(lpdd->hwndDrvList, LVS_EX_LABELTIP);
  2126. if(lpdd->hImageList) {
  2127. ListView_SetImageList(lpdd->hwndDrvList, lpdd->hImageList, LVSIL_SMALL);
  2128. }
  2129. //
  2130. // No redraw for faster insert
  2131. //
  2132. SendMessage(lpdd->hwndMfgList, WM_SETREDRAW, FALSE, 0L);
  2133. TurnRedrawBackOn = TRUE;
  2134. //
  2135. // Clean out the MFG list before filling it.
  2136. //
  2137. ListView_DeleteAllItems(lpdd->hwndMfgList);
  2138. lviItem.mask = LVIF_TEXT | LVIF_PARAM;
  2139. lviItem.iItem = 0;
  2140. lviItem.iSubItem = 0;
  2141. //
  2142. // Setup the Column Header
  2143. //
  2144. MfgNameId = -1;
  2145. for(CurDriverNode = DriverNodeHead; CurDriverNode; CurDriverNode = CurDriverNode->Next) {
  2146. //
  2147. // Skip this driver node if it is to be excluded of if it is an
  2148. // old INET driver or if it is a BAD driver.
  2149. //
  2150. if((CurDriverNode->Flags & DNF_OLD_INET_DRIVER) ||
  2151. (CurDriverNode->Flags & DNF_BAD_DRIVER) ||
  2152. ((CurDriverNode->Flags & DNF_EXCLUDEFROMLIST) &&
  2153. !(dipb->FlagsEx & DI_FLAGSEX_ALLOWEXCLUDEDDRVS))) {
  2154. continue;
  2155. }
  2156. if((MfgNameId == -1) || (MfgNameId != CurDriverNode->MfgName)) {
  2157. MfgNameId = CurDriverNode->MfgName;
  2158. MYASSERT(CurDriverNode->MfgDisplayName != -1);
  2159. lpszMfg = pStringTableStringFromId(pDeviceInfoSet->StringTable,
  2160. CurDriverNode->MfgDisplayName
  2161. );
  2162. lviItem.pszText = lpszMfg;
  2163. lviItem.lParam = (LPARAM)CurDriverNode;
  2164. i = ListView_InsertItem(lpdd->hwndMfgList, &lviItem);
  2165. }
  2166. //
  2167. // If this driver node is the selected one, preselect here.
  2168. //
  2169. if(lpdd->iCurDesc == CurDriverNode->DevDescription) {
  2170. ListView_SetItemState(lpdd->hwndMfgList,
  2171. i,
  2172. (LVIS_SELECTED|LVIS_FOCUSED),
  2173. (LVIS_SELECTED|LVIS_FOCUSED)
  2174. );
  2175. ShowListForMfg(lpdd, pDeviceInfoSet, dipb, NULL, i);
  2176. bDidDrvList = TRUE;
  2177. }
  2178. }
  2179. //
  2180. // Resize the Column
  2181. //
  2182. ListView_SetColumnWidth(lpdd->hwndMfgList, 0, LVSCW_AUTOSIZE_USEHEADER);
  2183. //
  2184. // If we did not expand one of the MFGs by default, then
  2185. // expand the First MFG.
  2186. //
  2187. if(!bDidDrvList) {
  2188. ListView_SetItemState(lpdd->hwndMfgList,
  2189. 0,
  2190. (LVIS_SELECTED|LVIS_FOCUSED),
  2191. (LVIS_SELECTED|LVIS_FOCUSED)
  2192. );
  2193. ShowListForMfg(lpdd, pDeviceInfoSet, dipb, NULL, 0);
  2194. SendMessage(lpdd->hwndMfgList, WM_SETREDRAW, TRUE, 0L);
  2195. TurnRedrawBackOn = FALSE;
  2196. } else {
  2197. //
  2198. // We must set redraw back to true before sending the
  2199. // LVM_ENSUREVISIBLE message, or otherwise, the listbox item
  2200. // may only be partially exposed.
  2201. //
  2202. SendMessage(lpdd->hwndMfgList, WM_SETREDRAW, TRUE, 0L);
  2203. TurnRedrawBackOn = FALSE;
  2204. ListView_EnsureVisible(lpdd->hwndMfgList,
  2205. ListView_GetNextItem(lpdd->hwndMfgList, -1, LVNI_SELECTED),
  2206. FALSE
  2207. );
  2208. }
  2209. } else {
  2210. //
  2211. // Hide the mult mfg controls
  2212. //
  2213. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_MFGLIST), SW_HIDE);
  2214. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_DRVLIST), SW_HIDE);
  2215. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_STATUS_TEXT), SW_HIDE);
  2216. //
  2217. // Show the Single MFG controls
  2218. //
  2219. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), SW_SHOW);
  2220. //
  2221. // Set the Models string
  2222. //
  2223. lvcCol.mask = LVCF_FMT | LVCF_TEXT;
  2224. lvcCol.fmt = LVCFMT_LEFT;
  2225. if(USE_CI_SELSTRINGS(dipb)) {
  2226. lvcCol.pszText = GET_CI_SELSTRINGS(dipb, ListLabel);
  2227. ListView_SetColumn(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), 0, &lvcCol);
  2228. } else {
  2229. if(!(LoadString(MyDllModuleHandle,
  2230. IDS_NDWSEL_MODELSLABEL,
  2231. szBuf,
  2232. SIZECHARS(szBuf)))) {
  2233. *szBuf = TEXT('\0');
  2234. }
  2235. lvcCol.pszText = szBuf;
  2236. ListView_SetColumn(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), 0, &lvcCol);
  2237. }
  2238. //
  2239. // Use the single listbox view for the driver list.
  2240. //
  2241. lpdd->hwndDrvList = GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST);
  2242. if (lpdd->hImageList) {
  2243. ListView_SetImageList(lpdd->hwndDrvList, lpdd->hImageList, LVSIL_SMALL);
  2244. }
  2245. ShowListForMfg(lpdd, pDeviceInfoSet, dipb, DriverNodeHead, -1);
  2246. }
  2247. } except(pSetupExceptionFilter(GetExceptionCode())) {
  2248. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  2249. if(TurnRedrawBackOn) {
  2250. SendMessage(lpdd->hwndMfgList, WM_SETREDRAW, TRUE, 0L);
  2251. }
  2252. }
  2253. UnlockDeviceInfoSet(pDeviceInfoSet);
  2254. return Err;
  2255. }
  2256. VOID
  2257. ShowListForMfg(
  2258. IN PSP_DIALOGDATA lpdd,
  2259. IN PDEVICE_INFO_SET DeviceInfoSet,
  2260. IN PDEVINSTALL_PARAM_BLOCK InstallParamBlock,
  2261. IN PDRIVER_NODE DriverNode, OPTIONAL
  2262. IN INT iMfg
  2263. )
  2264. /*++
  2265. Routine Description:
  2266. This routine builds the driver description list.
  2267. THE LOCK MUST ALREADY BE ACQUIRED BEFORE CALLING THIS ROUTINE!
  2268. Arguments:
  2269. lpdd - Supplies the address of a dialog data buffer containing parameters
  2270. to be used in filling in the driver description list.
  2271. DeviceInfoSet - Supplies the address of the device information set
  2272. structure for which the driver description list is to be built.
  2273. InstallParamBlock - Supplies the address of a device installation parameter
  2274. block that controls how the list is displayed.
  2275. DriverNode - Optionally, supplies a pointer to the first node in a driver
  2276. node list to traverse, adding to the list for each node. If DriverNode
  2277. is not specified, then the list is to be built based on a particular
  2278. manufacturer, whose index in the Manufacturer list is given by iMfg.
  2279. iMfg - Supplies the index within the Manufacturer list that the driver
  2280. description list is to be based on. This parameter is ignored if a
  2281. DriverNode is specified.
  2282. Return Value:
  2283. None.
  2284. --*/
  2285. {
  2286. INT i = -1;
  2287. LV_ITEM lviItem;
  2288. LV_FINDINFO lvfiFind;
  2289. LONG MfgNameId = -1;
  2290. TCHAR szTemp[LINE_LEN];
  2291. SYSTEMTIME SystemTime;
  2292. TCHAR FormatString[LINE_LEN];
  2293. HRESULT hr;
  2294. PTSTR StringEnd;
  2295. size_t StringBufSize;
  2296. //
  2297. // Set listview sortascending style based on DI_INF_IS_SORTED flag
  2298. //
  2299. SetWindowLong(lpdd->hwndDrvList,
  2300. GWL_STYLE,
  2301. (GetWindowLong(lpdd->hwndDrvList, GWL_STYLE) & ~(LVS_SORTASCENDING | LVS_SORTDESCENDING)) |
  2302. ((InstallParamBlock->Flags & DI_INF_IS_SORTED)
  2303. ? 0
  2304. : LVS_SORTASCENDING)
  2305. );
  2306. SendMessage(lpdd->hwndDrvList, WM_SETREDRAW, FALSE, 0L);
  2307. try {
  2308. //
  2309. // Clean out the List.
  2310. //
  2311. ListView_DeleteAllItems(lpdd->hwndDrvList);
  2312. if(!DriverNode) {
  2313. if(ListView_GetItemCount(lpdd->hwndMfgList) > 0) {
  2314. lviItem.mask = LVIF_PARAM;
  2315. lviItem.iItem = iMfg;
  2316. lviItem.iSubItem = 0;
  2317. if(!ListView_GetItem(lpdd->hwndMfgList, &lviItem) ||
  2318. !(DriverNode = GetDriverNodeFromLParam(DeviceInfoSet, lpdd, lviItem.lParam))) {
  2319. leave;
  2320. }
  2321. MfgNameId = DriverNode->MfgName;
  2322. } else {
  2323. //
  2324. // This means that there are no Manufacturers so we just have a empty list.
  2325. //
  2326. leave;
  2327. }
  2328. }
  2329. lviItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
  2330. lviItem.iItem = 0;
  2331. lviItem.iSubItem = 0;
  2332. //
  2333. // Add descriptions to the list
  2334. //
  2335. for( ; DriverNode; DriverNode = DriverNode->Next) {
  2336. if((MfgNameId != -1) && (MfgNameId != DriverNode->MfgName)) {
  2337. //
  2338. // We've gone beyond the manufacturer list--break out of loop.
  2339. //
  2340. break;
  2341. }
  2342. //
  2343. // If this is a special "Don't show me" one, then skip it
  2344. //
  2345. if((DriverNode->Flags & DNF_OLD_INET_DRIVER) ||
  2346. (DriverNode->Flags & DNF_BAD_DRIVER) ||
  2347. ((DriverNode->Flags & DNF_EXCLUDEFROMLIST) &&
  2348. !(InstallParamBlock->FlagsEx & DI_FLAGSEX_ALLOWEXCLUDEDDRVS))) {
  2349. continue;
  2350. }
  2351. //
  2352. // Build the device description string to add to the models list.
  2353. //
  2354. hr = StringCchCopyEx(
  2355. szTemp,
  2356. SIZECHARS(szTemp),
  2357. pStringTableStringFromId(DeviceInfoSet->StringTable,
  2358. DriverNode->DevDescriptionDisplayName),
  2359. &StringEnd,
  2360. &StringBufSize,
  2361. 0
  2362. );
  2363. //
  2364. // This shouldn't fail, since the maximum length of a device
  2365. // description name is less than the size of our szTemp buffer!
  2366. //
  2367. MYASSERT(SUCCEEDED(hr));
  2368. if(SUCCEEDED(hr)) {
  2369. if((DriverNode->Flags & DNF_DUPDESC) &&
  2370. (DriverNode->ProviderDisplayName != -1)) {
  2371. //
  2372. // For drivers with duplicate descriptions add the provider
  2373. // name in parens.
  2374. //
  2375. if(GetWindowLong(lpdd->hwndDrvList, GWL_EXSTYLE) & WS_EX_RTLREADING) {
  2376. MYVERIFY(SUCCEEDED(StringCchPrintfEx(StringEnd,
  2377. StringBufSize,
  2378. NULL,
  2379. NULL,
  2380. STRSAFE_IGNORE_NULLS | STRSAFE_NO_TRUNCATION,
  2381. L" \x200E(%s)\x200E",
  2382. pStringTableStringFromId(
  2383. DeviceInfoSet->StringTable,
  2384. DriverNode->ProviderDisplayName)
  2385. )));
  2386. } else {
  2387. MYVERIFY(SUCCEEDED(StringCchPrintfEx(StringEnd,
  2388. StringBufSize,
  2389. NULL,
  2390. NULL,
  2391. STRSAFE_IGNORE_NULLS | STRSAFE_NO_TRUNCATION,
  2392. TEXT(" (%s)"),
  2393. pStringTableStringFromId(
  2394. DeviceInfoSet->StringTable,
  2395. DriverNode->ProviderDisplayName)
  2396. )));
  2397. }
  2398. } else if(DriverNode->Flags & DNF_DUPPROVIDER) {
  2399. //
  2400. // For drivers with duplicate descriptions and providers,
  2401. // add the driver version and driver date if there is one,
  2402. // in brackets.
  2403. //
  2404. if(DriverNode->DriverVersion != 0) {
  2405. ULARGE_INTEGER Version;
  2406. Version.QuadPart = DriverNode->DriverVersion;
  2407. if(LoadString(MyDllModuleHandle,
  2408. IDS_VERSION,
  2409. FormatString,
  2410. SIZECHARS(FormatString))) {
  2411. hr = StringCchPrintfEx(StringEnd,
  2412. StringBufSize,
  2413. &StringEnd,
  2414. &StringBufSize,
  2415. STRSAFE_NO_TRUNCATION,
  2416. FormatString,
  2417. HIWORD(Version.HighPart),
  2418. LOWORD(Version.HighPart),
  2419. HIWORD(Version.LowPart),
  2420. LOWORD(Version.LowPart)
  2421. );
  2422. }
  2423. }
  2424. if(SUCCEEDED(hr) &&
  2425. ((DriverNode->DriverDate.dwLowDateTime != 0) ||
  2426. (DriverNode->DriverDate.dwHighDateTime != 0))) {
  2427. if(FileTimeToSystemTime(&(DriverNode->DriverDate), &SystemTime)) {
  2428. if(GetDateFormat(LOCALE_USER_DEFAULT,
  2429. ((GetWindowLong(lpdd->hwndDrvList, GWL_EXSTYLE) & WS_EX_RTLREADING)
  2430. ? DATE_SHORTDATE | DATE_RTLREADING
  2431. : DATE_SHORTDATE),
  2432. &SystemTime,
  2433. NULL,
  2434. FormatString,
  2435. SIZECHARS(FormatString)) != 0) {
  2436. MYVERIFY(SUCCEEDED(StringCchPrintfEx(StringEnd,
  2437. StringBufSize,
  2438. NULL,
  2439. NULL,
  2440. STRSAFE_NO_TRUNCATION,
  2441. TEXT(" [%s]"),
  2442. FormatString
  2443. )));
  2444. }
  2445. }
  2446. }
  2447. }
  2448. }
  2449. lviItem.pszText = szTemp;
  2450. lviItem.lParam = (LPARAM)DriverNode;
  2451. //
  2452. // We have to test for DNF_AUTHENTICODE_SIGNED first since if
  2453. // that flag is set then DNF_INF_IS_SIGNED is also always set.
  2454. //
  2455. if (DriverNode->Flags & DNF_AUTHENTICODE_SIGNED) {
  2456. lviItem.iImage = IMAGE_ICON_AUTHENTICODE_SIGNED;
  2457. } else if (DriverNode->Flags & DNF_INF_IS_SIGNED) {
  2458. lviItem.iImage = IMAGE_ICON_SIGNED;
  2459. } else {
  2460. lviItem.iImage = IMAGE_ICON_NOT_SIGNED;
  2461. }
  2462. if(ListView_InsertItem(lpdd->hwndDrvList, &lviItem) != -1) {
  2463. lviItem.iItem++;
  2464. }
  2465. }
  2466. //
  2467. // Sort the list unless the DI_INF_IS_SORTED flag is set
  2468. //
  2469. if(GetWindowLong(lpdd->hwndDrvList, GWL_STYLE) & LVS_SORTASCENDING) {
  2470. ListView_SortItems(lpdd->hwndDrvList,
  2471. (PFNLVCOMPARE)DriverNodeCompareProc,
  2472. (LPARAM)DeviceInfoSet
  2473. );
  2474. }
  2475. //
  2476. // Resize the Column
  2477. //
  2478. ListView_SetColumnWidth(lpdd->hwndDrvList, 0, LVSCW_AUTOSIZE_USEHEADER);
  2479. //
  2480. // select the current description string
  2481. //
  2482. if(lpdd->iCurDesc == -1) {
  2483. i = 0;
  2484. } else {
  2485. lvfiFind.flags = LVFI_STRING;
  2486. lvfiFind.psz = pStringTableStringFromId(DeviceInfoSet->StringTable,
  2487. lpdd->iCurDesc
  2488. );
  2489. i = ListView_FindItem(lpdd->hwndDrvList, -1, &lvfiFind);
  2490. if(i == -1) {
  2491. i = 0;
  2492. }
  2493. }
  2494. ListView_SetItemState(lpdd->hwndDrvList,
  2495. i,
  2496. (LVIS_SELECTED|LVIS_FOCUSED),
  2497. (LVIS_SELECTED|LVIS_FOCUSED)
  2498. );
  2499. } except(pSetupExceptionFilter(GetExceptionCode())) {
  2500. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  2501. i = -1;
  2502. }
  2503. //
  2504. // We must turn redraw back on before sending the LVM_ENSUREVISIBLE
  2505. // message, or otherwise the item may only be partially visible.
  2506. //
  2507. SendMessage(lpdd->hwndDrvList, WM_SETREDRAW, TRUE, 0L);
  2508. if(i != -1) {
  2509. ListView_EnsureVisible(lpdd->hwndDrvList, i, FALSE);
  2510. }
  2511. }
  2512. VOID
  2513. LockAndShowListForMfg(
  2514. IN PSP_DIALOGDATA lpdd,
  2515. IN INT iMfg
  2516. )
  2517. /*++
  2518. Routine Description:
  2519. This routine is a wrapper for ShowListForMfg. It is to be called from
  2520. points where the device information set lock is not already owned (e.g.,
  2521. the dialog prop message loop.
  2522. Arguments:
  2523. lpdd - Supplies the address of a dialog data buffer containing parameters
  2524. to be used in filling in the driver description list.
  2525. iMfg - Supplies the index within the Manufacturer list that the driver
  2526. description list is to be based on.
  2527. Return Value:
  2528. None.
  2529. --*/
  2530. {
  2531. PDEVICE_INFO_SET pDeviceInfoSet;
  2532. PDEVINSTALL_PARAM_BLOCK dipb;
  2533. PDEVINFO_ELEM DevInfoElem;
  2534. MYASSERT(lpdd);
  2535. if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
  2536. //
  2537. // should never hit this code path
  2538. //
  2539. MYASSERT(pDeviceInfoSet);
  2540. return;
  2541. }
  2542. try {
  2543. if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
  2544. DevInfoElem = lpdd->DevInfoElem;
  2545. } else {
  2546. DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
  2547. }
  2548. dipb = DevInfoElem ? &(DevInfoElem->InstallParamBlock)
  2549. : &(pDeviceInfoSet->InstallParamBlock);
  2550. ShowListForMfg(lpdd,
  2551. pDeviceInfoSet,
  2552. dipb,
  2553. NULL,
  2554. iMfg
  2555. );
  2556. } except(pSetupExceptionFilter(GetExceptionCode())) {
  2557. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  2558. }
  2559. UnlockDeviceInfoSet(pDeviceInfoSet);
  2560. }
  2561. BOOL
  2562. InitSelectDeviceDlg(
  2563. IN HWND hwndDlg,
  2564. IN OUT PNEWDEVWIZ_DATA ndwData
  2565. )
  2566. /*++
  2567. Routine Description:
  2568. This routine initializes the select device wizard page. It
  2569. builds the class list if it is needed, shows/hides necessary
  2570. controls based on Flags, and comes up with the right text
  2571. description of what's going on.
  2572. Arguments:
  2573. hwndDlg - Handle to dialog window
  2574. ndwData - Supplies the address of a New Device Wizard data block to be used
  2575. during the processing of this message.
  2576. Return Value:
  2577. TRUE if we have at least one driver (compat or class) displayed.
  2578. FALSE if we do not have any drivers (class and compat) displayed.
  2579. --*/
  2580. {
  2581. PDEVICE_INFO_SET pDeviceInfoSet = NULL;
  2582. PDEVINFO_ELEM DevInfoElem;
  2583. PDEVINSTALL_PARAM_BLOCK dipb;
  2584. SP_DEVINFO_DATA DevInfoData;
  2585. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  2586. DWORD DriverType = SPDIT_CLASSDRIVER;
  2587. DWORD Err;
  2588. INT ShowWhat;
  2589. CONST GUID *ClassGuid;
  2590. HICON hIcon;
  2591. LV_COLUMN lvcCol;
  2592. BOOL SpawnClassDriverSearch = FALSE;
  2593. PCLASSDRV_THREAD_CONTEXT ClassDrvThreadContext;
  2594. HCURSOR hOldCursor;
  2595. BOOL bRet = TRUE;
  2596. PSP_DIALOGDATA lpdd;
  2597. TCHAR szBuf[LINE_LEN];
  2598. HFONT hfont;
  2599. LOGFONT LogFont;
  2600. MYASSERT(ndwData);
  2601. lpdd = &(ndwData->ddData);
  2602. MYASSERT(lpdd);
  2603. if(!lpdd->hwndMfgList) {
  2604. UINT ImageListFlags = 0;
  2605. //
  2606. // Then this is the first time we've initialized this dialog (we may
  2607. // hit this routine multiple times in the wizard case, because the user
  2608. // can go back and forth between pages).
  2609. //
  2610. lpdd->hwndMfgList = GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_MFGLIST);
  2611. //
  2612. // Don't worry--hwndDrvList will be set later in FillInDeviceList().
  2613. //
  2614. //
  2615. // Create an image list and add the signed and not signed (blank) icons
  2616. // to the list.
  2617. // Note: If the window is in right-to-left reading then we need to OR
  2618. // in the ILC_MIRROR flag so that the icons do NOT get mirrored along
  2619. // with the rest of the UI.
  2620. //
  2621. ImageListFlags = ILC_MASK;
  2622. if(GetWindowLong(hwndDlg, GWL_EXSTYLE) & WS_EX_LAYOUTRTL) {
  2623. ImageListFlags |= ILC_MIRROR;
  2624. }
  2625. lpdd->hImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON),
  2626. GetSystemMetrics(SM_CYSMICON),
  2627. ImageListFlags,
  2628. 1,
  2629. 1
  2630. );
  2631. if(lpdd->hImageList) {
  2632. ImageList_SetBkColor(lpdd->hImageList, GetSysColor(COLOR_WINDOW));
  2633. if((hIcon = LoadIcon(MyDllModuleHandle, MAKEINTRESOURCE(IDI_BLANK))) != NULL) {
  2634. ImageList_AddIcon(lpdd->hImageList, hIcon);
  2635. }
  2636. if((hIcon = LoadIcon(MyDllModuleHandle, MAKEINTRESOURCE(IDI_SIGNED))) != NULL) {
  2637. ImageList_AddIcon(lpdd->hImageList, hIcon);
  2638. }
  2639. if((hIcon = LoadIcon(MyDllModuleHandle, MAKEINTRESOURCE(IDI_CERT))) != NULL) {
  2640. ImageList_AddIcon(lpdd->hImageList, hIcon);
  2641. }
  2642. }
  2643. //
  2644. // Create the normal and bold fonts for the digital signing text.
  2645. //
  2646. lpdd->hFontNormal = lpdd->hFontBold = NULL;
  2647. if((hfont = (HFONT)SendMessage(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), WM_GETFONT, 0, 0)) != NULL) {
  2648. GetObject(hfont, sizeof(LogFont), &LogFont);
  2649. lpdd->hFontNormal = CreateFontIndirect(&LogFont);
  2650. }
  2651. if((hfont = (HFONT)SendMessage(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), WM_GETFONT, 0, 0)) != NULL) {
  2652. GetObject(hfont, sizeof(LogFont), &LogFont);
  2653. LogFont.lfWeight = FW_BOLD;
  2654. lpdd->hFontBold = CreateFontIndirect(&LogFont);
  2655. }
  2656. ListView_SetExtendedListViewStyle(lpdd->hwndMfgList, LVS_EX_LABELTIP);
  2657. //
  2658. // Insert a ListView column for each of the listboxes.
  2659. // Set the text for the Manufacturer label now since it can't be
  2660. // changed by class installers like the model label can.
  2661. //
  2662. lvcCol.mask = 0;
  2663. ListView_InsertColumn(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_DRVLIST), 0, &lvcCol);
  2664. ListView_InsertColumn(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), 0, &lvcCol);
  2665. lvcCol.mask = LVCF_FMT | LVCF_TEXT;
  2666. lvcCol.fmt = LVCFMT_LEFT;
  2667. if(!(LoadString(MyDllModuleHandle,
  2668. IDS_NDWSEL_MFGLABEL,
  2669. szBuf,
  2670. SIZECHARS(szBuf)))) {
  2671. *szBuf = TEXT('\0');
  2672. }
  2673. lvcCol.pszText = szBuf;
  2674. ListView_InsertColumn(lpdd->hwndMfgList, 0, &lvcCol);
  2675. }
  2676. if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
  2677. //
  2678. // should never hit this code path
  2679. //
  2680. MYASSERT(pDeviceInfoSet);
  2681. return FALSE;
  2682. }
  2683. try {
  2684. if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
  2685. DevInfoElem = lpdd->DevInfoElem;
  2686. } else {
  2687. DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
  2688. }
  2689. if(DevInfoElem) {
  2690. dipb = &(DevInfoElem->InstallParamBlock);
  2691. ClassGuid = &(DevInfoElem->ClassGuid);
  2692. //
  2693. // Fill in a SP_DEVINFO_DATA structure for a later call to
  2694. // SetupDiBuildDriverInfoList.
  2695. //
  2696. DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  2697. DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
  2698. DevInfoElem,
  2699. &DevInfoData
  2700. );
  2701. //
  2702. // Set flags indicating which driver lists already exist.
  2703. //
  2704. if(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDCOMPATINFO) {
  2705. lpdd->bKeeplpCompatDrvList = TRUE;
  2706. }
  2707. if(DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDINFOLIST) {
  2708. lpdd->bKeeplpClassDrvList = TRUE;
  2709. }
  2710. if(DevInfoElem->SelectedDriver) {
  2711. lpdd->bKeeplpSelectedDrv = TRUE;
  2712. }
  2713. //
  2714. // We want to start out with the compatible driver list.
  2715. //
  2716. DriverType = SPDIT_COMPATDRIVER;
  2717. } else {
  2718. dipb = &(pDeviceInfoSet->InstallParamBlock);
  2719. if(pDeviceInfoSet->HasClassGuid) {
  2720. ClassGuid = &(pDeviceInfoSet->ClassGuid);
  2721. } else {
  2722. ClassGuid = &GUID_DEVCLASS_UNKNOWN;
  2723. }
  2724. if(pDeviceInfoSet->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDINFOLIST) {
  2725. lpdd->bKeeplpClassDrvList = TRUE;
  2726. }
  2727. if(pDeviceInfoSet->SelectedClassDriver) {
  2728. lpdd->bKeeplpSelectedDrv = TRUE;
  2729. }
  2730. }
  2731. //
  2732. // Get/set class icon
  2733. //
  2734. if(IsEqualGUID(ClassGuid, &GUID_NULL)) {
  2735. if(!SetupDiLoadClassIcon(&GUID_DEVCLASS_UNKNOWN, &hIcon, &(lpdd->iBitmap))) {
  2736. hIcon = NULL;
  2737. }
  2738. } else {
  2739. if(!SetupDiLoadClassIcon(ClassGuid, &hIcon, &(lpdd->iBitmap))) {
  2740. hIcon = NULL;
  2741. }
  2742. }
  2743. if(hIcon) {
  2744. SendDlgItemMessage(hwndDlg, IDC_CLASSICON, STM_SETICON, (WPARAM)hIcon, 0L);
  2745. }
  2746. //
  2747. // If we are supposed to override the instructions and title with the
  2748. // class installer-provided strings, do it now.
  2749. //
  2750. if(USE_CI_SELSTRINGS(dipb)) {
  2751. if(lpdd->flags & DD_FLAG_IS_DIALOGBOX) {
  2752. SetWindowText(hwndDlg, GET_CI_SELSTRINGS(dipb, Title));
  2753. } else {
  2754. //
  2755. // Set wizard title and subtitle
  2756. //
  2757. PropSheet_SetHeaderTitle(GetParent(hwndDlg),
  2758. PropSheet_HwndToIndex(GetParent(hwndDlg), hwndDlg),
  2759. GET_CI_SELSTRINGS(dipb, Title));
  2760. PropSheet_SetHeaderSubTitle(GetParent(hwndDlg),
  2761. PropSheet_HwndToIndex(GetParent(hwndDlg), hwndDlg),
  2762. GET_CI_SELSTRINGS(dipb, SubTitle));
  2763. }
  2764. SetDlgItemText(hwndDlg, IDC_NDW_TEXT, GET_CI_SELSTRINGS(dipb, Instructions));
  2765. }
  2766. //
  2767. // If we should not allow OEM driver, then hide the HAVE disk button.
  2768. //
  2769. if(!(dipb->Flags & DI_SHOWOEM)) {
  2770. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_HAVEDISK), SW_HIDE);
  2771. }
  2772. //
  2773. // Hide the Windows Update button if we should not search the web.
  2774. //
  2775. if((!(dipb->FlagsEx & DI_FLAGSEX_SHOWWINDOWSUPDATE)) ||
  2776. !CDMIsInternetAvailable()) {
  2777. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_WINDOWSUPDATE), SW_HIDE);
  2778. }
  2779. if(dipb->FlagsEx & DI_FLAGSEX_FILTERSIMILARDRIVERS) {
  2780. lpdd->flags |= DD_FLAG_SHOWSIMILARDRIVERS;
  2781. }
  2782. //
  2783. // In order to decrease the amount of time the user must wait before
  2784. // they're able to work with the Select Device dialog, we have adopted
  2785. // a 'hybrid' multi-threaded approach. As soon as we get the first
  2786. // displayable list built, then we will return, and build the other
  2787. // list (if necessary) in another thread.
  2788. //
  2789. // We do it this way because it's easier, it maintains the existing
  2790. // external behavior, and because it's easier.
  2791. //
  2792. hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); // Potentially slow operations ahead!
  2793. if(DriverType == SPDIT_COMPATDRIVER) {
  2794. //
  2795. // OR in the DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS flag so that we
  2796. // don't include old internet drivers in the list that we get back.
  2797. //
  2798. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  2799. if(SetupDiGetDeviceInstallParams(lpdd->DevInfoSet,
  2800. &DevInfoData,
  2801. &DeviceInstallParams)) {
  2802. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS;
  2803. SetupDiSetDeviceInstallParams(lpdd->DevInfoSet,
  2804. &DevInfoData,
  2805. &DeviceInstallParams
  2806. );
  2807. }
  2808. SetupDiBuildDriverInfoList(lpdd->DevInfoSet,
  2809. &DevInfoData,
  2810. SPDIT_COMPATDRIVER
  2811. );
  2812. //
  2813. // Verify that there are some devices in the list to show.
  2814. //
  2815. if(bNoDevsToShow(DevInfoElem)) {
  2816. if(!lpdd->bKeeplpCompatDrvList) {
  2817. SetupDiDestroyDriverInfoList(lpdd->DevInfoSet, &DevInfoData, SPDIT_COMPATDRIVER);
  2818. }
  2819. DriverType = SPDIT_CLASSDRIVER;
  2820. } else if(!lpdd->bKeeplpClassDrvList) {
  2821. //
  2822. // We have a list to get our UI up and running, but we don't
  2823. // have a class driver list yet. Set a flag that causes us to
  2824. // spawn a thread for this later.
  2825. //
  2826. SpawnClassDriverSearch = TRUE;
  2827. }
  2828. }
  2829. if(DriverType == SPDIT_CLASSDRIVER) {
  2830. //
  2831. // We couldn't find any compatible drivers, so we fall back on the
  2832. // class driver list. In this case we have to have this list
  2833. // before continuing. In the future, maybe we'll get fancier and
  2834. // do this in a separate thread, but for now, we just make the user
  2835. // wait.
  2836. //
  2837. //
  2838. // OR in the DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS flag so that we
  2839. // don't include old internet drivers in the list that we get back.
  2840. //
  2841. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  2842. if(SetupDiGetDeviceInstallParams(lpdd->DevInfoSet,
  2843. DevInfoElem ? &DevInfoData : NULL,
  2844. &DeviceInstallParams)) {
  2845. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS;
  2846. SetupDiSetDeviceInstallParams(lpdd->DevInfoSet,
  2847. DevInfoElem ? &DevInfoData : NULL,
  2848. &DeviceInstallParams
  2849. );
  2850. }
  2851. SetupDiBuildDriverInfoList(lpdd->DevInfoSet,
  2852. DevInfoElem ? &DevInfoData : NULL,
  2853. SPDIT_CLASSDRIVER
  2854. );
  2855. }
  2856. SetCursor(LoadCursor(NULL, IDC_ARROW)); // Done with slow operations.
  2857. if(DriverType == SPDIT_COMPATDRIVER) {
  2858. //
  2859. // Since we ran this through bNoDevsToShow() above, and it
  2860. // succeeded, we know there's at least one driver in the compatible
  2861. // driver list.
  2862. //
  2863. lpdd->bShowCompat = TRUE;
  2864. CheckDlgButton(hwndDlg,
  2865. IDC_NDW_PICKDEV_COMPAT,
  2866. BST_CHECKED
  2867. );
  2868. } else {
  2869. //
  2870. // There is no compatible list, so hide the radio buttons.
  2871. //
  2872. lpdd->bShowCompat = FALSE;
  2873. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), SW_HIDE);
  2874. }
  2875. //
  2876. // Initial current description. This will be used to set
  2877. // the Default ListView selection.
  2878. //
  2879. if(lpdd->iCurDesc == -1) {
  2880. //
  2881. // If we already have a selected driver for the devinfo set or
  2882. // element, then we'll use that, otherwise, we'll use the devinfo
  2883. // element's description (if applicable).
  2884. //
  2885. if(DevInfoElem) {
  2886. if(DevInfoElem->SelectedDriver) {
  2887. lpdd->iCurDesc = DevInfoElem->SelectedDriver->DevDescription;
  2888. } else {
  2889. TCHAR TempString[LINE_LEN];
  2890. ULONG TempStringSize;
  2891. //
  2892. // Use the caller-supplied device description, if there is
  2893. // one. If not, then see if we can retrieve the DeviceDesc
  2894. // registry property.
  2895. //
  2896. TempStringSize = sizeof(TempString);
  2897. if((DevInfoElem->DeviceDescription == -1) &&
  2898. (CM_Get_DevInst_Registry_Property(DevInfoElem->DevInst,
  2899. CM_DRP_DEVICEDESC,
  2900. NULL,
  2901. TempString,
  2902. &TempStringSize,
  2903. 0) == CR_SUCCESS)) {
  2904. //
  2905. // We were able to retrieve a device description. Now
  2906. // store it (case-insensitive only) in the devinfo
  2907. // element.
  2908. //
  2909. DevInfoElem->DeviceDescription = pStringTableAddString(
  2910. pDeviceInfoSet->StringTable,
  2911. TempString,
  2912. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  2913. NULL,0
  2914. );
  2915. }
  2916. lpdd->iCurDesc = DevInfoElem->DeviceDescription;
  2917. }
  2918. } else {
  2919. if(pDeviceInfoSet->SelectedClassDriver) {
  2920. lpdd->iCurDesc = pDeviceInfoSet->SelectedClassDriver->DevDescription;
  2921. }
  2922. }
  2923. }
  2924. Err = FillInDeviceList(hwndDlg, lpdd);
  2925. if(lpdd->flags & DD_FLAG_IS_DIALOGBOX) {
  2926. HWND hLineWnd;
  2927. RECT Rect;
  2928. //
  2929. // If FillInDeviceList() fails during init time, don't even bring
  2930. // up the dialog.
  2931. //
  2932. if(Err != NO_ERROR) {
  2933. EndDialog(hwndDlg, Err);
  2934. leave;
  2935. }
  2936. //
  2937. // Set the initial focus on the OK button.
  2938. //
  2939. SetFocus(GetDlgItem(hwndDlg, IDOK));
  2940. //
  2941. // Use the fancy etched frame style for the separator bar in the
  2942. // dialog.
  2943. //
  2944. hLineWnd = GetDlgItem(hwndDlg, IDD_DEVINSLINE);
  2945. SetWindowLong(hLineWnd,
  2946. GWL_EXSTYLE,
  2947. (GetWindowLong(hLineWnd, GWL_EXSTYLE) | WS_EX_STATICEDGE)
  2948. );
  2949. GetClientRect(hLineWnd, &Rect);
  2950. SetWindowPos(hLineWnd,
  2951. HWND_TOP,
  2952. 0,
  2953. 0,
  2954. Rect.right,
  2955. GetSystemMetrics(SM_CYEDGE),
  2956. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED
  2957. );
  2958. }
  2959. //
  2960. // If DriverType is SPDIT_CLASSDRIVER and ListView_GetItemCount returns
  2961. // 0 then we don't have any items to show at all. This will only happen
  2962. // when we search the default Windows INF directory and we do not have
  2963. // any INFs for a device.
  2964. //
  2965. if((DriverType == SPDIT_CLASSDRIVER) &&
  2966. (0 == ListView_GetItemCount(lpdd->hwndDrvList))) {
  2967. TCHAR TempString[LINE_LEN];
  2968. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_ONEMFG_DRVLIST), SW_HIDE);
  2969. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_MFGLIST), SW_HIDE);
  2970. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_DRVLIST), SW_HIDE);
  2971. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_ICON), SW_HIDE);
  2972. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), SW_HIDE);
  2973. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_LINK), SW_HIDE);
  2974. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_STATUS_TEXT), SW_SHOW);
  2975. if(!LoadString(MyDllModuleHandle, IDS_NDW_NO_DRIVERS, TempString, SIZECHARS(TempString))) {
  2976. *TempString = TEXT('\0');
  2977. }
  2978. SetDlgItemText(hwndDlg, IDC_NDW_STATUS_TEXT, TempString);
  2979. if(lpdd->flags & DD_FLAG_IS_DIALOGBOX) {
  2980. EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
  2981. } else {
  2982. if(((ndwData->InstallData).Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) &&
  2983. ((ndwData->InstallData).Flags & NDW_INSTALLFLAG_EXPRESSINTRO) &&
  2984. !((ndwData->InstallData).DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
  2985. //
  2986. // No back if we skipped the Class list, and are in express
  2987. // mode
  2988. //
  2989. PropSheet_SetWizButtons(GetParent(hwndDlg), 0);
  2990. } else {
  2991. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK);
  2992. }
  2993. }
  2994. bRet = FALSE;
  2995. }
  2996. } except(pSetupExceptionFilter(GetExceptionCode())) {
  2997. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  2998. bRet = FALSE;
  2999. SpawnClassDriverSearch = FALSE;
  3000. //
  3001. // If we're doing the dialog box version, then an exception should
  3002. // cause us to terminate the dialog and return an error.
  3003. //
  3004. if(lpdd->flags & DD_FLAG_IS_DIALOGBOX) {
  3005. EndDialog(hwndDlg, ERROR_INVALID_DATA);
  3006. }
  3007. }
  3008. UnlockDeviceInfoSet(pDeviceInfoSet);
  3009. if(SpawnClassDriverSearch) {
  3010. //
  3011. // Allocate a context structure to pass to the auxilliary thread (the
  3012. // auxilliary thread will take care of freeing the memory).
  3013. //
  3014. if(!(ClassDrvThreadContext = MyMalloc(sizeof(CLASSDRV_THREAD_CONTEXT)))) {
  3015. if(lpdd->flags & DD_FLAG_IS_DIALOGBOX) {
  3016. EndDialog(hwndDlg, ERROR_NOT_ENOUGH_MEMORY);
  3017. }
  3018. } else {
  3019. try {
  3020. //
  3021. // Fill in the context structure, and fire off the thread.
  3022. // NOTE: The DevInfoData struct has to have been filled in above
  3023. // for us to have gotten to this point.
  3024. //
  3025. ClassDrvThreadContext->DeviceInfoSet = lpdd->DevInfoSet;
  3026. CopyMemory(&(ClassDrvThreadContext->DeviceInfoData),
  3027. &DevInfoData,
  3028. sizeof(DevInfoData)
  3029. );
  3030. ClassDrvThreadContext->NotificationWindow = hwndDlg;
  3031. if(_beginthread(ClassDriverSearchThread, 0, ClassDrvThreadContext) == -1) {
  3032. //
  3033. // Assume out-of-memory
  3034. //
  3035. if(lpdd->flags & DD_FLAG_IS_DIALOGBOX) {
  3036. EndDialog(hwndDlg, ERROR_NOT_ENOUGH_MEMORY);
  3037. }
  3038. } else {
  3039. //
  3040. // Memory "handed off" to other thread--reset the pointer
  3041. // so we won't try to free it below...
  3042. //
  3043. ClassDrvThreadContext = NULL;
  3044. lpdd->AuxThreadRunning = TRUE;
  3045. }
  3046. } except(pSetupExceptionFilter(GetExceptionCode())) {
  3047. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  3048. }
  3049. if(ClassDrvThreadContext) {
  3050. MyFree(ClassDrvThreadContext);
  3051. }
  3052. }
  3053. }
  3054. return bRet;
  3055. }
  3056. PDRIVER_NODE
  3057. GetDriverNodeFromLParam(
  3058. IN PDEVICE_INFO_SET DeviceInfoSet,
  3059. IN PSP_DIALOGDATA lpdd,
  3060. IN LPARAM lParam
  3061. )
  3062. /*++
  3063. Routine Description:
  3064. This routine interprets lParam as a pointer to a driver node, and tries to
  3065. find the node in the class driver list for either the selected devinfo
  3066. element, or the set itself. If the lpdd flags field has the
  3067. DD_FLAG_USE_DEVINFO_ELEM bit set, then the lpdd's DevInfoElem will be used
  3068. instead of the currently selected device.
  3069. Arguments:
  3070. DeviceInfoSet - Supplies the address of the device information set
  3071. structure to search for the driver node in.
  3072. lpdd - Supplies the address of a dialog data structure that specifies
  3073. whether the wizard has an explicit association to the global class
  3074. driver list or to a particular device information element, and if so,
  3075. what it's associated with.
  3076. lParam - Supplies a value which may be the address of a driver node. The
  3077. appropriate linked list of driver nodes is searched to see if one of
  3078. them has this value as its address, and if so, a pointer to that driver
  3079. node is returned.
  3080. Return Value:
  3081. If success, the return value is the address of the matching driver node,
  3082. otherwise, it is NULL.
  3083. --*/
  3084. {
  3085. PDRIVER_NODE CurDriverNode;
  3086. PDEVINFO_ELEM DevInfoElem;
  3087. if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
  3088. DevInfoElem = lpdd->DevInfoElem;
  3089. } else {
  3090. DevInfoElem = DeviceInfoSet->SelectedDevInfoElem;
  3091. }
  3092. if(DevInfoElem) {
  3093. CurDriverNode = (lpdd->bShowCompat) ? DevInfoElem->CompatDriverHead
  3094. : DevInfoElem->ClassDriverHead;
  3095. } else {
  3096. MYASSERT(!lpdd->bShowCompat);
  3097. CurDriverNode = DeviceInfoSet->ClassDriverHead;
  3098. }
  3099. while(CurDriverNode) {
  3100. if(CurDriverNode == (PDRIVER_NODE)lParam) {
  3101. return CurDriverNode;
  3102. } else {
  3103. CurDriverNode = CurDriverNode->Next;
  3104. }
  3105. }
  3106. return NULL;
  3107. }
  3108. BOOL
  3109. OnSetActive(
  3110. IN HWND hwndDlg,
  3111. IN OUT PNEWDEVWIZ_DATA ndwData
  3112. )
  3113. /*++
  3114. Routine Description:
  3115. This routine handles the PSN_SETACTIVE message of the select device wizard
  3116. page.
  3117. Arguments:
  3118. hwndDlg - Supplies the window handle of the wizard dialog page.
  3119. ndwData - Supplies the address of a New Device Wizard data block to be used
  3120. during the processing of this message.
  3121. Return Value:
  3122. If success, the return value is TRUE, otherwise, it is FALSE.
  3123. --*/
  3124. {
  3125. BOOL b = TRUE;
  3126. PSP_INSTALLWIZARD_DATA iwd;
  3127. PSP_DIALOGDATA lpdd;
  3128. PDEVICE_INFO_SET pDeviceInfoSet;
  3129. PDEVINFO_ELEM DevInfoElem;
  3130. PDEVINSTALL_PARAM_BLOCK dipb;
  3131. MYASSERT(ndwData);
  3132. iwd = &(ndwData->InstallData);
  3133. lpdd = &(ndwData->ddData);
  3134. MYASSERT(lpdd);
  3135. if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
  3136. //
  3137. // should never hit this code path
  3138. //
  3139. MYASSERT(pDeviceInfoSet);
  3140. return FALSE;
  3141. }
  3142. try {
  3143. //
  3144. // Make sure our "waiting for class list" static text control is
  3145. // hidden!
  3146. //
  3147. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_STATUS_TEXT), SW_HIDE);
  3148. if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
  3149. DevInfoElem = lpdd->DevInfoElem;
  3150. } else {
  3151. DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
  3152. }
  3153. if(DevInfoElem) {
  3154. dipb = &(DevInfoElem->InstallParamBlock);
  3155. } else {
  3156. dipb = &(pDeviceInfoSet->InstallParamBlock);
  3157. }
  3158. //
  3159. // Set the Button State
  3160. //
  3161. if((iwd->Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) &&
  3162. (iwd->Flags & NDW_INSTALLFLAG_EXPRESSINTRO) &&
  3163. !(iwd->DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
  3164. //
  3165. // No back if we skipped the Class list, and are in express mode
  3166. //
  3167. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT);
  3168. } else {
  3169. PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
  3170. }
  3171. //
  3172. // Set the New Class install params.
  3173. // If we are being jumped to by a dyna wiz page,
  3174. // then do not call the class installer
  3175. //
  3176. if(iwd->DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED) {
  3177. InitSelectDeviceDlg(hwndDlg, ndwData);
  3178. } else {
  3179. BOOL FlagNeedsReset = FALSE;
  3180. SP_DEVINFO_DATA DeviceInfoData;
  3181. DWORD CiErr;
  3182. PDEVINFO_ELEM CurDevInfoElem;
  3183. //
  3184. // Call the Class Installer
  3185. //
  3186. if(!(dipb->Flags & DI_NODI_DEFAULTACTION)) {
  3187. dipb->Flags |= DI_NODI_DEFAULTACTION;
  3188. FlagNeedsReset = TRUE;
  3189. }
  3190. if(DevInfoElem) {
  3191. //
  3192. // Initialize a SP_DEVINFO_DATA buffer to use as an argument to
  3193. // SetupDiCallClassInstaller.
  3194. //
  3195. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  3196. DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
  3197. DevInfoElem,
  3198. &DeviceInfoData
  3199. );
  3200. }
  3201. //
  3202. // We need to unlock the HDEVINFO before calling the class
  3203. // installer.
  3204. //
  3205. UnlockDeviceInfoSet(pDeviceInfoSet);
  3206. pDeviceInfoSet = NULL;
  3207. CiErr = _SetupDiCallClassInstaller(
  3208. DIF_SELECTDEVICE,
  3209. lpdd->DevInfoSet,
  3210. DevInfoElem ? &DeviceInfoData : NULL,
  3211. CALLCI_LOAD_HELPERS | CALLCI_CALL_HELPERS
  3212. );
  3213. //
  3214. // Re-acquire the HDEVINFO lock.
  3215. //
  3216. if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
  3217. //
  3218. // should never hit this code path
  3219. //
  3220. MYASSERT(pDeviceInfoSet);
  3221. b = FALSE;
  3222. leave;
  3223. }
  3224. if(DevInfoElem && !(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM)) {
  3225. //
  3226. // Verify that the class installer didn't do something nasty
  3227. // like delete the currently selected devinfo element!
  3228. //
  3229. for(CurDevInfoElem = pDeviceInfoSet->DeviceInfoHead;
  3230. CurDevInfoElem;
  3231. CurDevInfoElem = CurDevInfoElem->Next) {
  3232. if(CurDevInfoElem = DevInfoElem) {
  3233. break;
  3234. }
  3235. }
  3236. if(!CurDevInfoElem) {
  3237. //
  3238. // The class installer deleted the selected devinfo
  3239. // element. Get the newly-selected one, or fall back to
  3240. // the global driver list if none selected.
  3241. //
  3242. if(DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem) {
  3243. dipb = &(DevInfoElem->InstallParamBlock);
  3244. } else {
  3245. dipb = &(pDeviceInfoSet->InstallParamBlock);
  3246. }
  3247. //
  3248. // Don't need to reset the default action flag.
  3249. //
  3250. FlagNeedsReset = FALSE;
  3251. }
  3252. }
  3253. //
  3254. // Reset the DI_NODI_DEFAULTACTION flag if necessary.
  3255. //
  3256. if(FlagNeedsReset) {
  3257. dipb->Flags &= ~DI_NODI_DEFAULTACTION;
  3258. }
  3259. switch(CiErr) {
  3260. //
  3261. // Class installer did the select, so goto analyze
  3262. //
  3263. case NO_ERROR :
  3264. SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_DYNAWIZ_ANALYZEDEV_PAGE);
  3265. break;
  3266. //
  3267. // Class installer wants us to do default.
  3268. //
  3269. case ERROR_DI_DO_DEFAULT :
  3270. InitSelectDeviceDlg(hwndDlg, ndwData);
  3271. break;
  3272. default :
  3273. //
  3274. // If we are doing an OEM select, and we fail, then
  3275. // we should init after clearing the OEM stuff.
  3276. //
  3277. if(iwd->Flags & NDW_INSTALLFLAG_CI_PICKED_OEM) {
  3278. iwd->Flags &= ~NDW_INSTALLFLAG_CI_PICKED_OEM;
  3279. //
  3280. // Destroy the existing class driver list.
  3281. //
  3282. if(DevInfoElem) {
  3283. //
  3284. // Initialize a SP_DEVINFO_DATA buffer to use as an
  3285. // argument to SetupDiDestroyDriverInfoList.
  3286. //
  3287. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  3288. DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
  3289. DevInfoElem,
  3290. &DeviceInfoData
  3291. );
  3292. }
  3293. SetupDiDestroyDriverInfoList(lpdd->DevInfoSet,
  3294. DevInfoElem ? &DeviceInfoData : NULL,
  3295. SPDIT_CLASSDRIVER
  3296. );
  3297. //
  3298. // Make sure the OEM button is shown.
  3299. //
  3300. dipb->Flags |= DI_SHOWOEM;
  3301. InitSelectDeviceDlg(hwndDlg, ndwData);
  3302. } else {
  3303. SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, IDD_DYNAWIZ_SELECTCLASS_PAGE);
  3304. }
  3305. break;
  3306. }
  3307. }
  3308. } except(pSetupExceptionFilter(GetExceptionCode())) {
  3309. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  3310. b = FALSE;
  3311. }
  3312. if(pDeviceInfoSet) {
  3313. UnlockDeviceInfoSet(pDeviceInfoSet);
  3314. }
  3315. return b;
  3316. }
  3317. BOOL
  3318. pSetupIsSelectedHardwareIdValid(
  3319. IN HWND hWnd,
  3320. IN PSP_DIALOGDATA lpdd,
  3321. IN INT iCur
  3322. )
  3323. /*++
  3324. Routine Description:
  3325. This routine will check to see if the driver selected by the user is valid.
  3326. If the driver is not valid then we will prompt the user with a message box
  3327. telling them that the driver was not writen for their hardware and ask them
  3328. if they want to continue.
  3329. A compatible driver is considered valid if one of the Hardware or
  3330. Compatible IDs of the driver node matches a Hardware or Compatible ID of
  3331. the hardware. The only reason we have this check is that class-/
  3332. co-installers can do the list themselves so we just need to make sure they
  3333. didn't stick a driver node into the compatible list that is not really
  3334. compatible.
  3335. A class driver is considered valid if it has the same Name, section name,
  3336. and INF as a driver in the compatible list. Or if one of the Hardware or
  3337. Compatible IDs of the driver node matches a Hardware or Compatible ID of
  3338. the hardware.
  3339. Arguments:
  3340. hwnd - Supplies the window handle of the wizard dialog page.
  3341. ndwData - Supplies the address of a New Device Wizard data block to be used
  3342. during the processing of this message.
  3343. iCur - The index of the selected driver in the list view.
  3344. Return Value:
  3345. TRUE if the selected driver is valid, or if the selected driver is NOT
  3346. valid but the user said they still want to install it.
  3347. FALSE otherwise.
  3348. --*/
  3349. {
  3350. PDEVICE_INFO_SET pDeviceInfoSet;
  3351. PDRIVER_NODE DriverNode;
  3352. LV_ITEM lviItem;
  3353. PDEVINFO_ELEM DevInfoElem;
  3354. LPTSTR Title = NULL;
  3355. LPTSTR Message = NULL;
  3356. UINT MessageLen;
  3357. BOOL bRet = FALSE;
  3358. LPTSTR IDBuffer = NULL;
  3359. ULONG IDBufferLen;
  3360. PTSTR pID, SelectedDriverHardwareId, SelectedDriverCompatibleId;
  3361. DWORD i, j;
  3362. int FailCount = 0;
  3363. PTSTR StringBuffers = NULL;
  3364. //
  3365. // If the DD_FLAG_USE_DEVINFO_ELEM flag is not set then we don't have a
  3366. // DevNode to validate the choosen ID against...so just return TRUE.
  3367. //
  3368. MYASSERT(lpdd);
  3369. if(!(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM)) {
  3370. return TRUE;
  3371. }
  3372. if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
  3373. //
  3374. // should never hit this code path
  3375. //
  3376. MYASSERT(pDeviceInfoSet);
  3377. return FALSE;
  3378. }
  3379. try {
  3380. //
  3381. // Figure out which device we're working with (there'd better be _some_
  3382. // device--it doesn't make sense to ask about compatibility otherwise!
  3383. //
  3384. if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
  3385. DevInfoElem = lpdd->DevInfoElem;
  3386. } else {
  3387. DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
  3388. }
  3389. MYASSERT(DevInfoElem);
  3390. if(!DevInfoElem) {
  3391. //
  3392. // Return true, since this is analogous to the case where the
  3393. // device has no hardware or compatible IDs.
  3394. //
  3395. bRet = TRUE;
  3396. leave;
  3397. }
  3398. //
  3399. // We won't verify the selected driver for certain classes of devices.
  3400. // This is usually because the device is not very Plug and Play and so
  3401. // we can't tell what is a valid driver and what isn't a valid driver.
  3402. // Currently the list of classes that we don't verify are:
  3403. //
  3404. // Monitor
  3405. //
  3406. if(IsEqualGUID(&GUID_DEVCLASS_MONITOR, &(DevInfoElem->ClassGuid))) {
  3407. bRet = TRUE;
  3408. leave;
  3409. }
  3410. lviItem.mask = LVIF_PARAM;
  3411. lviItem.iItem = iCur;
  3412. lviItem.iSubItem = 0;
  3413. if(ListView_GetItem(lpdd->hwndDrvList, &lviItem)) {
  3414. DriverNode = GetDriverNodeFromLParam(pDeviceInfoSet, lpdd, lviItem.lParam);
  3415. } else {
  3416. DriverNode = NULL;
  3417. }
  3418. if(!DriverNode) {
  3419. MYASSERT(FALSE); // this should never happen.
  3420. leave;
  3421. }
  3422. //
  3423. // allocate memory required for various strings to reduce stack usage
  3424. //
  3425. StringBuffers = MyMalloc(sizeof(TCHAR)*(LINE_LEN+SDT_MAX_TEXT+REGSTR_VAL_MAX_HCID_LEN));
  3426. if(StringBuffers) {
  3427. Title = StringBuffers; // [LINE_LEN]
  3428. Message = Title+LINE_LEN; // [SDT_MAX_TEXT]
  3429. IDBuffer = Message+SDT_MAX_TEXT; // [REGSTR_VAL_MAX_HCID_LEN]
  3430. } else {
  3431. leave; // out-of-memory, gotta bail!
  3432. }
  3433. //
  3434. // Retrieve the HardwareId for the selected driver.
  3435. //
  3436. SelectedDriverHardwareId = pStringTableStringFromId(
  3437. pDeviceInfoSet->StringTable,
  3438. DriverNode->HardwareId
  3439. );
  3440. for(i=0; i<2; i++) {
  3441. IDBufferLen = REGSTR_VAL_MAX_HCID_LEN;
  3442. if(CR_SUCCESS == CM_Get_DevInst_Registry_Property_Ex(
  3443. DevInfoElem->DevInst,
  3444. (i ? CM_DRP_COMPATIBLEIDS
  3445. : CM_DRP_HARDWAREID),
  3446. NULL,
  3447. IDBuffer,
  3448. &IDBufferLen,
  3449. 0,
  3450. pDeviceInfoSet->hMachine)) {
  3451. //
  3452. // See if the HardwareID for the selected driver matches
  3453. // any of the Hardware or Compatible IDs for the actual
  3454. // hardware.
  3455. //
  3456. for(pID = IDBuffer; *pID; pID += (lstrlen(pID) + 1)) {
  3457. if(!lstrcmpi(SelectedDriverHardwareId, pID)) {
  3458. bRet = TRUE;
  3459. leave;
  3460. }
  3461. }
  3462. //
  3463. // See if any of the Compatible IDs for the selected driver
  3464. // match any of the Hardware or Compatible IDs for the
  3465. // actual hardware
  3466. //
  3467. for(j=0; j < DriverNode->NumCompatIds; j++) {
  3468. SelectedDriverCompatibleId = pStringTableStringFromId(
  3469. pDeviceInfoSet->StringTable,
  3470. DriverNode->CompatIdList[j]
  3471. );
  3472. for(pID = IDBuffer; *pID; pID += (lstrlen(pID) + 1)) {
  3473. if(!lstrcmpi(SelectedDriverCompatibleId, pID)) {
  3474. bRet = TRUE;
  3475. leave;
  3476. }
  3477. }
  3478. }
  3479. } else {
  3480. FailCount++;
  3481. }
  3482. }
  3483. //
  3484. // If FailCount is 2 then CM_Get_DevInst_Registry_Property_Ex
  3485. // failed for both CM_DRP_HARDWAREID and CM_DRP_COMPATIBLEIDS.
  3486. // Since this DevNode does not have any Hardware or Compatible IDs
  3487. // we will let the user install any driver they want on this
  3488. // device. This usually happens only with manually installed
  3489. // devices.
  3490. //
  3491. if(FailCount == 2) {
  3492. bRet = TRUE;
  3493. leave;
  3494. }
  3495. //
  3496. // At this point none of the Hardware or Compatible Ids of the
  3497. // selected driver node match any of the Hardware or Compatible Ids
  3498. // of the actual hardware. We will do one last check here if this
  3499. // is a class driver. We will see if this class driver node has
  3500. // the same description, install section, and INF as a driver in
  3501. // the compatible list. The reason for this is that we don't
  3502. // handle duplicate descriptions well for class drivers since we
  3503. // don't compute their Rank. This means that if two driver nodes
  3504. // exist in an INF with the same description we might not have the
  3505. // correct matching one in the class list.
  3506. //
  3507. if(!lpdd->bShowCompat) {
  3508. PDRIVER_NODE CurDriverNode = NULL;
  3509. //
  3510. // Enumerate through all of the compatible driver nodes
  3511. //
  3512. for(CurDriverNode = DevInfoElem->CompatDriverHead;
  3513. CurDriverNode;
  3514. CurDriverNode = CurDriverNode->Next) {
  3515. if((CurDriverNode->InfFileName == DriverNode->InfFileName) &&
  3516. (CurDriverNode->InfSectionName == DriverNode->InfSectionName) &&
  3517. (CurDriverNode->DrvDescription == DriverNode->DrvDescription)) {
  3518. //
  3519. // We found a node that matches ours in the
  3520. // compatible driver list so that means that this
  3521. // class driver node is good.
  3522. //
  3523. bRet = TRUE;
  3524. leave;
  3525. }
  3526. }
  3527. }
  3528. //
  3529. // The ID of the driver that the user selected does not match any
  3530. // of the Hardware or Compatible IDs of this device. Warn the user
  3531. // that this is a bad thing and see if they want to continue.
  3532. //
  3533. if(!LoadString(MyDllModuleHandle, IDS_DRIVER_UPDATE_TITLE, Title, LINE_LEN)) {
  3534. *Title = TEXT('\0');
  3535. }
  3536. MessageLen = LoadString(MyDllModuleHandle, IDS_DRIVER_NOMATCH1, Message, SDT_MAX_TEXT);
  3537. MessageLen += LoadString(MyDllModuleHandle, IDS_DRIVER_NOMATCH2, Message + MessageLen, SDT_MAX_TEXT - MessageLen);
  3538. MessageLen += LoadString(MyDllModuleHandle, IDS_DRIVER_NOMATCH3, Message + MessageLen, SDT_MAX_TEXT - MessageLen);
  3539. if(MessageLen) {
  3540. if(IDYES == MessageBox(hWnd,
  3541. Message,
  3542. Title,
  3543. MB_YESNO
  3544. | MB_TASKMODAL
  3545. | MB_ICONEXCLAMATION
  3546. | MB_DEFBUTTON2)) {
  3547. bRet = TRUE;
  3548. leave;
  3549. }
  3550. }
  3551. } except(pSetupExceptionFilter(GetExceptionCode())) {
  3552. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  3553. }
  3554. UnlockDeviceInfoSet(pDeviceInfoSet);
  3555. if(StringBuffers) {
  3556. MyFree(StringBuffers);
  3557. }
  3558. return bRet;
  3559. }
  3560. VOID
  3561. SetSelectedDriverNode(
  3562. IN PSP_DIALOGDATA lpdd,
  3563. IN INT iCur
  3564. )
  3565. /*++
  3566. Routine Description:
  3567. This routine sets the selected driver for the currently selected device (or
  3568. global class driver list if no device selected) in the device information
  3569. set referenced in the SP_DIALOGDATA structure. If the
  3570. DD_FLAG_USE_DEVINFO_ELEM flag in the structure is set, then the driver is
  3571. selected for the set or element based on the DevInfoElem pointer instead of
  3572. the currently selected one.
  3573. Arguments:
  3574. lpdd - Supplies the address of a dialog data structure that contains
  3575. information about the device information set being used.
  3576. iCur - Supplies the index within the driver listbox window containing the
  3577. driver to be selected.
  3578. Return Value:
  3579. None.
  3580. --*/
  3581. {
  3582. PDEVICE_INFO_SET pDeviceInfoSet;
  3583. PDRIVER_NODE DriverNode;
  3584. LV_ITEM lviItem;
  3585. PDEVINFO_ELEM DevInfoElem;
  3586. TCHAR ClassGuidString[GUID_STRING_LEN];
  3587. SP_DEVINFO_DATA DevInfoData;
  3588. MYASSERT(lpdd);
  3589. if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
  3590. //
  3591. // should never hit this code path
  3592. //
  3593. MYASSERT(pDeviceInfoSet);
  3594. return;
  3595. }
  3596. try {
  3597. lviItem.mask = LVIF_PARAM;
  3598. lviItem.iItem = iCur;
  3599. lviItem.iSubItem = 0;
  3600. if(ListView_GetItem(lpdd->hwndDrvList, &lviItem)) {
  3601. DriverNode = GetDriverNodeFromLParam(pDeviceInfoSet, lpdd, lviItem.lParam);
  3602. } else {
  3603. DriverNode = NULL;
  3604. }
  3605. if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
  3606. DevInfoElem = lpdd->DevInfoElem;
  3607. } else {
  3608. DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
  3609. }
  3610. if(DevInfoElem) {
  3611. //
  3612. // If a driver node is being selected, update the device's class to
  3613. // ensure it matches the class of the INF containing the selected
  3614. // driver node.
  3615. //
  3616. if(DriverNode) {
  3617. //
  3618. // Get the INF class GUID for this driver node in string form,
  3619. // because this property is stored as a REG_SZ.
  3620. //
  3621. pSetupStringFromGuid(&(pDeviceInfoSet->GuidTable[DriverNode->GuidIndex]),
  3622. ClassGuidString,
  3623. SIZECHARS(ClassGuidString)
  3624. );
  3625. //
  3626. // Fill in a SP_DEVINFO_DATA structure for the upcoming call to
  3627. // SetupDiSetDeviceRegistryProperty.
  3628. //
  3629. DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  3630. DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
  3631. DevInfoElem,
  3632. &DevInfoData
  3633. );
  3634. if(!SetupDiSetDeviceRegistryProperty(lpdd->DevInfoSet,
  3635. &DevInfoData,
  3636. SPDRP_CLASSGUID,
  3637. (PBYTE)ClassGuidString,
  3638. sizeof(ClassGuidString))) {
  3639. //
  3640. // The class cannot be updated--don't change the selected
  3641. // driver.
  3642. //
  3643. leave;
  3644. }
  3645. }
  3646. DevInfoElem->SelectedDriver = DriverNode;
  3647. if(DriverNode) {
  3648. DevInfoElem->SelectedDriverType = (lpdd->bShowCompat)
  3649. ? SPDIT_COMPATDRIVER
  3650. : SPDIT_CLASSDRIVER;
  3651. } else {
  3652. DevInfoElem->SelectedDriverType = SPDIT_NODRIVER;
  3653. }
  3654. } else {
  3655. pDeviceInfoSet->SelectedClassDriver = DriverNode;
  3656. }
  3657. } except(pSetupExceptionFilter(GetExceptionCode())) {
  3658. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  3659. }
  3660. UnlockDeviceInfoSet(pDeviceInfoSet);
  3661. }
  3662. DWORD
  3663. HandleSelectOEM(
  3664. IN HWND hwndDlg,
  3665. IN OUT PNEWDEVWIZ_DATA ndwData
  3666. )
  3667. /*++
  3668. Routine Description:
  3669. This routine selects a new device based on a user-supplied path. Calling
  3670. this routine may cause a driver list to get built, which is a potentially
  3671. slow operation.
  3672. Arguments:
  3673. hwndDlg - Supplies the window handle of the select device wizard page.
  3674. ndwData - Supplies the address of a New Device Wizard data block to be used
  3675. during the processing of this message.
  3676. Return Value:
  3677. If successful, the return value is NO_ERROR, otherwise, it is a Win32 error
  3678. code indicating the cause of failure.
  3679. --*/
  3680. {
  3681. PSP_DIALOGDATA lpdd;
  3682. PDEVICE_INFO_SET pDeviceInfoSet;
  3683. PDEVINFO_ELEM DevInfoElem;
  3684. SP_DEVINFO_DATA DevInfoData;
  3685. DWORD Err;
  3686. MYASSERT(ndwData);
  3687. lpdd = &(ndwData->ddData);
  3688. MYASSERT(lpdd);
  3689. if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
  3690. //
  3691. // should never hit this code path
  3692. //
  3693. MYASSERT(pDeviceInfoSet);
  3694. return ERROR_INVALID_HANDLE;
  3695. }
  3696. try {
  3697. if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
  3698. DevInfoElem = lpdd->DevInfoElem;
  3699. } else {
  3700. DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
  3701. }
  3702. //
  3703. // If this is for a particular device, then initialize a device
  3704. // information structure to use for SelectOEMDriver.
  3705. //
  3706. if(DevInfoElem) {
  3707. DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  3708. DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
  3709. DevInfoElem,
  3710. &DevInfoData
  3711. );
  3712. }
  3713. //
  3714. // Unlock the device information set before popping up the OEM driver
  3715. // selection UI. Otherwise, our multi-threaded dialog will deadlock.
  3716. //
  3717. UnlockDeviceInfoSet(pDeviceInfoSet);
  3718. pDeviceInfoSet = NULL;
  3719. if((Err = SelectOEMDriver(hwndDlg,
  3720. lpdd->DevInfoSet,
  3721. DevInfoElem ? &DevInfoData : NULL,
  3722. !(lpdd->flags & DD_FLAG_IS_DIALOGBOX)
  3723. )) == ERROR_DI_DO_DEFAULT) {
  3724. if(DevInfoElem && DevInfoElem->CompatDriverHead) {
  3725. lpdd->bShowCompat = TRUE;
  3726. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), SW_SHOW);
  3727. } else {
  3728. lpdd->bShowCompat = FALSE;
  3729. //
  3730. // Since we don't have any compatible drivers to show, we will
  3731. // hide the show compatible and show class selection buttons.
  3732. //
  3733. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), SW_HIDE);
  3734. }
  3735. CheckDlgButton(hwndDlg,
  3736. IDC_NDW_PICKDEV_COMPAT,
  3737. lpdd->bShowCompat ? BST_CHECKED : BST_UNCHECKED
  3738. );
  3739. //
  3740. // Enable the UI. We turned it off when the user pressed the Have
  3741. // Disk... button
  3742. //
  3743. ToggleDialogControls(hwndDlg, ndwData, TRUE);
  3744. //
  3745. // Fill in the list to select from
  3746. //
  3747. FillInDeviceList(hwndDlg, lpdd);
  3748. }
  3749. } except(pSetupExceptionFilter(GetExceptionCode())) {
  3750. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  3751. }
  3752. if(pDeviceInfoSet) {
  3753. UnlockDeviceInfoSet(pDeviceInfoSet);
  3754. }
  3755. return Err;
  3756. }
  3757. DWORD
  3758. SelectWindowsUpdateDriver(
  3759. IN HWND hwndParent, OPTIONAL
  3760. IN HDEVINFO DeviceInfoSet,
  3761. IN OUT PSP_DEVINFO_DATA DeviceInfoData, OPTIONAL
  3762. IN PTSTR CDMPath,
  3763. IN BOOL IsWizard
  3764. )
  3765. /*++
  3766. Routine Description:
  3767. This is the worker routine that actually allows for the selection of a
  3768. Windows Update driver.
  3769. Arguments:
  3770. hwndParent - Optionally, supplies the window handle that is to be the
  3771. parent for any selection UI. If this parameter is not supplied, then
  3772. the hwndParent field of the devinfo set or element will be used.
  3773. DeviceInfoSet - Supplies the handle of the device info set for which a
  3774. Windows Update driver selection is to be performed.
  3775. DeviceInfoData - Optionally, supplies the address of the device information
  3776. element to select a driver for. If this parameter is not supplied,
  3777. then a Windows Update driver for the global class driver list will be
  3778. selected.
  3779. If a compatible driver was found for this device, the device
  3780. information element will have its class GUID updated upon return to
  3781. reflect the device's new class.
  3782. CDMPath - Supplies the directory path where Windows Update downloaded the
  3783. driver package(s) to.
  3784. IsWizard - Specifies whether this routine is being called in the context of
  3785. a select device wizard page.
  3786. Return Value:
  3787. If successful, the return value is NO_ERROR, otherwise, it is a Win32 error
  3788. code indicating the cause of failure.
  3789. --*/
  3790. {
  3791. PDEVICE_INFO_SET pDeviceInfoSet;
  3792. PDEVINFO_ELEM DevInfoElem = NULL;
  3793. PDEVINSTALL_PARAM_BLOCK dipb;
  3794. DWORD Err = NO_ERROR;
  3795. HWND hwndSave;
  3796. LONG DriverPathSave;
  3797. DWORD DriverPathFlagsSave;
  3798. BOOL bRestoreHwnd = FALSE, bRestoreDriverPath = FALSE;
  3799. UINT NewClassDriverCount;
  3800. TCHAR Title[MAX_TITLE_LEN];
  3801. HCURSOR hOldCursor;
  3802. BOOL bDoneWithDrvSearch = TRUE;
  3803. PDRIVER_NODE lpOrgCompat;
  3804. PDRIVER_NODE lpOrgCompatTail;
  3805. UINT OrgCompatCount;
  3806. PDRIVER_NODE lpOrgClass;
  3807. PDRIVER_NODE lpOrgClassTail;
  3808. UINT OrgClassCount;
  3809. PDRIVER_NODE lpOrgSel;
  3810. PDRIVER_NODE CurDriverNode;
  3811. PDRIVER_NODE DriverNodeHead = NULL;
  3812. DWORD dwOrgSelType;
  3813. DWORD dwOrgFlags;
  3814. DWORD dwOrgFlagsEx;
  3815. BOOL bRestoreDeviceInfo = FALSE;
  3816. LONG DriverPathId;
  3817. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  3818. //
  3819. // should never hit this code path
  3820. //
  3821. MYASSERT(pDeviceInfoSet);
  3822. return ERROR_INVALID_HANDLE;
  3823. }
  3824. try {
  3825. if(DeviceInfoData) {
  3826. //
  3827. // Then we're working with a particular device.
  3828. //
  3829. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  3830. DeviceInfoData,
  3831. NULL))) {
  3832. Err = ERROR_INVALID_PARAMETER;
  3833. leave;
  3834. }
  3835. dipb = &(DevInfoElem->InstallParamBlock);
  3836. } else {
  3837. dipb = &(pDeviceInfoSet->InstallParamBlock);
  3838. }
  3839. //
  3840. // Make this selection window the parent window for Windows Update UI
  3841. //
  3842. if(hwndParent) {
  3843. hwndSave = dipb->hwndParent;
  3844. dipb->hwndParent = hwndParent;
  3845. bRestoreHwnd = TRUE;
  3846. }
  3847. //
  3848. // Don't assume there is no old path. Save old one and pretend there
  3849. // is no old one in case of cancel.
  3850. //
  3851. DriverPathSave = dipb->DriverPath;
  3852. dipb->DriverPath = -1;
  3853. //
  3854. // Clear the DI_ENUMSINGLEINF flag, because we're going to be getting
  3855. // a path to a directory, _not_ to an individual INF
  3856. //
  3857. DriverPathFlagsSave = dipb->Flags & DI_ENUMSINGLEINF;
  3858. dipb->Flags &= ~DI_ENUMSINGLEINF;
  3859. bRestoreDriverPath = TRUE;
  3860. //
  3861. // Set the DriverPath to the path returned by CDM
  3862. //
  3863. if((DriverPathId = pStringTableAddString(
  3864. pDeviceInfoSet->StringTable,
  3865. CDMPath,
  3866. STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE,
  3867. NULL,0)) == -1) {
  3868. Err = ERROR_NOT_ENOUGH_MEMORY;
  3869. leave;
  3870. } else {
  3871. dipb->DriverPath = DriverPathId;
  3872. }
  3873. //
  3874. // Save the Original List info, in case we get
  3875. // an empty list on the Windows Update information.
  3876. //
  3877. // Note: we don't attempt to save/restore our driver enumeration hints
  3878. //
  3879. if(DevInfoElem) {
  3880. lpOrgClass = DevInfoElem->ClassDriverHead;
  3881. lpOrgClassTail = DevInfoElem->ClassDriverTail;
  3882. OrgClassCount = DevInfoElem->ClassDriverCount;
  3883. lpOrgSel = DevInfoElem->SelectedDriver;
  3884. dwOrgSelType = DevInfoElem->SelectedDriverType;
  3885. } else {
  3886. lpOrgClass = pDeviceInfoSet->ClassDriverHead;
  3887. lpOrgClassTail = pDeviceInfoSet->ClassDriverTail;
  3888. OrgClassCount = pDeviceInfoSet->ClassDriverCount;
  3889. lpOrgSel = pDeviceInfoSet->SelectedClassDriver;
  3890. dwOrgSelType = lpOrgSel ? SPDIT_CLASSDRIVER : SPDIT_NODRIVER;
  3891. }
  3892. dwOrgFlags = dipb->Flags;
  3893. dwOrgFlagsEx = dipb->FlagsEx;
  3894. bRestoreDeviceInfo = TRUE;
  3895. if(DevInfoElem) {
  3896. DevInfoElem->ClassDriverHead = DevInfoElem->ClassDriverTail = NULL;
  3897. DevInfoElem->ClassDriverCount = 0;
  3898. DevInfoElem->ClassDriverEnumHint = NULL;
  3899. DevInfoElem->ClassDriverEnumHintIndex = INVALID_ENUM_INDEX;
  3900. DevInfoElem->SelectedDriver = NULL;
  3901. DevInfoElem->SelectedDriverType = SPDIT_NODRIVER;
  3902. } else {
  3903. lpOrgCompat = NULL; // just so we won't ever try to free this list.
  3904. pDeviceInfoSet->ClassDriverHead = pDeviceInfoSet->ClassDriverTail = NULL;
  3905. pDeviceInfoSet->ClassDriverCount = 0;
  3906. pDeviceInfoSet->ClassDriverEnumHint = NULL;
  3907. pDeviceInfoSet->ClassDriverEnumHintIndex = INVALID_ENUM_INDEX;
  3908. pDeviceInfoSet->SelectedClassDriver = NULL;
  3909. }
  3910. dipb->Flags &= ~(DI_DIDCLASS | DI_MULTMFGS);
  3911. dipb->FlagsEx &= ~DI_FLAGSEX_DIDINFOLIST;
  3912. hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT)); // Potentially slow operation ahead!
  3913. dipb->FlagsEx |= DI_FLAGSEX_INET_DRIVER;
  3914. bDoneWithDrvSearch = FALSE;
  3915. Err = GLE_FN_CALL(FALSE,
  3916. SetupDiBuildDriverInfoList(DeviceInfoSet,
  3917. DeviceInfoData,
  3918. SPDIT_CLASSDRIVER)
  3919. );
  3920. dipb->FlagsEx &= ~DI_FLAGSEX_INET_DRIVER;
  3921. SetCursor(hOldCursor); // done with slow operation.
  3922. bDoneWithDrvSearch = TRUE;
  3923. if(Err != NO_ERROR) {
  3924. leave;
  3925. }
  3926. if(DevInfoElem) {
  3927. NewClassDriverCount = DevInfoElem->ClassDriverCount;
  3928. DriverNodeHead = DevInfoElem->ClassDriverHead;
  3929. } else {
  3930. NewClassDriverCount = pDeviceInfoSet->ClassDriverCount;
  3931. DriverNodeHead = pDeviceInfoSet->ClassDriverHead;
  3932. }
  3933. if(!NewClassDriverCount) {
  3934. if(!LoadString(MyDllModuleHandle,
  3935. IDS_SELECT_DEVICE,
  3936. Title,
  3937. SIZECHARS(Title))) {
  3938. *Title = TEXT('\0');
  3939. }
  3940. FormatMessageBox(MyDllModuleHandle,
  3941. NULL,
  3942. MSG_NO_DEVICEINFO_ERROR,
  3943. Title,
  3944. MB_OK | MB_TASKMODAL
  3945. );
  3946. Err = ERROR_DI_BAD_PATH;
  3947. leave;
  3948. }
  3949. //
  3950. // If we get to here, then we have at least one class driver--the class
  3951. // driver list head had better point to something!
  3952. //
  3953. MYASSERT(DriverNodeHead);
  3954. //
  3955. // Assume every driver node in the list is signed. Note that this
  3956. // may not actually be the case, as Windows Update may have given
  3957. // us a "stub" INF whose only use is to build up a list of choices
  3958. // to present to the user. After the user makes a selection, the
  3959. // relevant ID will then be sent to Windows Update to retrieve the
  3960. // real (signed) package.
  3961. //
  3962. for(CurDriverNode=DriverNodeHead;
  3963. CurDriverNode;
  3964. CurDriverNode = CurDriverNode->Next) {
  3965. CurDriverNode->Flags |= DNF_INF_IS_SIGNED;
  3966. }
  3967. //
  3968. // We're happy with our new class driver list, so destroy the original
  3969. // list
  3970. //
  3971. if(bRestoreDeviceInfo) {
  3972. DereferenceClassDriverList(pDeviceInfoSet, lpOrgClass);
  3973. bRestoreDeviceInfo = FALSE;
  3974. }
  3975. //
  3976. // We're happy with the new path, so we don't want to restore the
  3977. // original path.
  3978. //
  3979. bRestoreDriverPath = FALSE;
  3980. } except(pSetupExceptionFilter(GetExceptionCode())) {
  3981. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  3982. if(!bDoneWithDrvSearch) {
  3983. dipb->FlagsEx &= ~DI_FLAGSEX_INET_DRIVER;
  3984. SetCursor(hOldCursor);
  3985. }
  3986. }
  3987. if(bRestoreDeviceInfo || bRestoreHwnd || bRestoreDriverPath) {
  3988. try {
  3989. //
  3990. // If necessary, restore the original list(s).
  3991. //
  3992. if(bRestoreDeviceInfo) {
  3993. if(DevInfoElem) {
  3994. DereferenceClassDriverList(pDeviceInfoSet, DevInfoElem->ClassDriverHead);
  3995. DevInfoElem->ClassDriverHead = lpOrgClass;
  3996. DevInfoElem->ClassDriverTail = lpOrgClassTail;
  3997. DevInfoElem->ClassDriverCount = OrgClassCount;
  3998. DevInfoElem->SelectedDriver = lpOrgSel;
  3999. DevInfoElem->SelectedDriverType = dwOrgSelType;
  4000. } else {
  4001. DereferenceClassDriverList(pDeviceInfoSet, pDeviceInfoSet->ClassDriverHead);
  4002. pDeviceInfoSet->ClassDriverHead = lpOrgClass;
  4003. pDeviceInfoSet->ClassDriverTail = lpOrgClassTail;
  4004. pDeviceInfoSet->ClassDriverCount = OrgClassCount;
  4005. pDeviceInfoSet->SelectedClassDriver = lpOrgSel;
  4006. }
  4007. dipb->Flags = dwOrgFlags;
  4008. dipb->FlagsEx = dwOrgFlagsEx;
  4009. }
  4010. //
  4011. // If the install param block needs its parent hwnd restored, do so
  4012. // now.
  4013. //
  4014. if(bRestoreHwnd) {
  4015. dipb->hwndParent = hwndSave;
  4016. }
  4017. //
  4018. // Likewise, restore the old driver path if necessary.
  4019. //
  4020. if(bRestoreDriverPath) {
  4021. dipb->DriverPath = DriverPathSave;
  4022. dipb->Flags |= DriverPathFlagsSave;
  4023. }
  4024. } except(pSetupExceptionFilter(GetExceptionCode())) {
  4025. pSetupExceptionHandler(GetExceptionCode(),
  4026. ERROR_INVALID_PARAMETER,
  4027. NULL
  4028. );
  4029. }
  4030. }
  4031. UnlockDeviceInfoSet(pDeviceInfoSet);
  4032. return Err;
  4033. }
  4034. DWORD
  4035. HandleWindowsUpdate(
  4036. IN HWND hwndDlg,
  4037. IN OUT PNEWDEVWIZ_DATA ndwData
  4038. )
  4039. /*++
  4040. Routine Description:
  4041. This routine selects a new driver based on a list from INF file(s) that get
  4042. downloaded from the Windows Update Internet site.
  4043. Arguments:
  4044. hwndDlg - Supplies the window handle of the select device wizard page.
  4045. ndwData - Supplies the address of a New Device Wizard data block to be used
  4046. during the processing of this message.
  4047. Return Value:
  4048. If successful, the return value is NO_ERROR, otherwise, it is a Win32 error
  4049. code indicating the cause of failure.
  4050. --*/
  4051. {
  4052. PSP_DIALOGDATA lpdd;
  4053. PDEVICE_INFO_SET pDeviceInfoSet;
  4054. PDEVINSTALL_PARAM_BLOCK dipb;
  4055. SP_WINDOWSUPDATE_PARAMS WindowsUpdateParams;
  4056. PDEVINFO_ELEM DevInfoElem;
  4057. SP_DEVINFO_DATA DevInfoData;
  4058. TCHAR CDMPath[MAX_PATH];
  4059. ULONG BufferLen;
  4060. DOWNLOADINFO DownloadInfo;
  4061. HMODULE hModCDM = NULL;
  4062. DOWNLOAD_UPDATED_FILES_PROC DownloadUpdateFilesProc;
  4063. DWORD Err;
  4064. TCHAR Title[MAX_TITLE_LEN];
  4065. SPFUSIONINSTANCE spFusionInstance;
  4066. BOOL bLeaveFusionContext = FALSE;
  4067. MYASSERT(ndwData);
  4068. lpdd = &(ndwData->ddData);
  4069. MYASSERT(lpdd);
  4070. if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
  4071. //
  4072. // should never hit this code path
  4073. //
  4074. MYASSERT(pDeviceInfoSet);
  4075. return ERROR_INVALID_HANDLE;
  4076. }
  4077. try {
  4078. if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
  4079. DevInfoElem = lpdd->DevInfoElem;
  4080. } else {
  4081. DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
  4082. }
  4083. //
  4084. // If this is for a particular device, then initialize a device
  4085. // information structure.
  4086. //
  4087. if(DevInfoElem) {
  4088. DevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  4089. DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
  4090. DevInfoElem,
  4091. &DevInfoData
  4092. );
  4093. dipb = &(DevInfoElem->InstallParamBlock);
  4094. } else {
  4095. dipb = &(pDeviceInfoSet->InstallParamBlock);
  4096. }
  4097. //
  4098. // Call the class installer to get the package ID and so it can open
  4099. // a handle to the Windows Update server.
  4100. //
  4101. ZeroMemory(&WindowsUpdateParams, sizeof(SP_WINDOWSUPDATE_PARAMS));
  4102. WindowsUpdateParams.ClassInstallHeader.InstallFunction = DIF_GETWINDOWSUPDATEINFO;
  4103. WindowsUpdateParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  4104. Err = DoInstallActionWithParams(DIF_GETWINDOWSUPDATEINFO,
  4105. pDeviceInfoSet,
  4106. DevInfoElem ? &DevInfoData : NULL,
  4107. &WindowsUpdateParams.ClassInstallHeader,
  4108. sizeof(SP_WINDOWSUPDATE_PARAMS),
  4109. INSTALLACTION_CALL_CI
  4110. );
  4111. if(Err != NO_ERROR) {
  4112. leave;
  4113. }
  4114. //
  4115. // We now have a PackageId and a handle to the Windows Update
  4116. // server.
  4117. //
  4118. //
  4119. // Fill In the DOWNLOADINFO structure to pass to CDM.DLL
  4120. //
  4121. ZeroMemory(&DownloadInfo, sizeof(DOWNLOADINFO));
  4122. DownloadInfo.dwDownloadInfoSize = sizeof(DOWNLOADINFO);
  4123. DownloadInfo.lpFile = NULL;
  4124. DownloadInfo.lpHardwareIDs = (LPCWSTR)WindowsUpdateParams.PackageId;
  4125. DownloadInfo.lpDeviceInstanceID = NULL;
  4126. GetVersionEx((OSVERSIONINFOW *)&DownloadInfo.OSVersionInfo);
  4127. //
  4128. // Set dwArchitecture to PROCESSOR_ARCHITECTURE_UNKNOWN, this
  4129. // causes Windows Update to check base on the architecture of the
  4130. // machine itself. You only need to explictly set the value if
  4131. // you want to download drivers for a different architecture than
  4132. // the machine this is running on.
  4133. //
  4134. DownloadInfo.dwArchitecture = PROCESSOR_ARCHITECTURE_UNKNOWN;
  4135. DownloadInfo.dwFlags = 0;
  4136. DownloadInfo.dwClientID = 0;
  4137. DownloadInfo.localid = 0;
  4138. CDMPath[0] = TEXT('\0');
  4139. //
  4140. // Dynamically retrieve the CDM function we need to call.
  4141. //
  4142. bLeaveFusionContext = spFusionEnterContext(NULL, &spFusionInstance);
  4143. Err = GLE_FN_CALL(NULL, hModCDM = LoadLibrary(TEXT("cdm.dll")));
  4144. if(Err == NO_ERROR) {
  4145. Err = GLE_FN_CALL(NULL,
  4146. DownloadUpdateFilesProc = (PVOID)GetProcAddress(
  4147. hModCDM,
  4148. "DownloadUpdatedFiles")
  4149. );
  4150. }
  4151. if(Err == NO_ERROR) {
  4152. Err = GLE_FN_CALL(FALSE,
  4153. DownloadUpdateFilesProc(WindowsUpdateParams.CDMContext,
  4154. hwndDlg,
  4155. &DownloadInfo,
  4156. CDMPath,
  4157. sizeof(CDMPath),
  4158. &BufferLen)
  4159. );
  4160. if((Err == NO_ERROR) && !(*CDMPath)) {
  4161. Err = ERROR_DI_BAD_PATH;
  4162. }
  4163. }
  4164. if(hModCDM) {
  4165. FreeLibrary(hModCDM);
  4166. hModCDM = NULL;
  4167. }
  4168. if(bLeaveFusionContext) {
  4169. spFusionLeaveContext(&spFusionInstance);
  4170. bLeaveFusionContext = FALSE;
  4171. }
  4172. if(Err != NO_ERROR) {
  4173. //
  4174. // Pop up an error messagebox informing the user that we didn't
  4175. // get any drivers from Windows Update.
  4176. //
  4177. if(!LoadString(MyDllModuleHandle,
  4178. IDS_SELECT_DEVICE,
  4179. Title,
  4180. SIZECHARS(Title))) {
  4181. *Title = TEXT('\0');
  4182. }
  4183. FormatMessageBox(MyDllModuleHandle,
  4184. NULL,
  4185. MSG_NO_DEVICEINFO_ERROR,
  4186. Title,
  4187. MB_OK | MB_TASKMODAL
  4188. );
  4189. leave;
  4190. }
  4191. Err = SelectWindowsUpdateDriver(hwndDlg,
  4192. lpdd->DevInfoSet,
  4193. DevInfoElem ? &DevInfoData : NULL,
  4194. CDMPath,
  4195. !(lpdd->flags & DD_FLAG_IS_DIALOGBOX)
  4196. );
  4197. if(Err != NO_ERROR) {
  4198. leave;
  4199. }
  4200. //
  4201. // Fill in the list to select from
  4202. //
  4203. lpdd->bShowCompat = FALSE;
  4204. CheckDlgButton(hwndDlg,
  4205. IDC_NDW_PICKDEV_COMPAT,
  4206. BST_UNCHECKED
  4207. );
  4208. //
  4209. // Enable the UI. We turned it off when the user pressed the Windows
  4210. // Update... button
  4211. //
  4212. ToggleDialogControls(hwndDlg, ndwData, TRUE);
  4213. FillInDeviceList(hwndDlg, lpdd);
  4214. //
  4215. // Since we only show the class list when selecting from Windows
  4216. // Update, hide the selection buttons.
  4217. //
  4218. ShowWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), SW_HIDE);
  4219. } except(pSetupExceptionFilter(GetExceptionCode())) {
  4220. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  4221. if(hModCDM) {
  4222. FreeLibrary(hModCDM);
  4223. }
  4224. if(bLeaveFusionContext) {
  4225. spFusionLeaveContext(&spFusionInstance);
  4226. }
  4227. }
  4228. UnlockDeviceInfoSet(pDeviceInfoSet);
  4229. return Err;
  4230. }
  4231. PNEWDEVWIZ_DATA
  4232. GetNewDevWizDataFromPsPage(
  4233. LPPROPSHEETPAGE ppsp
  4234. )
  4235. /*++
  4236. Routine Description:
  4237. This routine retrieves a pointer to a NEWDEVWIZDATA structure to be used by
  4238. a wizard page dialog proc. It is called during the WM_INITDIALOG handling.
  4239. Arguments:
  4240. Page - Property sheet page structure for this wizard page.
  4241. Return Value:
  4242. If success, a pointer to the structure, NULL otherwise.
  4243. --*/
  4244. {
  4245. PDEVICE_INFO_SET pDeviceInfoSet;
  4246. PVOID WizObjectId;
  4247. PWIZPAGE_OBJECT CurWizObject = NULL;
  4248. //
  4249. // Access the device info set handle stored in the propsheetpage's lParam.
  4250. //
  4251. MYASSERT(ppsp);
  4252. if(pDeviceInfoSet = AccessDeviceInfoSet((HDEVINFO)(ppsp->lParam))) {
  4253. try {
  4254. //
  4255. // The ObjectID (pointer, actually) for the corresponding wizard
  4256. // object for this page is stored at the end of the ppsp structure.
  4257. // Retrieve this now, and look for it in the devinfo set's list of
  4258. // wizard objects.
  4259. //
  4260. WizObjectId = *((PVOID *)(&(((PBYTE)ppsp)[sizeof(PROPSHEETPAGE)])));
  4261. for(CurWizObject = pDeviceInfoSet->WizPageList;
  4262. CurWizObject;
  4263. CurWizObject = CurWizObject->Next) {
  4264. if(WizObjectId == CurWizObject) {
  4265. //
  4266. // We found our object.
  4267. //
  4268. break;
  4269. }
  4270. }
  4271. } except(pSetupExceptionFilter(GetExceptionCode())) {
  4272. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  4273. CurWizObject = NULL;
  4274. }
  4275. UnlockDeviceInfoSet(pDeviceInfoSet);
  4276. }
  4277. return CurWizObject ? CurWizObject->ndwData : NULL;
  4278. }
  4279. BOOL
  4280. WINAPI
  4281. SetupDiSelectDevice(
  4282. IN HDEVINFO DeviceInfoSet,
  4283. IN OUT PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
  4284. )
  4285. /*++
  4286. Routine Description:
  4287. Default handler for DIF_SELECTDEVICE
  4288. This routine will handle the UI for allowing a user to select a driver
  4289. for the specified device information set or element. By using the Flags
  4290. field of the installation parameter block struct, the caller can specify
  4291. special handling of the UI, such as allowing selecting from OEM disks.
  4292. Arguments:
  4293. DeviceInfoSet - Supplies a handle to the device information set for which a
  4294. driver is to be selected.
  4295. DeviceInfoData - Optionally, supplies the address of a SP_DEVINFO_DATA
  4296. structure for which a driver is to be selected. If this parameter is
  4297. not specified, then a driver will be selected for the global class
  4298. driver list associated with the device information set itself.
  4299. This is an IN OUT parameter because the class GUID for the device will
  4300. be updated to reflect the class of the most-compatible driver, if a
  4301. compatible driver list was built.
  4302. Return Value:
  4303. If the function succeeds, the return value is TRUE.
  4304. If the function fails, the return value is FALSE. To get extended error
  4305. information, call GetLastError.
  4306. --*/
  4307. {
  4308. PDEVICE_INFO_SET pDeviceInfoSet = NULL;
  4309. DWORD Err = NO_ERROR;
  4310. PDEVINFO_ELEM DevInfoElem = NULL;
  4311. PDEVINSTALL_PARAM_BLOCK dipb;
  4312. WIZPAGE_OBJECT WizPageObject;
  4313. NEWDEVWIZ_DATA ndwData;
  4314. PWIZPAGE_OBJECT CurWizObject, PrevWizObject;
  4315. //
  4316. // Store the address of the corresponding wizard object at the
  4317. // end of the PROPSHEETPAGE buffer.
  4318. //
  4319. BYTE pspBuffer[sizeof(PROPSHEETPAGE) + sizeof(PVOID)];
  4320. LPPROPSHEETPAGE Page = (LPPROPSHEETPAGE)pspBuffer;
  4321. try {
  4322. //
  4323. // Make sure we're running interactively.
  4324. //
  4325. if(GlobalSetupFlags & (PSPGF_NONINTERACTIVE|PSPGF_UNATTENDED_SETUP)) {
  4326. Err = ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION;
  4327. leave;
  4328. }
  4329. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  4330. Err = ERROR_INVALID_HANDLE;
  4331. leave;
  4332. }
  4333. //
  4334. // This routine cannot be called when the lock level is nested
  4335. // (i.e., > 1). This is explicitly disallowed, so that our multi-
  4336. // threaded dialog won't deadlock.
  4337. //
  4338. if(pDeviceInfoSet->LockRefCount > 1) {
  4339. Err = ERROR_DEVINFO_LIST_LOCKED;
  4340. leave;
  4341. }
  4342. if(DeviceInfoData) {
  4343. //
  4344. // Special check to make sure we aren't being passed a zombie
  4345. // (different from phantom, the zombie devinfo element is one whose
  4346. // corresponding devinst was deleted via SetupDiRemoveDevice, but
  4347. // who lingers on until the caller kills it via
  4348. // SetupDiDeleteDeviceInfo or SetupDiDestroyDeviceInfoList).
  4349. //
  4350. if(!DeviceInfoData->DevInst) {
  4351. Err = ERROR_INVALID_PARAMETER;
  4352. leave;
  4353. }
  4354. //
  4355. // Then we are to select a driver for a particular device.
  4356. //
  4357. if(!(DevInfoElem = FindAssociatedDevInfoElem(pDeviceInfoSet,
  4358. DeviceInfoData,
  4359. NULL))) {
  4360. Err = ERROR_INVALID_PARAMETER;
  4361. leave;
  4362. }
  4363. dipb = &(DevInfoElem->InstallParamBlock);
  4364. } else {
  4365. dipb = &(pDeviceInfoSet->InstallParamBlock);
  4366. }
  4367. ZeroMemory(&ndwData, sizeof(ndwData));
  4368. ndwData.ddData.iCurDesc = -1;
  4369. ndwData.ddData.DevInfoSet = DeviceInfoSet;
  4370. ndwData.ddData.DevInfoElem = DevInfoElem;
  4371. ndwData.ddData.flags = DD_FLAG_USE_DEVINFO_ELEM | DD_FLAG_IS_DIALOGBOX;
  4372. WizPageObject.RefCount = 1;
  4373. WizPageObject.ndwData = &ndwData;
  4374. //
  4375. // We're safe in placing this stack object in the devinfo set's linked
  4376. // list, since nobody will ever attempt to free it.
  4377. //
  4378. WizPageObject.Next = pDeviceInfoSet->WizPageList;
  4379. pDeviceInfoSet->WizPageList = &WizPageObject;
  4380. //
  4381. // Since we're using the same code as the Add New Device Wizard, we
  4382. // have to supply a LPROPSHEETPAGE as the lParam to the DialogProc.
  4383. // (All we care about is the lParam field, and the DWORD at the end
  4384. // of the buffer.)
  4385. //
  4386. Page->lParam = (LPARAM)DeviceInfoSet;
  4387. *((PVOID *)(&(pspBuffer[sizeof(PROPSHEETPAGE)]))) = &WizPageObject;
  4388. //
  4389. // Release the lock, so other stuff can happen while this dialog is up.
  4390. //
  4391. UnlockDeviceInfoSet(pDeviceInfoSet);
  4392. pDeviceInfoSet = NULL;
  4393. Err = (DWORD)DialogBoxParam(MyDllModuleHandle,
  4394. MAKEINTRESOURCE(DLG_DEVINSTALL),
  4395. dipb->hwndParent,
  4396. SelectDeviceDlgProc,
  4397. (LPARAM)Page
  4398. );
  4399. //
  4400. // Re-acquire the devinfo set lock.
  4401. //
  4402. if(!(pDeviceInfoSet = AccessDeviceInfoSet(DeviceInfoSet))) {
  4403. //
  4404. // should never hit this code path
  4405. // this would imply another thread messed this handle up
  4406. //
  4407. MYASSERT(pDeviceInfoSet);
  4408. Err = ERROR_INVALID_HANDLE;
  4409. leave;
  4410. }
  4411. //
  4412. // Now remove the wizard page object from the devinfo set's list. We
  4413. // can't assume that it's still at the head of the list, since someone
  4414. // else couldn've added another page.
  4415. //
  4416. for(CurWizObject = pDeviceInfoSet->WizPageList, PrevWizObject = NULL;
  4417. CurWizObject;
  4418. PrevWizObject = CurWizObject, CurWizObject = CurWizObject->Next) {
  4419. if(CurWizObject == &WizPageObject) {
  4420. break;
  4421. }
  4422. }
  4423. MYASSERT(CurWizObject);
  4424. if(PrevWizObject) {
  4425. PrevWizObject->Next = CurWizObject->Next;
  4426. } else {
  4427. pDeviceInfoSet->WizPageList = CurWizObject->Next;
  4428. }
  4429. if(DeviceInfoData) {
  4430. //
  4431. // Update the caller's device information element with its
  4432. // (potentially) new class.
  4433. //
  4434. DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
  4435. DevInfoElem,
  4436. DeviceInfoData
  4437. );
  4438. }
  4439. } except(pSetupExceptionFilter(GetExceptionCode())) {
  4440. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, &Err);
  4441. }
  4442. if(pDeviceInfoSet) {
  4443. UnlockDeviceInfoSet(pDeviceInfoSet);
  4444. }
  4445. SetLastError(Err);
  4446. return (Err == NO_ERROR);
  4447. }
  4448. BOOL
  4449. bNoDevsToShow(
  4450. IN PDEVINFO_ELEM DevInfoElem
  4451. )
  4452. /*++
  4453. Routine Description:
  4454. This routine determines whether or not there are any compatible devices to
  4455. be displayed for the specified devinfo element.
  4456. Arguments:
  4457. DevInfoElem - Supplies the address of a devinfo element to check.
  4458. Return Value:
  4459. If there are no devices to show, the return value is TRUE.
  4460. If there is at least one device (driver node) without the
  4461. DNF_EXCLUDEFROMLIST flag set, the return value is FALSE.
  4462. --*/
  4463. {
  4464. PDRIVER_NODE CurDriverNode;
  4465. for(CurDriverNode = DevInfoElem->CompatDriverHead;
  4466. CurDriverNode;
  4467. CurDriverNode = CurDriverNode->Next) {
  4468. if(!(CurDriverNode->Flags & DNF_OLD_INET_DRIVER) &&
  4469. !(CurDriverNode->Flags & DNF_BAD_DRIVER) &&
  4470. (!(CurDriverNode->Flags & DNF_EXCLUDEFROMLIST) ||
  4471. (DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_ALLOWEXCLUDEDDRVS))) {
  4472. return FALSE;
  4473. }
  4474. }
  4475. return TRUE;
  4476. }
  4477. VOID
  4478. OnCancel(
  4479. IN PNEWDEVWIZ_DATA ndwData
  4480. )
  4481. /*++
  4482. Routine Description:
  4483. This routine is only called in the select device dialog (not wizard) case.
  4484. Its sole purpose is to destroy any driver lists that weren't present before
  4485. SetupDiSelectDevice was called.
  4486. Arguments:
  4487. ndwData - Supplies the address of a data structure containing information
  4488. on the driver lists to be (possibly) destroyed.
  4489. Return Value:
  4490. None.
  4491. --*/
  4492. {
  4493. PSP_DIALOGDATA lpdd;
  4494. PDEVICE_INFO_SET pDeviceInfoSet;
  4495. PDEVINFO_ELEM DevInfoElem;
  4496. PDEVINSTALL_PARAM_BLOCK dipb;
  4497. DWORD SelectedDriverType = SPDIT_NODRIVER;
  4498. MYASSERT(ndwData);
  4499. lpdd = &(ndwData->ddData);
  4500. MYASSERT(lpdd);
  4501. if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
  4502. //
  4503. // should never hit this code path
  4504. //
  4505. MYASSERT(pDeviceInfoSet);
  4506. return;
  4507. }
  4508. try {
  4509. if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
  4510. DevInfoElem = lpdd->DevInfoElem;
  4511. } else {
  4512. DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
  4513. }
  4514. if(DevInfoElem) {
  4515. if(lpdd->bKeeplpSelectedDrv) {
  4516. SelectedDriverType = DevInfoElem->SelectedDriverType;
  4517. } else {
  4518. DevInfoElem->SelectedDriver = NULL;
  4519. DevInfoElem->SelectedDriverType = SPDIT_NODRIVER;
  4520. }
  4521. if((DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDINFOLIST) &&
  4522. !lpdd->bKeeplpClassDrvList && (SelectedDriverType != SPDIT_CLASSDRIVER)) {
  4523. DereferenceClassDriverList(pDeviceInfoSet, DevInfoElem->ClassDriverHead);
  4524. DevInfoElem->ClassDriverHead = DevInfoElem->ClassDriverTail = NULL;
  4525. DevInfoElem->ClassDriverCount = 0;
  4526. DevInfoElem->ClassDriverEnumHint = NULL;
  4527. DevInfoElem->ClassDriverEnumHintIndex = INVALID_ENUM_INDEX;
  4528. DevInfoElem->InstallParamBlock.Flags &= ~(DI_DIDCLASS | DI_MULTMFGS);
  4529. DevInfoElem->InstallParamBlock.FlagsEx &= ~DI_FLAGSEX_DIDINFOLIST;
  4530. }
  4531. if((DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDCOMPATINFO) &&
  4532. !lpdd->bKeeplpCompatDrvList && (SelectedDriverType != SPDIT_COMPATDRIVER)) {
  4533. DestroyDriverNodes(DevInfoElem->CompatDriverHead, pDeviceInfoSet);
  4534. DevInfoElem->CompatDriverHead = DevInfoElem->CompatDriverTail = NULL;
  4535. DevInfoElem->CompatDriverCount = 0;
  4536. DevInfoElem->CompatDriverEnumHint = NULL;
  4537. DevInfoElem->CompatDriverEnumHintIndex = INVALID_ENUM_INDEX;
  4538. DevInfoElem->InstallParamBlock.Flags &= ~DI_DIDCOMPAT;
  4539. DevInfoElem->InstallParamBlock.FlagsEx &= ~DI_FLAGSEX_DIDCOMPATINFO;
  4540. }
  4541. } else {
  4542. if(lpdd->bKeeplpSelectedDrv) {
  4543. if(pDeviceInfoSet->SelectedClassDriver) {
  4544. SelectedDriverType = SPDIT_CLASSDRIVER;
  4545. }
  4546. } else {
  4547. pDeviceInfoSet->SelectedClassDriver = NULL;
  4548. }
  4549. if((pDeviceInfoSet->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDINFOLIST) &&
  4550. !lpdd->bKeeplpClassDrvList && (SelectedDriverType != SPDIT_CLASSDRIVER)) {
  4551. DereferenceClassDriverList(pDeviceInfoSet, pDeviceInfoSet->ClassDriverHead);
  4552. pDeviceInfoSet->ClassDriverHead = pDeviceInfoSet->ClassDriverTail = NULL;
  4553. pDeviceInfoSet->ClassDriverCount = 0;
  4554. pDeviceInfoSet->ClassDriverEnumHint = NULL;
  4555. pDeviceInfoSet->ClassDriverEnumHintIndex = INVALID_ENUM_INDEX;
  4556. pDeviceInfoSet->InstallParamBlock.Flags &= ~(DI_DIDCLASS | DI_MULTMFGS);
  4557. pDeviceInfoSet->InstallParamBlock.FlagsEx &= ~DI_FLAGSEX_DIDINFOLIST;
  4558. }
  4559. }
  4560. } except(pSetupExceptionFilter(GetExceptionCode())) {
  4561. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  4562. }
  4563. UnlockDeviceInfoSet(pDeviceInfoSet);
  4564. }
  4565. LONG
  4566. GetCurDesc(
  4567. IN PSP_DIALOGDATA lpdd
  4568. )
  4569. /*++
  4570. Routine Description:
  4571. This routine returns the (case-insensitive) string table index for the
  4572. description of the currently selected driver. This is used to select a
  4573. particular entry in a listview control.
  4574. Arguments:
  4575. lpdd - Supplies the address of a dialog data structure that contains
  4576. information about the device information set being used.
  4577. Return Value:
  4578. The string table ID for the device description, as stored in the currently-
  4579. selected driver node.
  4580. --*/
  4581. {
  4582. PDEVICE_INFO_SET pDeviceInfoSet;
  4583. PDEVINFO_ELEM DevInfoElem;
  4584. LONG ret;
  4585. MYASSERT(lpdd);
  4586. if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
  4587. //
  4588. // should never hit this code path
  4589. //
  4590. MYASSERT(pDeviceInfoSet);
  4591. return -1;
  4592. }
  4593. try {
  4594. if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
  4595. DevInfoElem = lpdd->DevInfoElem;
  4596. } else {
  4597. DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
  4598. }
  4599. if(DevInfoElem) {
  4600. ret = DevInfoElem->SelectedDriver
  4601. ? DevInfoElem->SelectedDriver->DevDescription
  4602. : -1;
  4603. } else {
  4604. ret = pDeviceInfoSet->SelectedClassDriver
  4605. ? pDeviceInfoSet->SelectedClassDriver->DevDescription
  4606. : -1;
  4607. }
  4608. } except(pSetupExceptionFilter(GetExceptionCode())) {
  4609. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  4610. ret = -1;
  4611. }
  4612. UnlockDeviceInfoSet(pDeviceInfoSet);
  4613. return ret;
  4614. }
  4615. VOID
  4616. __cdecl
  4617. ClassDriverSearchThread(
  4618. IN PVOID Context
  4619. )
  4620. /*++
  4621. Routine Description:
  4622. Thread entry point to build a class driver list asynchronously to the main
  4623. thread which is displaying a Select Device dialog. This thread will free
  4624. the memory containing its context, so the main thread should not access it
  4625. after passing it to this thread.
  4626. Arguments:
  4627. Context - supplies driver search context.
  4628. Return Value:
  4629. None.
  4630. --*/
  4631. {
  4632. PCLASSDRV_THREAD_CONTEXT ClassDrvThreadContext = Context;
  4633. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  4634. BOOL b;
  4635. DWORD Err;
  4636. //
  4637. // OR in the DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS flag so that we don't
  4638. // include old internet drivers in the list that we get back.
  4639. //
  4640. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  4641. if(SetupDiGetDeviceInstallParams(ClassDrvThreadContext->DeviceInfoSet,
  4642. &(ClassDrvThreadContext->DeviceInfoData),
  4643. &DeviceInstallParams))
  4644. {
  4645. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS;
  4646. SetupDiSetDeviceInstallParams(ClassDrvThreadContext->DeviceInfoSet,
  4647. &(ClassDrvThreadContext->DeviceInfoData),
  4648. &DeviceInstallParams
  4649. );
  4650. }
  4651. Err = GLE_FN_CALL(FALSE,
  4652. b = SetupDiBuildDriverInfoList(
  4653. ClassDrvThreadContext->DeviceInfoSet,
  4654. &(ClassDrvThreadContext->DeviceInfoData),
  4655. SPDIT_CLASSDRIVER)
  4656. );
  4657. //
  4658. // Now send a message to our notification window informing them of the outcome.
  4659. //
  4660. PostMessage(ClassDrvThreadContext->NotificationWindow,
  4661. WMX_CLASSDRVLIST_DONE,
  4662. (WPARAM)b,
  4663. (LPARAM)Err
  4664. );
  4665. MyFree(Context);
  4666. //
  4667. // Done.
  4668. //
  4669. _endthread();
  4670. }
  4671. BOOL
  4672. pSetupIsClassDriverListBuilt(
  4673. IN PSP_DIALOGDATA lpdd
  4674. )
  4675. /*++
  4676. Routine Description:
  4677. This routine determines whether or not a class driver list has already been
  4678. built for the specified dialog data.
  4679. Arguments:
  4680. lpdd - Supplies the address of a dialog data buffer that is being queried
  4681. for the presence of a class driver list.
  4682. Return Value:
  4683. If a class driver list has already been built, the return value is TRUE,
  4684. otherwise, it is FALSE.
  4685. --*/
  4686. {
  4687. PDEVICE_INFO_SET pDeviceInfoSet;
  4688. PDEVINFO_ELEM DevInfoElem;
  4689. BOOL b = FALSE;
  4690. MYASSERT(lpdd);
  4691. if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
  4692. //
  4693. // should never hit this code path
  4694. //
  4695. MYASSERT(pDeviceInfoSet);
  4696. return FALSE;
  4697. }
  4698. try {
  4699. if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
  4700. DevInfoElem = lpdd->DevInfoElem;
  4701. } else {
  4702. DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
  4703. }
  4704. if(DevInfoElem) {
  4705. b = DevInfoElem->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDINFOLIST;
  4706. } else {
  4707. b = pDeviceInfoSet->InstallParamBlock.FlagsEx & DI_FLAGSEX_DIDINFOLIST;
  4708. }
  4709. } except(pSetupExceptionFilter(GetExceptionCode())) {
  4710. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  4711. }
  4712. UnlockDeviceInfoSet(pDeviceInfoSet);
  4713. return b;
  4714. }
  4715. VOID
  4716. pSetupDevInfoDataFromDialogData(
  4717. IN PSP_DIALOGDATA lpdd,
  4718. OUT PSP_DEVINFO_DATA DeviceInfoData
  4719. )
  4720. /*++
  4721. Routine Description:
  4722. This routine fills in a SP_DEVINFO_DATA structure based on the device
  4723. information element specified in the supplied dialog data.
  4724. Arguments:
  4725. lpdd - Supplies the address of a dialog data buffer that specifies a
  4726. devinfo element to be used in filling in the DeviceInfoData buffer.
  4727. DeviceInfoData - Supplies the address of a SP_DEVINFO_DATA structure that
  4728. is filled in with information about the devinfo element specified in
  4729. the dialog data.
  4730. Return Value:
  4731. None.
  4732. --*/
  4733. {
  4734. PDEVICE_INFO_SET pDeviceInfoSet;
  4735. PDEVINFO_ELEM DevInfoElem;
  4736. MYASSERT(lpdd);
  4737. if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
  4738. //
  4739. // should never hit this code path
  4740. //
  4741. MYASSERT(pDeviceInfoSet);
  4742. return;
  4743. }
  4744. try {
  4745. if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
  4746. DevInfoElem = lpdd->DevInfoElem;
  4747. } else {
  4748. DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
  4749. }
  4750. //
  4751. // The dialog data had better be referencing a devinfo element!
  4752. //
  4753. MYASSERT(DevInfoElem);
  4754. DeviceInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
  4755. DevInfoDataFromDeviceInfoElement(pDeviceInfoSet, DevInfoElem, DeviceInfoData);
  4756. } except(pSetupExceptionFilter(GetExceptionCode())) {
  4757. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  4758. }
  4759. UnlockDeviceInfoSet(pDeviceInfoSet);
  4760. }
  4761. VOID
  4762. CleanupDriverLists(
  4763. IN OUT PNEWDEVWIZ_DATA ndwData
  4764. )
  4765. /*++
  4766. Routine Description:
  4767. This routine will destroy both the class and compatible driver lists that
  4768. were created while the wizard page was up.
  4769. Arguments:
  4770. ndwData - Supplies the address of a New Device Wizard data block to be used
  4771. during the processing of this message.
  4772. Return Value:
  4773. None.
  4774. --*/
  4775. {
  4776. PSP_DIALOGDATA lpdd;
  4777. PDEVICE_INFO_SET pDeviceInfoSet;
  4778. PDEVINFO_ELEM DevInfoElem;
  4779. PDEVINSTALL_PARAM_BLOCK dipb;
  4780. SP_DEVINFO_DATA DeviceInfoData;
  4781. MYASSERT(ndwData);
  4782. lpdd = &(ndwData->ddData);
  4783. MYASSERT(lpdd);
  4784. if(!(pDeviceInfoSet = AccessDeviceInfoSet(lpdd->DevInfoSet))) {
  4785. //
  4786. // should never hit this code path
  4787. //
  4788. MYASSERT(pDeviceInfoSet);
  4789. return;
  4790. }
  4791. try {
  4792. if(lpdd->flags & DD_FLAG_USE_DEVINFO_ELEM) {
  4793. DevInfoElem = lpdd->DevInfoElem;
  4794. } else {
  4795. DevInfoElem = pDeviceInfoSet->SelectedDevInfoElem;
  4796. }
  4797. if(DevInfoElem) {
  4798. //
  4799. // Initialize a SP_DEVINFO_DATA buffer to use as an argument to
  4800. // SetupDiDestroyDriverInfoList.
  4801. //
  4802. DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  4803. DevInfoDataFromDeviceInfoElement(pDeviceInfoSet,
  4804. DevInfoElem,
  4805. &DeviceInfoData
  4806. );
  4807. //
  4808. // We need to reset the DriverPath so that if we come back into the
  4809. // wizard we will rebuild from the correct directory. Otherwise we
  4810. // will be stuck with the Have Disk... path that the user entered.
  4811. //
  4812. DevInfoElem->InstallParamBlock.DriverPath = -1;
  4813. } else {
  4814. pDeviceInfoSet->InstallParamBlock.DriverPath = -1;
  4815. }
  4816. SetupDiDestroyDriverInfoList(pDeviceInfoSet,
  4817. DevInfoElem ? &DeviceInfoData : NULL,
  4818. SPDIT_COMPATDRIVER
  4819. );
  4820. SetupDiDestroyDriverInfoList(pDeviceInfoSet,
  4821. DevInfoElem ? &DeviceInfoData : NULL,
  4822. SPDIT_CLASSDRIVER
  4823. );
  4824. } except(pSetupExceptionFilter(GetExceptionCode())) {
  4825. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  4826. }
  4827. UnlockDeviceInfoSet(pDeviceInfoSet);
  4828. }
  4829. VOID
  4830. ToggleDialogControls(
  4831. IN HWND hwndDlg,
  4832. IN OUT PNEWDEVWIZ_DATA ndwData,
  4833. IN BOOL Enable
  4834. )
  4835. /*++
  4836. Routine Description:
  4837. This routine either enables or disables all controls on a Select Device
  4838. dialog box, depending on the value of Enable.
  4839. Arguments:
  4840. hwndDlg - Supplies the handle of the Select Device dialog
  4841. ndwData - Supplies the address of a New Device Wizard data block to be used
  4842. during the processing of this message.
  4843. Enable - If TRUE, then enable all controls (with possible exception of
  4844. "Show all devices" radio button (if class list search failed). If
  4845. FALSE, disable all controls.
  4846. Return Value:
  4847. None.
  4848. --*/
  4849. {
  4850. //
  4851. // If we're enabling controls, make sure we only enable the "Show
  4852. // compatible drivers" check box if we successfully built a class list.
  4853. //
  4854. if(Enable) {
  4855. if(!((ndwData->ddData).flags & DD_FLAG_CLASSLIST_FAILED)) {
  4856. EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), TRUE);
  4857. } else {
  4858. //
  4859. // The class list failed to build, so we will show the compatible
  4860. // list only. Check and disable the show compatible check box.
  4861. //
  4862. (ndwData->ddData).bShowCompat = TRUE;
  4863. CheckDlgButton(hwndDlg, IDC_NDW_PICKDEV_COMPAT, BST_CHECKED);
  4864. EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), FALSE);
  4865. }
  4866. } else {
  4867. EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_COMPAT), FALSE);
  4868. }
  4869. EnableWindow((ndwData->ddData).hwndDrvList, Enable);
  4870. EnableWindow((ndwData->ddData).hwndMfgList, Enable);
  4871. EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_HAVEDISK), Enable);
  4872. EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_WINDOWSUPDATE), Enable);
  4873. EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_ICON), Enable);
  4874. EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_TEXT), Enable);
  4875. EnableWindow(GetDlgItem(hwndDlg, IDC_NDW_PICKDEV_SIGNED_LINK), Enable);
  4876. if ((ndwData->ddData).flags & DD_FLAG_IS_DIALOGBOX) {
  4877. EnableWindow(GetDlgItem(hwndDlg, IDOK), Enable);
  4878. EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), Enable);
  4879. } else {
  4880. INT WizardFlags = 0;
  4881. if (Enable) {
  4882. //
  4883. // Don't show the back button if we are in express mode.
  4884. //
  4885. if(!((ndwData->InstallData).Flags & NDW_INSTALLFLAG_SKIPCLASSLIST) ||
  4886. !((ndwData->InstallData).Flags & NDW_INSTALLFLAG_EXPRESSINTRO) ||
  4887. ((ndwData->InstallData).DynamicPageFlags & DYNAWIZ_FLAG_PAGESADDED)) {
  4888. WizardFlags |= PSWIZB_BACK;
  4889. }
  4890. //
  4891. // Show the Next button if there is at least one driver selected in the
  4892. // list view.
  4893. //
  4894. if(ListView_GetSelectedCount((ndwData->ddData).hwndDrvList) > 0) {
  4895. WizardFlags |= PSWIZB_NEXT;
  4896. }
  4897. }
  4898. PropSheet_SetWizButtons(GetParent(hwndDlg), WizardFlags);
  4899. EnableWindow(GetDlgItem(GetParent(hwndDlg), IDCANCEL), Enable);
  4900. }
  4901. }
  4902. BOOL
  4903. CDMIsInternetAvailable(
  4904. void
  4905. )
  4906. /*++
  4907. Routine Description:
  4908. This routine will return TRUE or FALSE based on if this machine can get to
  4909. the Internet or not.
  4910. Arguments:
  4911. None
  4912. Return Value:
  4913. TRUE if the machine can get to the Internet.
  4914. FALSE if the machine can NOT get to the Internet.
  4915. --*/
  4916. {
  4917. BOOL IsInternetAvailable = FALSE;
  4918. HKEY hKey = INVALID_HANDLE_VALUE;
  4919. DWORD Policy;
  4920. ULONG cbData;
  4921. HMODULE hModCDM = NULL;
  4922. CDM_INTERNET_AVAILABLE_PROC CdmInternetAvailable;
  4923. SPFUSIONINSTANCE spFusionInstance;
  4924. BOOL bLeaveFusionContext = FALSE;
  4925. try {
  4926. //
  4927. // Check the DontSearchWindowsUpdate DriverSearching policy.
  4928. //
  4929. if(ERROR_SUCCESS == RegOpenKeyEx(
  4930. HKEY_CURRENT_USER,
  4931. TEXT("Software\\Policies\\Microsoft\\Windows\\DriverSearching"),
  4932. 0,
  4933. KEY_READ,
  4934. &hKey)) {
  4935. cbData = sizeof(Policy);
  4936. //
  4937. // Initialize Policy, so we don't pickup random data if
  4938. // actual cbData size < sizeof(DWORD)
  4939. //
  4940. Policy = 0;
  4941. if(ERROR_SUCCESS == RegQueryValueEx(hKey,
  4942. TEXT("DontSearchWindowsUpdate"),
  4943. NULL,
  4944. NULL,
  4945. (LPBYTE)&Policy,
  4946. &cbData)) {
  4947. if(Policy) {
  4948. //
  4949. // If the DontSearchWindowsUpdate policy is set then we
  4950. // want to return FALSE.
  4951. //
  4952. leave;
  4953. }
  4954. }
  4955. } else {
  4956. //
  4957. // Couldn't open the policy registry key--make sure it's still set
  4958. // to an invalid value so we'll know not to try and close it later.
  4959. //
  4960. hKey = INVALID_HANDLE_VALUE;
  4961. }
  4962. bLeaveFusionContext = spFusionEnterContext(NULL,&spFusionInstance);
  4963. if((NO_ERROR != GLE_FN_CALL(NULL, hModCDM = LoadLibrary(TEXT("cdm.dll")))) ||
  4964. (NO_ERROR != GLE_FN_CALL(NULL, CdmInternetAvailable = (PVOID)GetProcAddress(hModCDM, "DownloadIsInternetAvailable")))) {
  4965. leave;
  4966. }
  4967. IsInternetAvailable = CdmInternetAvailable();
  4968. } except(pSetupExceptionFilter(GetExceptionCode())) {
  4969. pSetupExceptionHandler(GetExceptionCode(), ERROR_INVALID_PARAMETER, NULL);
  4970. }
  4971. if(hModCDM) {
  4972. FreeLibrary(hModCDM);
  4973. }
  4974. if(bLeaveFusionContext) {
  4975. spFusionLeaveContext(&spFusionInstance);
  4976. }
  4977. if(hKey != INVALID_HANDLE_VALUE) {
  4978. RegCloseKey(hKey);
  4979. }
  4980. return IsInternetAvailable;
  4981. }