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

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