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.

2161 lines
72 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1996 - 1999
  6. //
  7. // File: finish.c
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "newdevp.h"
  11. #include <help.h>
  12. typedef
  13. UINT
  14. (*PDEVICEPROBLEMTEXT)(
  15. HMACHINE hMachine,
  16. DEVNODE DevNode,
  17. ULONG ProblemNumber,
  18. LPTSTR Buffer,
  19. UINT BufferSize
  20. );
  21. BOOL
  22. IsNullDriverInstalled(
  23. DEVNODE DevNode
  24. )
  25. /*++
  26. Routine Description:
  27. This routine determines whether a null driver, or no driver at all, is
  28. installed for this device instance. Currently the test is that I know
  29. a null driver was installed if the "Driver" value entry doesn't exist.
  30. Arguments:
  31. DevNode
  32. Return Value:
  33. Returns TRUE if a null driver was installed for this device, otherwise
  34. returns FALSE.
  35. --*/
  36. {
  37. TCHAR Buffer[1];
  38. DWORD dwSize, dwType;
  39. dwSize = SIZECHARS(Buffer);
  40. if (CM_Get_DevNode_Registry_Property(DevNode,
  41. CM_DRP_DRIVER,
  42. &dwType,
  43. (LPVOID)Buffer,
  44. &dwSize,
  45. 0) == CR_BUFFER_SMALL) {
  46. return FALSE;
  47. } else {
  48. return TRUE;
  49. }
  50. }
  51. PTCHAR
  52. DeviceProblemText(
  53. HMACHINE hMachine,
  54. DEVNODE DevNode,
  55. ULONG ProblemNumber
  56. )
  57. {
  58. UINT LenChars, ReqLenChars;
  59. HMODULE hDevMgr=NULL;
  60. PTCHAR Buffer=NULL;
  61. PDEVICEPROBLEMTEXT pDeviceProblemText = NULL;
  62. hDevMgr = LoadLibrary(TEXT("devmgr.dll"));
  63. if (hDevMgr)
  64. {
  65. pDeviceProblemText = (PVOID) GetProcAddress(hDevMgr, "DeviceProblemTextW");
  66. }
  67. if (pDeviceProblemText)
  68. {
  69. LenChars = (pDeviceProblemText)(hMachine,
  70. DevNode,
  71. ProblemNumber,
  72. Buffer,
  73. 0
  74. );
  75. if (!LenChars)
  76. {
  77. goto DPTExitCleanup;
  78. }
  79. LenChars++; // one extra for terminating NULL
  80. Buffer = LocalAlloc(LPTR, LenChars*sizeof(TCHAR));
  81. if (!Buffer)
  82. {
  83. goto DPTExitCleanup;
  84. }
  85. ReqLenChars = (pDeviceProblemText)(hMachine,
  86. DevNode,
  87. ProblemNumber,
  88. Buffer,
  89. LenChars
  90. );
  91. if (!ReqLenChars || ReqLenChars >= LenChars)
  92. {
  93. LocalFree(Buffer);
  94. Buffer = NULL;
  95. }
  96. }
  97. DPTExitCleanup:
  98. if (hDevMgr)
  99. {
  100. FreeLibrary(hDevMgr);
  101. }
  102. return Buffer;
  103. }
  104. BOOL
  105. DeviceHasResources(
  106. DEVINST DeviceInst
  107. )
  108. {
  109. CONFIGRET ConfigRet;
  110. ULONG lcType = NUM_LOG_CONF;
  111. while (lcType--)
  112. {
  113. ConfigRet = CM_Get_First_Log_Conf_Ex(NULL, DeviceInst, lcType, NULL);
  114. if (ConfigRet == CR_SUCCESS)
  115. {
  116. return TRUE;
  117. }
  118. }
  119. return FALSE;
  120. }
  121. BOOL
  122. GetClassGuidForInf(
  123. PTSTR InfFileName,
  124. LPGUID ClassGuid
  125. )
  126. {
  127. TCHAR ClassName[MAX_CLASS_NAME_LEN];
  128. DWORD NumGuids;
  129. if(!SetupDiGetINFClass(InfFileName,
  130. ClassGuid,
  131. ClassName,
  132. sizeof(ClassName)/sizeof(TCHAR),
  133. NULL))
  134. {
  135. return FALSE;
  136. }
  137. if (IsEqualGUID(ClassGuid, &GUID_NULL))
  138. {
  139. //
  140. // Then we need to retrieve the GUID associated with the INF's class name.
  141. // (If this class name isn't installed (i.e., has no corresponding GUID),
  142. // or if it matches with multiple GUIDs, then we abort.
  143. //
  144. if(!SetupDiClassGuidsFromName(ClassName, ClassGuid, 1, &NumGuids) || !NumGuids)
  145. {
  146. return FALSE;
  147. }
  148. }
  149. return TRUE;
  150. }
  151. BOOL
  152. IsInternetDriver(
  153. HDEVINFO hDeviceInfo,
  154. PSP_DEVINFO_DATA DeviceInfoData
  155. )
  156. {
  157. BOOL InternetDriver = FALSE;
  158. SP_DRVINFO_DATA DriverInfoData;
  159. SP_DRVINSTALL_PARAMS DriverInstallParams;
  160. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  161. if(SetupDiGetSelectedDriver(hDeviceInfo, DeviceInfoData, &DriverInfoData)) {
  162. DriverInstallParams.cbSize = sizeof(SP_DRVINSTALL_PARAMS);
  163. if (SetupDiGetDriverInstallParams(hDeviceInfo,
  164. DeviceInfoData,
  165. &DriverInfoData,
  166. &DriverInstallParams
  167. )
  168. &&
  169. (DriverInstallParams.Flags & DNF_INET_DRIVER))
  170. {
  171. InternetDriver = TRUE;
  172. }
  173. }
  174. return InternetDriver;
  175. }
  176. UINT
  177. QueueCallback(
  178. IN PVOID Context,
  179. IN UINT Notification,
  180. IN UINT_PTR Param1,
  181. IN UINT_PTR Param2
  182. )
  183. {
  184. PNEWDEVWIZ NewDevWiz = (PNEWDEVWIZ)Context;
  185. switch (Notification) {
  186. case SPFILENOTIFY_TARGETNEWER:
  187. //
  188. // When doing a driver rollback we expect that some of the files will
  189. // be older then the files currently on the system since most backups
  190. // will be of older driver packages. So when a user does a rollback we
  191. // will hide the older vs. newer file prompt and always copy the older
  192. // backed up file.
  193. //
  194. if (NewDevWiz->Flags & IDI_FLAG_ROLLBACK) {
  195. return TRUE;
  196. }
  197. break;
  198. case SPFILENOTIFY_STARTCOPY:
  199. if (NewDevWiz->hWnd) {
  200. SendMessage(NewDevWiz->hWnd,
  201. WUM_INSTALLPROGRESS,
  202. INSTALLOP_COPY,
  203. (WPARAM)((PFILEPATHS)Param1)
  204. );
  205. }
  206. break;
  207. case SPFILENOTIFY_STARTRENAME:
  208. if (NewDevWiz->hWnd) {
  209. SendMessage(NewDevWiz->hWnd,
  210. WUM_INSTALLPROGRESS,
  211. INSTALLOP_RENAME,
  212. (WPARAM)((PFILEPATHS)Param1)
  213. );
  214. }
  215. break;
  216. case SPFILENOTIFY_STARTDELETE:
  217. if (NewDevWiz->hWnd) {
  218. SendMessage(NewDevWiz->hWnd,
  219. WUM_INSTALLPROGRESS,
  220. INSTALLOP_DELETE,
  221. (WPARAM)((PFILEPATHS)Param1)
  222. );
  223. }
  224. break;
  225. case SPFILENOTIFY_STARTBACKUP:
  226. if (NewDevWiz->hWnd) {
  227. SendMessage(NewDevWiz->hWnd,
  228. WUM_INSTALLPROGRESS,
  229. INSTALLOP_BACKUP,
  230. (WPARAM)((PFILEPATHS)Param1)
  231. );
  232. }
  233. break;
  234. }
  235. return SetupDefaultQueueCallback(NewDevWiz->MessageHandlerContext,
  236. Notification,
  237. Param1,
  238. Param2
  239. );
  240. }
  241. LONG
  242. ClassInstallerInstalls(
  243. HWND hwndParent,
  244. PNEWDEVWIZ NewDevWiz,
  245. BOOL BackupOldDrivers,
  246. BOOL ReadOnlyInstall,
  247. BOOL DontCreateQueue
  248. )
  249. {
  250. DWORD Err = ERROR_SUCCESS;
  251. HSPFILEQ FileQueue = INVALID_HANDLE_VALUE;
  252. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  253. DWORD ScanResult = 0;
  254. int FileQueueNeedsReboot = 0;
  255. NewDevWiz->MessageHandlerContext = NULL;
  256. //
  257. // If we can't create our own queue and we are doing a read-only install
  258. // then fail with ERROR_ACCESS_DENIED.
  259. //
  260. if (DontCreateQueue && ReadOnlyInstall) {
  261. Err = ERROR_ACCESS_DENIED;
  262. goto clean0;
  263. }
  264. //
  265. // verify with class installer, and class-specific coinstallers
  266. // that the driver is not blacklisted. For DIF_ALLOW_INSTALL we
  267. // accept ERROR_SUCCESS or ERROR_DI_DO_DEFAULT as good return codes.
  268. //
  269. if (!SetupDiCallClassInstaller(DIF_ALLOW_INSTALL,
  270. NewDevWiz->hDeviceInfo,
  271. &NewDevWiz->DeviceInfoData
  272. ) &&
  273. (GetLastError() != ERROR_DI_DO_DEFAULT)) {
  274. Err = GetLastError();
  275. goto clean0;
  276. }
  277. //
  278. // Create our own queue.
  279. //
  280. if (!DontCreateQueue) {
  281. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  282. if (!SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  283. &NewDevWiz->DeviceInfoData,
  284. &DeviceInstallParams
  285. )) {
  286. Err = GetLastError();
  287. goto clean0;
  288. }
  289. FileQueue = SetupOpenFileQueue();
  290. if (FileQueue == INVALID_HANDLE_VALUE) {
  291. Err = ERROR_NOT_ENOUGH_MEMORY;
  292. goto clean0;
  293. }
  294. DeviceInstallParams.Flags |= DI_NOVCP;
  295. DeviceInstallParams.FileQueue = FileQueue;
  296. //
  297. // Only set the DI_FLAGSEX_PREINSTALLBACKUP flag if we are doing a
  298. // backup...not in the read only install case.
  299. //
  300. if (BackupOldDrivers) {
  301. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_PREINSTALLBACKUP;
  302. }
  303. SetupDiSetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  304. &NewDevWiz->DeviceInfoData,
  305. &DeviceInstallParams
  306. );
  307. //
  308. // If the IDI_FLAG_SETRESTOREPOINT flag is set then we want to set the
  309. // SPQ_FLAG_ABORT_IF_UNSIGNED value on the file queue. With this flag
  310. // setup setupapi will bail out of the copy if it encounters an unsigned
  311. // file. At that point we will set a system restore point and then
  312. // do the copy. This way the user can back out of an unsigned driver
  313. // install using system restore.
  314. //
  315. // Note that system restore is currently not supported on 64-bit so
  316. // don't bother setting the SPQ_FLAG_ABORT_IF_UNSIGNED flag.
  317. //
  318. #ifndef _WIN64
  319. if (NewDevWiz->Flags & IDI_FLAG_SETRESTOREPOINT) {
  320. SetupSetFileQueueFlags(FileQueue,
  321. SPQ_FLAG_ABORT_IF_UNSIGNED,
  322. SPQ_FLAG_ABORT_IF_UNSIGNED
  323. );
  324. }
  325. #endif
  326. }
  327. //
  328. // Install the files first in one shot.
  329. // This allows new coinstallers to run during the install.
  330. //
  331. if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICEFILES,
  332. NewDevWiz->hDeviceInfo,
  333. &NewDevWiz->DeviceInfoData
  334. )) {
  335. Err = GetLastError();
  336. goto clean0;
  337. }
  338. if (FileQueue != INVALID_HANDLE_VALUE) {
  339. //
  340. // If we created our own FileQueue then we need to
  341. // scan and possibly commit the queue
  342. //
  343. // If we are doing a read only install then we just queued up the files so
  344. // that we could do a presence check on them. We will throw away the queue
  345. // so that the files are not copied.
  346. //
  347. // Any other install, prune copies as needed
  348. //
  349. if (!SetupScanFileQueue(FileQueue,
  350. ReadOnlyInstall
  351. ? SPQ_SCAN_FILE_PRESENCE
  352. : (SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_PRUNE_COPY_QUEUE),
  353. hwndParent,
  354. NULL,
  355. NULL,
  356. &ScanResult
  357. )) {
  358. //
  359. // If the API failed then set the ScanResult to 0 (failure).
  360. //
  361. ScanResult = 0;
  362. }
  363. if (ReadOnlyInstall && (ScanResult != 1)) {
  364. //
  365. // ReadOnlyInstall cannot perform copies, deletes or renames
  366. // bail now!
  367. //
  368. Err = ERROR_ACCESS_DENIED;
  369. goto clean0;
  370. }
  371. //
  372. // We will always commit the file queue, even if we pruned all of the
  373. // files. The reason for this is that backing up of drivers, for
  374. // driver rollback, won't work unless the file queue is committed.
  375. //
  376. if(NewDevWiz->Flags & IDI_FLAG_ROLLBACK) {
  377. //
  378. // Prepare file queue for rollback
  379. // we need the directory of the INF
  380. // that's being used for the install
  381. //
  382. SP_DRVINFO_DATA DriverInfoData;
  383. SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
  384. DWORD RetVal;
  385. LPTSTR pFileName;
  386. TCHAR BackupPath[MAX_PATH];
  387. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  388. if (SetupDiGetSelectedDriver(NewDevWiz->hDeviceInfo,
  389. &NewDevWiz->DeviceInfoData,
  390. &DriverInfoData)) {
  391. DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  392. if (SetupDiGetDriverInfoDetail(NewDevWiz->hDeviceInfo,
  393. &NewDevWiz->DeviceInfoData,
  394. &DriverInfoData,
  395. &DriverInfoDetailData,
  396. sizeof(SP_DRVINFO_DETAIL_DATA),
  397. NULL) ||
  398. (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
  399. //
  400. // we now have path of INF we're using for the restore
  401. //
  402. RetVal = GetFullPathName(DriverInfoDetailData.InfFileName,
  403. MAX_PATH,
  404. BackupPath,
  405. &pFileName);
  406. if(RetVal && pFileName && (pFileName != BackupPath)) {
  407. if(*CharPrev(BackupPath,pFileName)==TEXT('\\')) {
  408. pFileName--;
  409. }
  410. *pFileName = TEXT('\0');
  411. //
  412. // Prepare queue for rollback
  413. // if this fails, carry on, it'll work in a degraded way
  414. //
  415. SetupPrepareQueueForRestore(FileQueue,BackupPath,0);
  416. }
  417. }
  418. }
  419. }
  420. NewDevWiz->MessageHandlerContext = SetupInitDefaultQueueCallbackEx(
  421. hwndParent,
  422. (DeviceInstallParams.Flags & DI_QUIETINSTALL)
  423. ? INVALID_HANDLE_VALUE : NewDevWiz->hWnd,
  424. WUM_INSTALLPROGRESS,
  425. 0,
  426. NULL
  427. );
  428. if (NewDevWiz->MessageHandlerContext) {
  429. //
  430. // Commit the file queue.
  431. //
  432. if (!SetupCommitFileQueue(hwndParent,
  433. FileQueue,
  434. QueueCallback,
  435. (PVOID)NewDevWiz
  436. )) {
  437. Err = GetLastError();
  438. if (Err == ERROR_SET_SYSTEM_RESTORE_POINT) {
  439. UINT RestorePointResourceId;
  440. //
  441. // If we get back ERROR_SET_SYSTEM_RESTORE_POINT then
  442. // we better have the IDI_FLAG_SETRESTOREPOINT flag
  443. // set.
  444. //
  445. ASSERT(NewDevWiz->Flags & IDI_FLAG_SETRESTOREPOINT);
  446. if (!(DeviceInstallParams.Flags & DI_QUIETINSTALL) &&
  447. NewDevWiz->hWnd) {
  448. PostMessage(NewDevWiz->hWnd,
  449. WUM_INSTALLPROGRESS,
  450. INSTALLOP_SETTEXT,
  451. (LPARAM)IDS_SYSTEMRESTORE_TEXT
  452. );
  453. }
  454. SetupTermDefaultQueueCallback(NewDevWiz->MessageHandlerContext);
  455. NewDevWiz->MessageHandlerContext = SetupInitDefaultQueueCallbackEx(
  456. hwndParent,
  457. (DeviceInstallParams.Flags & DI_QUIETINSTALL)
  458. ? INVALID_HANDLE_VALUE : NewDevWiz->hWnd,
  459. WUM_INSTALLPROGRESS,
  460. 0,
  461. NULL
  462. );
  463. if (NewDevWiz->MessageHandlerContext) {
  464. //
  465. // Set the system restore point.
  466. //
  467. if (NewDevWiz->Flags & IDI_FLAG_ROLLBACK) {
  468. RestorePointResourceId = IDS_ROLLBACK_SETRESTOREPOINT;
  469. } else if (NewDevWiz->InstallType == NDWTYPE_FOUNDNEW) {
  470. RestorePointResourceId = IDS_NEW_SETRESTOREPOINT;
  471. } else {
  472. RestorePointResourceId = IDS_UPDATE_SETRESTOREPOINT;
  473. }
  474. pSetSystemRestorePoint(TRUE, FALSE, RestorePointResourceId);
  475. NewDevWiz->SetRestorePoint = TRUE;
  476. if (!(DeviceInstallParams.Flags & DI_QUIETINSTALL) &&
  477. NewDevWiz->hWnd) {
  478. PostMessage(NewDevWiz->hWnd,
  479. WUM_INSTALLPROGRESS,
  480. INSTALLOP_SETTEXT,
  481. (LPARAM)NULL
  482. );
  483. }
  484. //
  485. // Clear the SPQ_FLAG_ABORT_IF_UNSIGNED flag so the file
  486. // queue will be commited the next time.
  487. //
  488. SetupSetFileQueueFlags(FileQueue,
  489. SPQ_FLAG_ABORT_IF_UNSIGNED,
  490. 0
  491. );
  492. //
  493. // Now that we have set the restore point and cleared the
  494. // SPQ_FLAG_ABORT_IF_UNSIGNED flag from the file queue we
  495. // can commit the queue again.
  496. //
  497. if (!SetupCommitFileQueue(hwndParent,
  498. FileQueue,
  499. QueueCallback,
  500. (PVOID)NewDevWiz
  501. )) {
  502. Err = GetLastError();
  503. //
  504. // If the error we get is ERROR_CANCELLED then
  505. // the user has canceld out of the file copy.
  506. // This means that no changes have been made
  507. // to the system, so we will tell system
  508. // restore to cancel its restore point.
  509. //
  510. // Also clear the SetRestorePoint BOOL since
  511. // we didn't actually set a restore point.
  512. //
  513. if (Err == ERROR_CANCELLED) {
  514. pSetSystemRestorePoint(FALSE, TRUE, 0);
  515. NewDevWiz->SetRestorePoint = FALSE;
  516. }
  517. goto clean0;
  518. } else {
  519. //
  520. // We were successful in commiting the file queue, so check
  521. // to see whether a reboot is required as a result of committing
  522. // the queue (i.e. because files were in use, or the INF requested
  523. // a reboot).
  524. //
  525. FileQueueNeedsReboot = SetupPromptReboot(FileQueue, NULL, TRUE);
  526. }
  527. }
  528. } else {
  529. goto clean0;
  530. }
  531. } else {
  532. //
  533. // We were successful in commiting the file queue, so check
  534. // to see whether a reboot is required as a result of committing
  535. // the queue (i.e. because files were in use, or the INF requested
  536. // a reboot).
  537. //
  538. FileQueueNeedsReboot = SetupPromptReboot(FileQueue, NULL, TRUE);
  539. }
  540. }
  541. if (BackupOldDrivers) {
  542. //
  543. // If the backup succeeded and we have a UpdateDriverInfo structure
  544. // then we need to call SetupGetBackupInformation so we can get the
  545. // registry key that the backup was saved into.
  546. //
  547. SP_BACKUP_QUEUE_PARAMS BackupQueueParams;
  548. BackupQueueParams.cbSize = sizeof(SP_BACKUP_QUEUE_PARAMS);
  549. if (NewDevWiz->UpdateDriverInfo &&
  550. SetupGetBackupInformation(FileQueue, &BackupQueueParams)) {
  551. lstrcpy(NewDevWiz->UpdateDriverInfo->BackupRegistryKey, REGSTR_PATH_REINSTALL);
  552. lstrcat(NewDevWiz->UpdateDriverInfo->BackupRegistryKey, TEXT("\\"));
  553. lstrcat(NewDevWiz->UpdateDriverInfo->BackupRegistryKey, BackupQueueParams.ReinstallInstance);
  554. }
  555. }
  556. }
  557. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  558. if (SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  559. &NewDevWiz->DeviceInfoData,
  560. &DeviceInstallParams
  561. )) {
  562. DWORD FileQueueFlags;
  563. //
  564. // If we didn't copy any files when commiting the file queue then the
  565. // SPQ_FLAG_FILES_MODIFIED flag will NOT be set. In this case set
  566. // the DI_FLAGSEX_RESTART_DEVICE_ONLY flag so that we only stop/start
  567. // this single device. By default setupapi will stop/start this device
  568. // as well as any other device that was using the same driver/filter
  569. // that this device is using.
  570. //
  571. if ((FileQueue != INVALID_HANDLE_VALUE) &&
  572. SetupGetFileQueueFlags(FileQueue, &FileQueueFlags) &&
  573. !(FileQueueFlags & SPQ_FLAG_FILES_MODIFIED)) {
  574. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_RESTART_DEVICE_ONLY;
  575. }
  576. //
  577. // Set the DI_NOFILECOPY flag since we already copied the files during
  578. // the DIF_INSTALLDEVICEFILES, so we don't need to copy them again during
  579. // the DIF_INSTALLDEVICE.
  580. //
  581. DeviceInstallParams.Flags |= DI_NOFILECOPY;
  582. SetupDiSetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  583. &NewDevWiz->DeviceInfoData,
  584. &DeviceInstallParams
  585. );
  586. }
  587. //
  588. // Register any device-specific co-installers for this device,
  589. //
  590. if (!SetupDiCallClassInstaller(DIF_REGISTER_COINSTALLERS,
  591. NewDevWiz->hDeviceInfo,
  592. &NewDevWiz->DeviceInfoData
  593. )) {
  594. Err = GetLastError();
  595. goto clean0;
  596. }
  597. //
  598. // install any INF/class installer-specified interfaces.
  599. // and then finally the real "InstallDevice"!
  600. //
  601. if (!SetupDiCallClassInstaller(DIF_INSTALLINTERFACES,
  602. NewDevWiz->hDeviceInfo,
  603. &NewDevWiz->DeviceInfoData
  604. )
  605. ||
  606. !SetupDiCallClassInstaller(DIF_INSTALLDEVICE,
  607. NewDevWiz->hDeviceInfo,
  608. &NewDevWiz->DeviceInfoData
  609. )) {
  610. Err = GetLastError();
  611. goto clean0;
  612. }
  613. Err = ERROR_SUCCESS;
  614. clean0:
  615. if (NewDevWiz->MessageHandlerContext) {
  616. SetupTermDefaultQueueCallback(NewDevWiz->MessageHandlerContext);
  617. }
  618. //
  619. // If the file queue said that a reboot was needed then set the
  620. // DI_NEEDRESTART flag.
  621. //
  622. if (FileQueueNeedsReboot) {
  623. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  624. if (SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  625. &NewDevWiz->DeviceInfoData,
  626. &DeviceInstallParams
  627. )) {
  628. DeviceInstallParams.Flags |= DI_NEEDRESTART;
  629. SetupDiSetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  630. &NewDevWiz->DeviceInfoData,
  631. &DeviceInstallParams
  632. );
  633. }
  634. }
  635. if (FileQueue != INVALID_HANDLE_VALUE) {
  636. //
  637. // If we have a valid file queue handle and there was an error during
  638. // the device install then we want to delete any new INFs that were
  639. // copied into the INF directory. We do this under the assumption that
  640. // since there was an error during the install these INFs must be bad.
  641. //
  642. if (Err != ERROR_SUCCESS) {
  643. SetupUninstallNewlyCopiedInfs(FileQueue,
  644. 0,
  645. NULL
  646. );
  647. }
  648. //
  649. // Clear out our file queue from the device install params. We need
  650. // to do this or else SetupCloseFileQueue will fail because it will
  651. // still have a ref count.
  652. //
  653. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  654. if (SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  655. &NewDevWiz->DeviceInfoData,
  656. &DeviceInstallParams
  657. )) {
  658. DeviceInstallParams.Flags &= ~DI_NOVCP;
  659. DeviceInstallParams.FileQueue = INVALID_HANDLE_VALUE;
  660. SetupDiSetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  661. &NewDevWiz->DeviceInfoData,
  662. &DeviceInstallParams
  663. );
  664. }
  665. SetupCloseFileQueue(FileQueue);
  666. }
  667. return Err;
  668. }
  669. //
  670. // invokable only from finish page!
  671. //
  672. DWORD
  673. InstallDev(
  674. HWND hwndParent,
  675. PNEWDEVWIZ NewDevWiz
  676. )
  677. {
  678. SP_DRVINFO_DATA DriverInfoData;
  679. SP_DRVINFO_DETAIL_DATA DriverInfoDetailData;
  680. SP_DEVINSTALL_PARAMS DeviceInstallParams;
  681. TCHAR ClassGuidString[MAX_GUID_STRING_LEN];
  682. GUID ClassGuidInf;
  683. LPGUID ClassGuid;
  684. int ClassGuidNum;
  685. DWORD Error = ERROR_SUCCESS;
  686. BOOL IgnoreRebootFlags = FALSE;
  687. TCHAR Buffer[MAX_PATH*2];
  688. PVOID pvBuffer = Buffer;
  689. ULONG DevNodeStatus = 0, Problem = 0;
  690. DWORD ClassGuidListSize, i;
  691. BOOL Backup = FALSE;
  692. BOOL DontCreateQueue = FALSE;
  693. if (!NewDevWiz->ClassGuidSelected)
  694. {
  695. NewDevWiz->ClassGuidSelected = (LPGUID)&GUID_NULL;
  696. }
  697. DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
  698. if (SetupDiGetSelectedDriver(NewDevWiz->hDeviceInfo,
  699. &NewDevWiz->DeviceInfoData,
  700. &DriverInfoData
  701. ))
  702. {
  703. //
  704. // Get details on this driver node, so that we can examine the INF that this
  705. // node came from.
  706. //
  707. DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
  708. if(!SetupDiGetDriverInfoDetail(NewDevWiz->hDeviceInfo,
  709. &NewDevWiz->DeviceInfoData,
  710. &DriverInfoData,
  711. &DriverInfoDetailData,
  712. sizeof(DriverInfoDetailData),
  713. NULL
  714. ))
  715. {
  716. Error = GetLastError();
  717. if (Error != ERROR_INSUFFICIENT_BUFFER)
  718. {
  719. goto clean0;
  720. }
  721. }
  722. //
  723. // Verif that the class is installed, if its not then
  724. // attempt to install it.
  725. //
  726. NdwBuildClassInfoList(NewDevWiz, 0);
  727. //
  728. // fetch classguid from inf, (It may be different than what we already
  729. // have in class guid selected).
  730. //
  731. if (!GetClassGuidForInf(DriverInfoDetailData.InfFileName, &ClassGuidInf))
  732. {
  733. ClassGuidInf = *NewDevWiz->ClassGuidSelected;
  734. }
  735. if (IsEqualGUID(&ClassGuidInf, &GUID_NULL))
  736. {
  737. ClassGuidInf = GUID_DEVCLASS_UNKNOWN;
  738. }
  739. //
  740. // if the ClassGuidInf wasn't found then this class hasn't been installed yet.
  741. // -install the class installer now.
  742. //
  743. ClassGuid = NewDevWiz->ClassGuidList;
  744. ClassGuidNum = NewDevWiz->ClassGuidNum;
  745. while (ClassGuidNum--)
  746. {
  747. if (IsEqualGUID(ClassGuid, &ClassGuidInf))
  748. {
  749. break;
  750. }
  751. ClassGuid++;
  752. }
  753. if (ClassGuidNum < 0 &&
  754. !SetupDiInstallClass(hwndParent,
  755. DriverInfoDetailData.InfFileName,
  756. NewDevWiz->SilentMode ? DI_QUIETINSTALL : 0,
  757. NULL
  758. ))
  759. {
  760. Error = GetLastError();
  761. goto clean0;
  762. }
  763. }
  764. //
  765. // No selected driver, and no associated class--use "Unknown" class.
  766. //
  767. else
  768. {
  769. //
  770. // If the devnode is currently running 'raw', then remember this
  771. // fact so that we don't require a reboot later (NULL driver installation
  772. // isn't going to change anything).
  773. //
  774. if (CM_Get_DevNode_Status(&DevNodeStatus,
  775. &Problem,
  776. NewDevWiz->DeviceInfoData.DevInst,
  777. 0) == CR_SUCCESS)
  778. {
  779. if (!SetupDiGetDeviceRegistryProperty(NewDevWiz->hDeviceInfo,
  780. &NewDevWiz->DeviceInfoData,
  781. SPDRP_SERVICE,
  782. NULL, // regdatatype
  783. pvBuffer,
  784. sizeof(Buffer),
  785. NULL
  786. ))
  787. {
  788. *Buffer = TEXT('\0');
  789. }
  790. if((DevNodeStatus & DN_STARTED) && (*Buffer == TEXT('\0')))
  791. {
  792. IgnoreRebootFlags = TRUE;
  793. }
  794. }
  795. if (IsEqualGUID(NewDevWiz->ClassGuidSelected, &GUID_NULL))
  796. {
  797. pSetupStringFromGuid(&GUID_DEVCLASS_UNKNOWN,
  798. ClassGuidString,
  799. sizeof(ClassGuidString)/sizeof(TCHAR)
  800. );
  801. SetupDiSetDeviceRegistryProperty(NewDevWiz->hDeviceInfo,
  802. &NewDevWiz->DeviceInfoData,
  803. SPDRP_CLASSGUID,
  804. (PBYTE)ClassGuidString,
  805. sizeof(ClassGuidString)
  806. );
  807. }
  808. ClassGuidInf = *NewDevWiz->ClassGuidSelected;
  809. }
  810. //
  811. // We will backup the current drivers in all cases except if any of the following are true:
  812. //
  813. // 1) The device is a printer
  814. // 2) The selected driver is the currently installed driver
  815. // 3) The DontBackupCurrentDrivers NEWDEVWIZ BOOL is TRUE
  816. // 4) The device has a problem
  817. //
  818. if (IsEqualGUID(&ClassGuidInf, &GUID_DEVCLASS_PRINTER) ||
  819. IsInstalledDriver(NewDevWiz, NULL) ||
  820. (NewDevWiz->Flags & IDI_FLAG_NOBACKUP) ||
  821. ((CM_Get_DevNode_Status(&DevNodeStatus, &Problem, NewDevWiz->DeviceInfoData.DevInst, 0) == CR_SUCCESS) &&
  822. ((DevNodeStatus & DN_HAS_PROBLEM) ||
  823. (DevNodeStatus & DN_PRIVATE_PROBLEM)))) {
  824. Backup = FALSE;
  825. } else {
  826. Backup = TRUE;
  827. }
  828. //
  829. // We will always create our own queue during device install, except in the
  830. // following specific cases.
  831. //
  832. // 1) The device is a printer
  833. //
  834. // Note that if we can't create our own queue then we cannot do any of the
  835. // operations that need a queue, like backup, rollback, read-only install,
  836. // or setting a restore point.
  837. //
  838. DontCreateQueue = IsEqualGUID(&ClassGuidInf, & GUID_DEVCLASS_PRINTER);
  839. Error = ClassInstallerInstalls(hwndParent,
  840. NewDevWiz,
  841. Backup,
  842. (NewDevWiz->Flags & IDI_FLAG_READONLY_INSTALL),
  843. DontCreateQueue
  844. );
  845. //
  846. // If this is a WU/CDM install and it was successful then set
  847. // the DriverWasUpgraded to TRUE
  848. //
  849. if (NewDevWiz->UpdateDriverInfo && (Error == ERROR_SUCCESS)) {
  850. NewDevWiz->UpdateDriverInfo->DriverWasUpgraded = TRUE;
  851. }
  852. //
  853. // If this is a new device (currently no drivers are installed) and we encounter
  854. // an error that is not ERROR_CANCELLED then we will install the NULL driver for
  855. // this device and set the FAILED INSTALL flag.
  856. //
  857. if ((Error != ERROR_SUCCESS) &&
  858. (Error != ERROR_CANCELLED))
  859. {
  860. if (IsNullDriverInstalled(NewDevWiz->DeviceInfoData.DevInst)) {
  861. if (SetupDiSetSelectedDriver(NewDevWiz->hDeviceInfo,
  862. &NewDevWiz->DeviceInfoData,
  863. NULL
  864. ))
  865. {
  866. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  867. if (SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  868. &NewDevWiz->DeviceInfoData,
  869. &DeviceInstallParams
  870. ))
  871. {
  872. DeviceInstallParams.FlagsEx |= DI_FLAGSEX_SETFAILEDINSTALL;
  873. SetupDiSetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  874. &NewDevWiz->DeviceInfoData,
  875. &DeviceInstallParams
  876. );
  877. }
  878. SetupDiInstallDevice(NewDevWiz->hDeviceInfo, &NewDevWiz->DeviceInfoData);
  879. }
  880. }
  881. goto clean0;
  882. }
  883. //
  884. // See if the device needs to the system to be restarted before it will work.
  885. //
  886. if(!IgnoreRebootFlags) {
  887. DeviceInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  888. if (SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  889. &NewDevWiz->DeviceInfoData,
  890. &DeviceInstallParams
  891. ) &&
  892. (DeviceInstallParams.Flags & (DI_NEEDRESTART | DI_NEEDREBOOT))) {
  893. //
  894. // If either the DI_NEEDRESTART or the DI_NEEDREBOOT DeviceInstallParams
  895. // flag is set, then a restart is needed.
  896. //
  897. NewDevWiz->Reboot |= DI_NEEDREBOOT;
  898. } else if ((CM_Get_DevNode_Status(&DevNodeStatus,
  899. &Problem,
  900. NewDevWiz->DeviceInfoData.DevInst,
  901. 0) == CR_SUCCESS) &&
  902. (DevNodeStatus & DN_NEED_RESTART) ||
  903. (Problem == CM_PROB_NEED_RESTART)) {
  904. //
  905. // If the DN_NEED_RESTART devnode status flag is set, then a restart
  906. // is needed.
  907. //
  908. NewDevWiz->Reboot |= DI_NEEDREBOOT;
  909. }
  910. }
  911. clean0:
  912. return Error;
  913. }
  914. DWORD
  915. InstallNullDriver(
  916. HWND hDlg,
  917. PNEWDEVWIZ NewDevWiz,
  918. BOOL FailedInstall
  919. )
  920. {
  921. SP_DEVINSTALL_PARAMS DevInstallParams;
  922. DWORD Err = ERROR_SUCCESS;
  923. DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  924. //
  925. // Set the DI_FLAGSEX_SETFAILEDINSTALL flag if this is a failed
  926. // install.
  927. //
  928. if (FailedInstall)
  929. {
  930. if (SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  931. &NewDevWiz->DeviceInfoData,
  932. &DevInstallParams
  933. ))
  934. {
  935. DevInstallParams.FlagsEx |= DI_FLAGSEX_SETFAILEDINSTALL;
  936. SetupDiSetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  937. &NewDevWiz->DeviceInfoData,
  938. &DevInstallParams
  939. );
  940. }
  941. }
  942. //
  943. // Set the selected driver to NULL
  944. //
  945. if (SetupDiSetSelectedDriver(NewDevWiz->hDeviceInfo,
  946. &NewDevWiz->DeviceInfoData,
  947. NULL
  948. ))
  949. {
  950. //
  951. // verify with class installer, and class-specific coinstallers
  952. // that the driver is not blacklisted. For DIF_ALLOW_INSTALL we
  953. // accept ERROR_SUCCESS or ERROR_DI_DO_DEFAULT as good return codes.
  954. //
  955. if (SetupDiCallClassInstaller(DIF_ALLOW_INSTALL,
  956. NewDevWiz->hDeviceInfo,
  957. &NewDevWiz->DeviceInfoData
  958. ) ||
  959. (GetLastError() == ERROR_DI_DO_DEFAULT)) {
  960. //
  961. // If the class/co-installers gave the OK then call DIF_INSTALLDEVICE.
  962. //
  963. if (!SetupDiCallClassInstaller(DIF_INSTALLDEVICE,
  964. NewDevWiz->hDeviceInfo,
  965. &NewDevWiz->DeviceInfoData
  966. )) {
  967. Err = GetLastError();
  968. }
  969. } else {
  970. Err = GetLastError();
  971. }
  972. }
  973. return Err;
  974. } // InstallNullDriver
  975. BOOL
  976. CALLBACK
  977. AddPropSheetPageProc(
  978. IN HPROPSHEETPAGE hpage,
  979. IN LPARAM lParam
  980. )
  981. {
  982. *((HPROPSHEETPAGE *)lParam) = hpage;
  983. return TRUE;
  984. }
  985. void
  986. DisplayResource(
  987. PNEWDEVWIZ NewDevWiz,
  988. HWND hWndParent
  989. )
  990. {
  991. HINSTANCE hLib;
  992. PROPSHEETHEADER psh;
  993. HPROPSHEETPAGE hpsPages[1];
  994. SP_PROPSHEETPAGE_REQUEST PropPageRequest;
  995. LPFNADDPROPSHEETPAGES ExtensionPropSheetPage = NULL;
  996. LPTSTR Title;
  997. SP_DEVINSTALL_PARAMS DevInstallParams;
  998. //
  999. // Now get the resource selection page from setupapi.dll
  1000. //
  1001. hLib = GetModuleHandle(TEXT("setupapi.dll"));
  1002. if (hLib)
  1003. {
  1004. ExtensionPropSheetPage = (PVOID)GetProcAddress(hLib, "ExtensionPropSheetPageProc");
  1005. }
  1006. if (!ExtensionPropSheetPage)
  1007. {
  1008. return;
  1009. }
  1010. PropPageRequest.cbSize = sizeof(SP_PROPSHEETPAGE_REQUEST);
  1011. PropPageRequest.PageRequested = SPPSR_SELECT_DEVICE_RESOURCES;
  1012. PropPageRequest.DeviceInfoSet = NewDevWiz->hDeviceInfo;
  1013. PropPageRequest.DeviceInfoData = &NewDevWiz->DeviceInfoData;
  1014. if (!ExtensionPropSheetPage(&PropPageRequest,
  1015. AddPropSheetPageProc,
  1016. (LONG_PTR)hpsPages
  1017. ))
  1018. {
  1019. // warning ?
  1020. return;
  1021. }
  1022. //
  1023. // create the property sheet
  1024. //
  1025. psh.dwSize = sizeof(PROPSHEETHEADER);
  1026. psh.dwFlags = PSH_PROPTITLE | PSH_NOAPPLYNOW;
  1027. psh.hwndParent = hWndParent;
  1028. psh.hInstance = hNewDev;
  1029. psh.pszIcon = NULL;
  1030. switch (NewDevWiz->InstallType) {
  1031. case NDWTYPE_FOUNDNEW:
  1032. Title = (LPTSTR)IDS_FOUNDDEVICE;
  1033. break;
  1034. case NDWTYPE_UPDATE:
  1035. Title = (LPTSTR)IDS_UPDATEDEVICE;
  1036. break;
  1037. default:
  1038. Title = TEXT(""); // unknown
  1039. }
  1040. psh.pszCaption = Title;
  1041. psh.nPages = 1;
  1042. psh.phpage = hpsPages;
  1043. psh.nStartPage = 0;
  1044. psh.pfnCallback = NULL;
  1045. //
  1046. // Clear the Propchange pending bit in the DeviceInstall params.
  1047. //
  1048. DevInstallParams.cbSize = sizeof(SP_DEVINSTALL_PARAMS);
  1049. if (SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  1050. &NewDevWiz->DeviceInfoData,
  1051. &DevInstallParams
  1052. ))
  1053. {
  1054. DevInstallParams.FlagsEx &= ~DI_FLAGSEX_PROPCHANGE_PENDING;
  1055. SetupDiSetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  1056. &NewDevWiz->DeviceInfoData,
  1057. &DevInstallParams
  1058. );
  1059. }
  1060. if (PropertySheet(&psh) == -1)
  1061. {
  1062. DestroyPropertySheetPage(hpsPages[0]);
  1063. }
  1064. //
  1065. // If a PropChange occurred invoke the DIF_PROPERTYCHANGE
  1066. //
  1067. if (SetupDiGetDeviceInstallParams(NewDevWiz->hDeviceInfo,
  1068. &NewDevWiz->DeviceInfoData,
  1069. &DevInstallParams
  1070. ))
  1071. {
  1072. if (DevInstallParams.FlagsEx & DI_FLAGSEX_PROPCHANGE_PENDING)
  1073. {
  1074. SP_PROPCHANGE_PARAMS PropChangeParams;
  1075. PropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  1076. PropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
  1077. PropChangeParams.Scope = DICS_FLAG_GLOBAL;
  1078. PropChangeParams.HwProfile = 0;
  1079. if (SetupDiSetClassInstallParams(NewDevWiz->hDeviceInfo,
  1080. &NewDevWiz->DeviceInfoData,
  1081. (PSP_CLASSINSTALL_HEADER)&PropChangeParams,
  1082. sizeof(PropChangeParams)
  1083. ))
  1084. {
  1085. SetupDiCallClassInstaller(DIF_PROPERTYCHANGE,
  1086. NewDevWiz->hDeviceInfo,
  1087. &NewDevWiz->DeviceInfoData
  1088. );
  1089. }
  1090. //
  1091. // Clear the class install parameters.
  1092. //
  1093. SetupDiSetClassInstallParams(NewDevWiz->hDeviceInfo,
  1094. &NewDevWiz->DeviceInfoData,
  1095. NULL,
  1096. 0
  1097. );
  1098. }
  1099. }
  1100. return;
  1101. }
  1102. DWORD WINAPI
  1103. InstallDevThreadProc(
  1104. LPVOID lpVoid
  1105. )
  1106. /*++
  1107. Description:
  1108. In the Wizard, we will do the driver installation in a separate thread so that the user
  1109. will see the driver instal wizard page.
  1110. --*/
  1111. {
  1112. PNEWDEVWIZ NewDevWiz = (PNEWDEVWIZ)lpVoid;
  1113. //
  1114. // Do the device install
  1115. //
  1116. NewDevWiz->LastError = InstallDev(NewDevWiz->hWnd, NewDevWiz);
  1117. //
  1118. // Post a message to the window to let it know that we are finished with the install
  1119. //
  1120. PostMessage(NewDevWiz->hWnd, WUM_INSTALLCOMPLETE, TRUE, GetLastError());
  1121. return GetLastError();
  1122. }
  1123. INT_PTR CALLBACK
  1124. NDW_InstallDevDlgProc(
  1125. HWND hDlg,
  1126. UINT wMsg,
  1127. WPARAM wParam,
  1128. LPARAM lParam
  1129. )
  1130. {
  1131. HWND hwndParentDlg = GetParent(hDlg);
  1132. PNEWDEVWIZ NewDevWiz = (PNEWDEVWIZ)GetWindowLongPtr(hDlg, DWLP_USER);
  1133. LONG Error;
  1134. ULONG DevNodeStatus, Problem;
  1135. static HANDLE DeviceInstallThread = NULL;
  1136. TCHAR Text1[MAX_PATH], Text2[MAX_PATH], Target[MAX_PATH], Format[MAX_PATH];
  1137. PTSTR p;
  1138. switch (wMsg) {
  1139. case WM_INITDIALOG: {
  1140. LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam;
  1141. NewDevWiz = (PNEWDEVWIZ)lppsp->lParam;
  1142. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)NewDevWiz);
  1143. break;
  1144. }
  1145. case WM_DESTROY:
  1146. break;
  1147. case WUM_INSTALLCOMPLETE:
  1148. //
  1149. // This message is posted to the window when the device installation is complete.
  1150. //
  1151. WaitForSingleObject(DeviceInstallThread, INFINITE);
  1152. Animate_Stop(GetDlgItem(hDlg, IDC_ANIMATE_INSTALL));
  1153. NewDevWiz->CurrCursor = NULL;
  1154. PropSheet_PressButton(hwndParentDlg, PSBTN_NEXT);
  1155. break;
  1156. case WUM_INSTALLPROGRESS:
  1157. Text1[0] = Text2[0] = TEXT('\0');
  1158. //
  1159. // This is the message that is sent from setupapi so we can display our
  1160. // own copy progress.
  1161. //
  1162. // If wParam is 0 then the lParam is the number of files that will be
  1163. // copied.
  1164. // If wParam is 1 then that is a tick for a single file being copied,
  1165. // so the progress bar should be advanced.
  1166. //
  1167. switch (wParam) {
  1168. case 0:
  1169. ShowWindow(GetDlgItem(hDlg, IDC_PROGRESS_INSTALL), SW_SHOW);
  1170. ShowWindow(GetDlgItem(hDlg, IDC_FILECOPY_TEXT1), SW_SHOW);
  1171. ShowWindow(GetDlgItem(hDlg, IDC_FILECOPY_TEXT2), SW_SHOW);
  1172. ShowWindow(GetDlgItem(hDlg, IDC_STATUS_TEXT), SW_HIDE);
  1173. SetDlgItemText(hDlg, IDC_FILECOPY_TEXT1, TEXT(""));
  1174. SetDlgItemText(hDlg, IDC_FILECOPY_TEXT2, TEXT(""));
  1175. SendMessage(GetDlgItem(hDlg, IDC_PROGRESS_INSTALL), PBM_SETRANGE,0,MAKELPARAM(0,lParam));
  1176. SendMessage(GetDlgItem(hDlg, IDC_PROGRESS_INSTALL), PBM_SETSTEP,1,0);
  1177. SendMessage(GetDlgItem(hDlg, IDC_PROGRESS_INSTALL), PBM_SETPOS,0,0);
  1178. break;
  1179. case 1:
  1180. SendMessage(GetDlgItem(hDlg, IDC_PROGRESS_INSTALL), PBM_STEPIT,0,0);
  1181. break;
  1182. case INSTALLOP_COPY:
  1183. lstrcpyn(Target, ((PFILEPATHS)lParam)->Target, MAX_PATH);
  1184. if (p = _tcsrchr(Target,TEXT('\\'))) {
  1185. *p++ = 0;
  1186. lstrcpyn(Text1, p, MAX_PATH);
  1187. if (LoadString(hNewDev, IDS_FILEOP_TO, Format, SIZECHARS(Format))) {
  1188. _snwprintf(Text2, MAX_PATH, Format, Target);
  1189. }
  1190. } else {
  1191. lstrcpyn(Text1, ((PFILEPATHS)lParam)->Target, MAX_PATH);
  1192. lstrcpy(Text2, TEXT(""));
  1193. }
  1194. break;
  1195. case INSTALLOP_RENAME:
  1196. lstrcpyn(Text1, ((PFILEPATHS)lParam)->Source, MAX_PATH);
  1197. if (p = _tcsrchr(((PFILEPATHS)lParam)->Target, TEXT('\\'))) {
  1198. p++;
  1199. } else {
  1200. p = (PTSTR)((PFILEPATHS)lParam)->Target;
  1201. }
  1202. if (LoadString(hNewDev, IDS_FILEOP_TO, Format, SIZECHARS(Format))) {
  1203. _snwprintf(Text2, MAX_PATH, Format, p);
  1204. }
  1205. break;
  1206. case INSTALLOP_DELETE:
  1207. lstrcpyn(Target, ((PFILEPATHS)lParam)->Target, MAX_PATH);
  1208. if (p = _tcsrchr(Target,TEXT('\\'))) {
  1209. *p++ = 0;
  1210. lstrcpyn(Text1, p, MAX_PATH);
  1211. if (LoadString(hNewDev, IDS_FILEOP_FROM, Format, SIZECHARS(Format))) {
  1212. _snwprintf(Text2, MAX_PATH, Format, Target);
  1213. }
  1214. } else {
  1215. lstrcpyn(Text1, ((PFILEPATHS)lParam)->Target, MAX_PATH);
  1216. lstrcpy(Text2, TEXT(""));
  1217. }
  1218. break;
  1219. case INSTALLOP_BACKUP:
  1220. lstrcpyn(Target, ((PFILEPATHS)lParam)->Source, MAX_PATH);
  1221. if (p = _tcsrchr(Target,TEXT('\\'))) {
  1222. *p++ = 0;
  1223. if (((PFILEPATHS)lParam)->Target == NULL) {
  1224. if (LoadString(hNewDev, IDS_FILEOP_BACKUP, Format, SIZECHARS(Format))) {
  1225. _snwprintf(Text1, MAX_PATH, Format, p);
  1226. }
  1227. } else {
  1228. lstrcpyn(Text1, p, MAX_PATH);
  1229. }
  1230. lstrcpyn(Text2, Target, MAX_PATH);
  1231. } else {
  1232. if (LoadString(hNewDev, IDS_FILEOP_BACKUP, Format, SIZECHARS(Format))) {
  1233. _snwprintf(Text1, MAX_PATH, Format, Target);
  1234. }
  1235. lstrcpy(Text2, TEXT(""));
  1236. }
  1237. break;
  1238. case INSTALLOP_SETTEXT:
  1239. ShowWindow(GetDlgItem(hDlg, IDC_STATUS_TEXT), SW_SHOW);
  1240. ShowWindow(GetDlgItem(hDlg, IDC_PROGRESS_INSTALL), SW_HIDE);
  1241. ShowWindow(GetDlgItem(hDlg, IDC_FILECOPY_TEXT1), SW_HIDE);
  1242. if (lParam) {
  1243. if (LoadString(hNewDev, (UINT)lParam, Text2, SIZECHARS(Text2))) {
  1244. ShowWindow(GetDlgItem(hDlg, IDC_STATUS_TEXT), SW_SHOW);
  1245. SetDlgItemText(hDlg, IDC_STATUS_TEXT, Text2);
  1246. }
  1247. } else {
  1248. SetDlgItemText(hDlg, IDC_STATUS_TEXT, TEXT(""));
  1249. }
  1250. Text1[0] = TEXT('\0');
  1251. Text2[0] = TEXT('\0');
  1252. break;
  1253. }
  1254. if ((Text1[0] != TEXT('\0')) && (Text2[0] != TEXT('\0'))) {
  1255. ShowWindow(GetDlgItem(hDlg, IDC_STATUS_TEXT), SW_HIDE);
  1256. ShowWindow(GetDlgItem(hDlg, IDC_FILECOPY_TEXT1), SW_SHOW);
  1257. ShowWindow(GetDlgItem(hDlg, IDC_FILECOPY_TEXT2), SW_SHOW);
  1258. SetDlgItemText(hDlg, IDC_FILECOPY_TEXT1, Text1);
  1259. SetDlgItemText(hDlg, IDC_FILECOPY_TEXT2, Text2);
  1260. }
  1261. break;
  1262. case WM_NOTIFY:
  1263. switch (((NMHDR FAR *)lParam)->code) {
  1264. case PSN_SETACTIVE: {
  1265. HICON hicon;
  1266. SP_DRVINFO_DATA DriverInfoData;
  1267. NewDevWiz->PrevPage = IDD_NEWDEVWIZ_INSTALLDEV;
  1268. //
  1269. // This is an intermediary status page, no buttons needed.
  1270. // Set the device description
  1271. // Set the class Icon
  1272. //
  1273. PropSheet_SetWizButtons(hwndParentDlg, 0);
  1274. EnableWindow(GetDlgItem(GetParent(hDlg), IDCANCEL), FALSE);
  1275. ShowWindow(GetDlgItem(hDlg, IDC_PROGRESS_INSTALL), SW_HIDE);
  1276. ShowWindow(GetDlgItem(hDlg, IDC_FILECOPY_TEXT1), SW_HIDE);
  1277. ShowWindow(GetDlgItem(hDlg, IDC_FILECOPY_TEXT2), SW_HIDE);
  1278. ShowWindow(GetDlgItem(hDlg, IDC_STATUS_TEXT), SW_HIDE);
  1279. SetDriverDescription(hDlg, IDC_NDW_DESCRIPTION, NewDevWiz);
  1280. if (SetupDiLoadClassIcon(NewDevWiz->ClassGuidSelected, &hicon, NULL)) {
  1281. hicon = (HICON)SendDlgItemMessage(hDlg, IDC_CLASSICON, STM_SETICON, (WPARAM)hicon, 0L);
  1282. if (hicon) {
  1283. DestroyIcon(hicon);
  1284. }
  1285. }
  1286. NewDevWiz->CurrCursor = NewDevWiz->IdcWait;
  1287. SetCursor(NewDevWiz->CurrCursor);
  1288. //
  1289. // If we are doing a silent install then do the actual install here in the PSN_SETACTIVE.
  1290. // Doing the install here means that this wizard page will never be displayed. When we
  1291. // are finished calling InstallDev() then we will jump to any FinishInstall pages that
  1292. // the class/co-installers have added, or we will jump to our finish page.
  1293. //
  1294. if (NewDevWiz->SilentMode) {
  1295. //
  1296. // do the Install immediately and move to the next page
  1297. // to prevent any UI from showing.
  1298. //
  1299. NewDevWiz->hWnd = NULL;
  1300. NewDevWiz->LastError =InstallDev(hDlg, NewDevWiz);
  1301. NewDevWiz->CurrCursor = NULL;
  1302. //
  1303. // Add the FinishInstall Page and jump to it if the install was successful
  1304. //
  1305. if (NewDevWiz->LastError == ERROR_SUCCESS) {
  1306. NewDevWiz->WizExtFinishInstall.hPropSheet = CreateWizExtPage(IDD_WIZARDEXT_FINISHINSTALL,
  1307. WizExtFinishInstallDlgProc,
  1308. NewDevWiz
  1309. );
  1310. if (NewDevWiz->WizExtFinishInstall.hPropSheet) {
  1311. PropSheet_AddPage(hwndParentDlg, NewDevWiz->WizExtFinishInstall.hPropSheet);
  1312. }
  1313. SetDlgMsgResult(hDlg, wMsg, IDD_WIZARDEXT_FINISHINSTALL);
  1314. } else {
  1315. //
  1316. // There was an error during the install so just jump to our finish page
  1317. //
  1318. SetDlgMsgResult(hDlg, wMsg, -1);
  1319. }
  1320. }
  1321. //
  1322. // Post ourselves a msg, to do the actual install, this allows this
  1323. // page to show itself while the install is actually occuring.
  1324. //
  1325. else {
  1326. DWORD ThreadId;
  1327. NewDevWiz->hWnd = hDlg;
  1328. ShowWindow(GetDlgItem(hDlg, IDC_ANIMATE_INSTALL), SW_SHOW);
  1329. Animate_Open(GetDlgItem(hDlg, IDC_ANIMATE_INSTALL), MAKEINTRESOURCE(IDA_INSTALLING));
  1330. Animate_Play(GetDlgItem(hDlg, IDC_ANIMATE_INSTALL), 0, -1, -1);
  1331. //
  1332. // Start up a separate thread to do the device installation on.
  1333. // When the driver installation is complete the InstallDevThreadProc
  1334. // will post us a WUM_INSTALLCOMPLETE message.
  1335. //
  1336. DeviceInstallThread = CreateThread(NULL,
  1337. 0,
  1338. (LPTHREAD_START_ROUTINE)InstallDevThreadProc,
  1339. (LPVOID)NewDevWiz,
  1340. 0,
  1341. &ThreadId
  1342. );
  1343. //
  1344. // If the CreateThread fails then we will just call InstallDev() ourselves.
  1345. //
  1346. if (!DeviceInstallThread) {
  1347. NewDevWiz->hWnd = NULL;
  1348. //
  1349. // Do the device install
  1350. //
  1351. NewDevWiz->LastError = InstallDev(NewDevWiz->hWnd, NewDevWiz);
  1352. //
  1353. // Post a message to the window to let it know that we are finished with the install
  1354. //
  1355. PostMessage(hDlg, WUM_INSTALLCOMPLETE, TRUE, GetLastError());
  1356. }
  1357. }
  1358. break;
  1359. }
  1360. case PSN_WIZNEXT:
  1361. Animate_Stop(GetDlgItem(hDlg, IDC_ANIMATE_INSTALL));
  1362. //
  1363. // Add the FinishInstall Page and jump to it if the installation succeded.
  1364. //
  1365. if (NewDevWiz->LastError == ERROR_SUCCESS) {
  1366. NewDevWiz->WizExtFinishInstall.hPropSheet = CreateWizExtPage(IDD_WIZARDEXT_FINISHINSTALL,
  1367. WizExtFinishInstallDlgProc,
  1368. NewDevWiz
  1369. );
  1370. if (NewDevWiz->WizExtFinishInstall.hPropSheet) {
  1371. PropSheet_AddPage(hwndParentDlg, NewDevWiz->WizExtFinishInstall.hPropSheet);
  1372. }
  1373. SetDlgMsgResult(hDlg, wMsg, IDD_WIZARDEXT_FINISHINSTALL);
  1374. } else {
  1375. //
  1376. // There was an error during the install so just jump to our finish page
  1377. //
  1378. SetDlgMsgResult(hDlg, wMsg, IDD_NEWDEVWIZ_FINISH);
  1379. }
  1380. break;
  1381. }
  1382. break;
  1383. case WM_SETCURSOR:
  1384. if (NewDevWiz->CurrCursor) {
  1385. SetCursor(NewDevWiz->CurrCursor);
  1386. break;
  1387. }
  1388. // fall thru to return(FALSE);
  1389. default:
  1390. return(FALSE);
  1391. }
  1392. return(TRUE);
  1393. }
  1394. void
  1395. ShowInstallSummary(
  1396. HWND hDlg,
  1397. PNEWDEVWIZ NewDevWiz
  1398. )
  1399. {
  1400. LONG Error;
  1401. CONFIGRET ConfigRet;
  1402. ULONG Len, Problem, DevNodeStatus;
  1403. BOOL HasResources;
  1404. HWND hwndParentDlg = GetParent(hDlg);
  1405. PTCHAR ErrorMsg, ProblemText;
  1406. TCHAR TextBuffer[MAX_PATH*4];
  1407. Problem = 0;
  1408. *TextBuffer = TEXT('\0');
  1409. Error = NewDevWiz->LastError;
  1410. //
  1411. // On Windows Update installs we don't want to show any UI at all, even
  1412. // if there was an error during the installation.
  1413. // We can tell a WU install from a CDM install because only a WU install
  1414. // has a UpdateDriverInfo structure and is SilentMode.
  1415. // We also never want to show the finish page if this is a NonInteractive
  1416. // install.
  1417. //
  1418. if ((NewDevWiz->SilentMode &&
  1419. NewDevWiz->UpdateDriverInfo) ||
  1420. NewDevWiz->Flags & IDI_FLAG_NONINTERACTIVE)
  1421. {
  1422. HideWindowByMove(hwndParentDlg);
  1423. PropSheet_PressButton(hwndParentDlg, PSBTN_FINISH);
  1424. return;
  1425. }
  1426. if (NewDevWiz->hfontTextBigBold) {
  1427. SetWindowFont(GetDlgItem(hDlg, IDC_FINISH_MSG1), NewDevWiz->hfontTextBigBold, TRUE);
  1428. }
  1429. if (NDWTYPE_UPDATE == NewDevWiz->InstallType) {
  1430. SetDlgText(hDlg, IDC_FINISH_MSG1, IDS_FINISH_MSG1_UPGRADE, IDS_FINISH_MSG1_UPGRADE);
  1431. } else {
  1432. SetDlgText(hDlg, IDC_FINISH_MSG1, IDS_FINISH_MSG1_NEW, IDS_FINISH_MSG1_NEW);
  1433. }
  1434. //
  1435. // Installation failed
  1436. //
  1437. if (Error != ERROR_SUCCESS) {
  1438. NewDevWiz->Installed = FALSE;
  1439. SetDlgText(hDlg, IDC_FINISH_MSG1, IDS_FINISH_MSG1_INSTALL_PROBLEM, IDS_FINISH_MSG1_INSTALL_PROBLEM);
  1440. SetDlgText(hDlg, IDC_FINISH_MSG2, IDS_FINISH_PROB_MSG2, IDS_FINISH_PROB_MSG2);
  1441. #if DBG
  1442. DbgPrint("InstallDev Error =%x\n", Error);
  1443. #endif
  1444. //
  1445. // Display failure message for installation
  1446. //
  1447. // We will special case the following error codes so we can give a more
  1448. // friendly description of the problem to the user:
  1449. //
  1450. // TRUST_E_SUBJECT_FORM_UNKNOWN
  1451. // ERROR_NO_ASSOCIATED_SERVICE
  1452. // TYPE_E_ELEMENTNOTFOUND
  1453. // ERROR_NOT_FOUND
  1454. //
  1455. if ((Error == TRUST_E_SUBJECT_FORM_UNKNOWN) ||
  1456. (Error == CERT_E_EXPIRED) ||
  1457. (Error == TYPE_E_ELEMENTNOTFOUND) ||
  1458. (Error == ERROR_NOT_FOUND)) {
  1459. LoadText(TextBuffer,
  1460. sizeof(TextBuffer),
  1461. IDS_FINISH_PROB_TRUST_E_SUBJECT_FORM_UNKNOWN,
  1462. IDS_FINISH_PROB_TRUST_E_SUBJECT_FORM_UNKNOWN);
  1463. } else if (Error == ERROR_NO_ASSOCIATED_SERVICE) {
  1464. LoadText(TextBuffer,
  1465. sizeof(TextBuffer),
  1466. IDS_FINISH_PROB_ERROR_NO_ASSOCIATED_SERVICE,
  1467. IDS_FINISH_PROB_ERROR_NO_ASSOCIATED_SERVICE);
  1468. } else {
  1469. LoadText(TextBuffer, sizeof(TextBuffer), IDS_NDW_ERRORFIN1_PNP, IDS_NDW_ERRORFIN1_PNP);
  1470. if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  1471. NULL,
  1472. HRESULT_FROM_SETUPAPI(Error),
  1473. 0,
  1474. (LPTSTR)&ErrorMsg,
  1475. 0,
  1476. NULL
  1477. ))
  1478. {
  1479. lstrcat(TextBuffer, TEXT("\n\n"));
  1480. lstrcat(TextBuffer, ErrorMsg);
  1481. LocalFree(ErrorMsg);
  1482. }
  1483. }
  1484. SetDlgItemText(hDlg, IDC_FINISH_MSG3, TextBuffer);
  1485. }
  1486. //
  1487. // No errors installing the drivers for this device
  1488. //
  1489. else {
  1490. //
  1491. // Check to see if the device itself has any problems
  1492. //
  1493. Error = CM_Get_DevNode_Status(&DevNodeStatus,
  1494. &Problem,
  1495. NewDevWiz->DeviceInfoData.DevInst,
  1496. 0
  1497. );
  1498. if(Error != CR_SUCCESS) {
  1499. //
  1500. // For some reason, we couldn't retrieve the devnode's status.
  1501. // Default status and problem values to zero.
  1502. //
  1503. DevNodeStatus = Problem = 0;
  1504. }
  1505. //
  1506. // make sure the reboot flags\Problem are set correctly
  1507. //
  1508. if (NewDevWiz->Reboot || Problem == CM_PROB_NEED_RESTART) {
  1509. if (Problem != CM_PROB_PARTIAL_LOG_CONF) {
  1510. Problem = CM_PROB_NEED_RESTART;
  1511. }
  1512. NewDevWiz->Reboot |= DI_NEEDREBOOT;
  1513. }
  1514. NewDevWiz->Installed = TRUE;
  1515. HasResources = DeviceHasResources(NewDevWiz->DeviceInfoData.DevInst);
  1516. //
  1517. // The device has a problem
  1518. //
  1519. if ((Error != CR_SUCCESS) || Problem) {
  1520. //
  1521. // If we are going to launch the troubleshooter then change the finish text.
  1522. //
  1523. // We currently launch the troubleshooter if the device has some type of problem,
  1524. // unless the problem is CM_PROB_NEED_RESTART.
  1525. //
  1526. if (Problem && (Problem != CM_PROB_NEED_RESTART)) {
  1527. SetDlgText(hDlg, IDC_FINISH_MSG1, IDS_FINISH_MSG1_DEVICE_PROBLEM, IDS_FINISH_MSG1_DEVICE_PROBLEM);
  1528. SetDlgText(hDlg, IDC_FINISH_MSG2, IDS_FINISH_PROB_MSG2, IDS_FINISH_PROB_MSG2);
  1529. NewDevWiz->LaunchTroubleShooter = TRUE;
  1530. SetDlgText(hDlg, IDC_FINISH_MSG4, IDS_FINISH_PROB_MSG4, IDS_FINISH_PROB_MSG4);
  1531. }
  1532. //
  1533. // Show the resource button if the device has resources and it
  1534. // has the problem CM_PROB_PARTIAL_LOG_CONF
  1535. //
  1536. if (HasResources && (Problem == CM_PROB_PARTIAL_LOG_CONF)) {
  1537. ShowWindow(GetDlgItem(hDlg, IDC_NDW_DISPLAYRESOURCE), SW_SHOW);
  1538. }
  1539. if (Problem == CM_PROB_NEED_RESTART) {
  1540. LoadText(TextBuffer, sizeof(TextBuffer), IDS_NEEDREBOOT, IDS_NEEDREBOOT);
  1541. }
  1542. else if (Problem) {
  1543. ProblemText = DeviceProblemText(NULL,
  1544. NewDevWiz->DeviceInfoData.DevInst,
  1545. Problem
  1546. );
  1547. if (ProblemText) {
  1548. lstrcat(TextBuffer, TEXT("\n\n"));
  1549. lstrcat(TextBuffer, ProblemText);
  1550. LocalFree(ProblemText);
  1551. }
  1552. }
  1553. #if DBG
  1554. DbgPrint("InstallDev CM_Get_DevNode_Status()=%x DevNodeStatus=%x Problem=%x\n",
  1555. Error,
  1556. DevNodeStatus,
  1557. Problem
  1558. );
  1559. #endif
  1560. }
  1561. //
  1562. // Installation was sucessful and the device does not have any problems
  1563. //
  1564. else {
  1565. //
  1566. // If this was a silent install (a Rank 0 match for example) then don't show the finish
  1567. // page.
  1568. //
  1569. if (NewDevWiz->SilentMode) {
  1570. HideWindowByMove(hwndParentDlg);
  1571. PropSheet_PressButton(hwndParentDlg, PSBTN_FINISH);
  1572. return;
  1573. }
  1574. }
  1575. SetDlgItemText(hDlg, IDC_FINISH_MSG3, TextBuffer);
  1576. }
  1577. }
  1578. INT_PTR CALLBACK
  1579. NDW_FinishDlgProc(
  1580. HWND hDlg,
  1581. UINT wMsg,
  1582. WPARAM wParam,
  1583. LPARAM lParam
  1584. )
  1585. {
  1586. PNEWDEVWIZ NewDevWiz = (PNEWDEVWIZ)GetWindowLongPtr(hDlg, DWLP_USER);
  1587. switch (wMsg) {
  1588. case WM_INITDIALOG:
  1589. {
  1590. LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam;
  1591. NewDevWiz = (PNEWDEVWIZ)lppsp->lParam;
  1592. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)NewDevWiz);
  1593. break;
  1594. }
  1595. case WM_DESTROY:
  1596. break;
  1597. case WM_COMMAND:
  1598. switch (wParam) {
  1599. case IDC_NDW_DISPLAYRESOURCE:
  1600. DisplayResource(NewDevWiz, GetParent(hDlg));
  1601. break;
  1602. }
  1603. break;
  1604. case WM_NOTIFY:
  1605. switch (((NMHDR FAR *)lParam)->code) {
  1606. case PSN_SETACTIVE: {
  1607. HICON hicon;
  1608. SP_DRVINFO_DATA DriverInfoData;
  1609. //
  1610. // No back button since install is already done.
  1611. // set the device description
  1612. // Hide Resources button until we know if resources exist or not.
  1613. // Set the class Icon
  1614. //
  1615. PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_FINISH);
  1616. EnableWindow(GetDlgItem(GetParent(hDlg), IDCANCEL), FALSE);
  1617. ShowWindow(GetDlgItem(hDlg, IDC_NDW_DISPLAYRESOURCE), SW_HIDE);
  1618. if (NewDevWiz->LastError == ERROR_CANCELLED) {
  1619. if (NewDevWiz->SilentMode)
  1620. {
  1621. HideWindowByMove(GetParent(hDlg));
  1622. }
  1623. PropSheet_PressButton(GetParent(hDlg), PSBTN_CANCEL);
  1624. } else {
  1625. SetDriverDescription(hDlg, IDC_NDW_DESCRIPTION, NewDevWiz);
  1626. if (SetupDiLoadClassIcon(NewDevWiz->ClassGuidSelected, &hicon, NULL)) {
  1627. hicon = (HICON)SendDlgItemMessage(hDlg, IDC_CLASSICON, STM_SETICON, (WPARAM)hicon, 0L);
  1628. if (hicon) {
  1629. DestroyIcon(hicon);
  1630. }
  1631. }
  1632. ShowInstallSummary(hDlg, NewDevWiz);
  1633. }
  1634. break;
  1635. }
  1636. case PSN_RESET:
  1637. break;
  1638. case PSN_WIZFINISH:
  1639. if (NewDevWiz->LaunchTroubleShooter) {
  1640. //
  1641. // The command line that we will run is:
  1642. // rundll32 devmgr.dll, DeviceProblenWizard_RunDLL /deviceid %s
  1643. // where %s is the device instance id.
  1644. //
  1645. TCHAR szCmdLine[512];
  1646. TCHAR DeviceInstanceId[MAX_DEVICE_ID_LEN];
  1647. if (CM_Get_Device_ID(NewDevWiz->DeviceInfoData.DevInst,
  1648. DeviceInstanceId,
  1649. sizeof(DeviceInstanceId)/sizeof(TCHAR),
  1650. 0
  1651. ) == CR_SUCCESS) {
  1652. wsprintf(szCmdLine, TEXT("devmgr.dll,DeviceProblenWizard_RunDLL /deviceid %s"),
  1653. DeviceInstanceId);
  1654. ShellExecute(NULL,
  1655. TEXT("open"),
  1656. TEXT("RUNDLL32.EXE"),
  1657. szCmdLine,
  1658. NULL,
  1659. SW_SHOWNORMAL
  1660. );
  1661. }
  1662. }
  1663. break;
  1664. }
  1665. break;
  1666. default:
  1667. return(FALSE);
  1668. }
  1669. return(TRUE);
  1670. }
  1671. INT_PTR CALLBACK
  1672. WizExtFinishInstallDlgProc(
  1673. HWND hDlg,
  1674. UINT wMsg,
  1675. WPARAM wParam,
  1676. LPARAM lParam
  1677. )
  1678. {
  1679. HWND hwndParentDlg = GetParent(hDlg);
  1680. PNEWDEVWIZ NewDevWiz = (PNEWDEVWIZ )GetWindowLongPtr(hDlg, DWLP_USER);
  1681. int PrevPageId;
  1682. switch (wMsg) {
  1683. case WM_INITDIALOG: {
  1684. LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam;
  1685. NewDevWiz = (PNEWDEVWIZ )lppsp->lParam;
  1686. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)NewDevWiz);
  1687. break;
  1688. }
  1689. case WM_DESTROY:
  1690. break;
  1691. case WM_NOTIFY:
  1692. switch (((NMHDR FAR *)lParam)->code) {
  1693. case PSN_SETACTIVE:
  1694. PrevPageId = NewDevWiz->PrevPage;
  1695. NewDevWiz->PrevPage = IDD_WIZARDEXT_FINISHINSTALL;
  1696. if (PrevPageId == IDD_NEWDEVWIZ_INSTALLDEV)
  1697. {
  1698. PROPSHEETPAGE psp;
  1699. HPROPSHEETPAGE hPage = NULL;
  1700. //
  1701. // Moving forward on first page
  1702. //
  1703. //
  1704. // If this was a silent install and NOT a NonInteractive install
  1705. // then we need to create the FinishInstallIntro page at this
  1706. // point so we can add it to the wizard. We do this so the wizard
  1707. // has a proper intro and finish page with the FinishInstall
  1708. // pages inbetween.
  1709. //
  1710. if (NewDevWiz->SilentMode &&
  1711. !(NewDevWiz->Flags & IDI_FLAG_NONINTERACTIVE)) {
  1712. ZeroMemory(&psp, sizeof(PROPSHEETPAGE));
  1713. psp.dwSize = sizeof(PROPSHEETPAGE);
  1714. psp.hInstance = hNewDev;
  1715. psp.dwFlags = PSP_DEFAULT | PSP_USETITLE | PSP_HIDEHEADER;
  1716. psp.pszTemplate = MAKEINTRESOURCE(IDD_NEWDEVWIZ_FINISHINSTALL_INTRO);
  1717. psp.pfnDlgProc = FinishInstallIntroDlgProc;
  1718. psp.lParam = (LPARAM)NewDevWiz;
  1719. hPage = CreatePropertySheetPage(&psp);
  1720. }
  1721. //
  1722. // Add ClassWizard Extension pages for FinishInstall
  1723. //
  1724. if (AddClassWizExtPages(hwndParentDlg,
  1725. NewDevWiz,
  1726. &NewDevWiz->WizExtFinishInstall.DeviceWizardData,
  1727. DIF_NEWDEVICEWIZARD_FINISHINSTALL,
  1728. hPage
  1729. )) {
  1730. //
  1731. // If this is a NonInteractive install then we need to set the last
  1732. // error at this point so the error is propagated back to the original
  1733. // caller.
  1734. //
  1735. if (NewDevWiz->Flags & IDI_FLAG_NONINTERACTIVE) {
  1736. NewDevWiz->LastError = ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION;
  1737. } else {
  1738. //
  1739. // If we have finish install pages then we should also show the finish
  1740. // page.
  1741. //
  1742. NewDevWiz->SilentMode = FALSE;
  1743. }
  1744. }
  1745. //
  1746. // Add the end page, which is FinishInstall end
  1747. //
  1748. NewDevWiz->WizExtFinishInstall.hPropSheetEnd = CreateWizExtPage(IDD_WIZARDEXT_FINISHINSTALL_END,
  1749. WizExtFinishInstallEndDlgProc,
  1750. NewDevWiz
  1751. );
  1752. if (NewDevWiz->WizExtFinishInstall.hPropSheetEnd)
  1753. {
  1754. PropSheet_AddPage(hwndParentDlg, NewDevWiz->WizExtFinishInstall.hPropSheetEnd);
  1755. }
  1756. }
  1757. //
  1758. // We can't go backwards, so always go forward
  1759. //
  1760. SetDlgMsgResult(hDlg, wMsg, -1);
  1761. break;
  1762. case PSN_WIZNEXT:
  1763. SetDlgMsgResult(hDlg, wMsg, 0);
  1764. break;
  1765. }
  1766. break;
  1767. default:
  1768. return(FALSE);
  1769. }
  1770. return(TRUE);
  1771. }
  1772. INT_PTR CALLBACK
  1773. WizExtFinishInstallEndDlgProc(
  1774. HWND hDlg,
  1775. UINT wMsg,
  1776. WPARAM wParam,
  1777. LPARAM lParam
  1778. )
  1779. {
  1780. HWND hwndParentDlg = GetParent(hDlg);
  1781. PNEWDEVWIZ NewDevWiz = (PNEWDEVWIZ )GetWindowLongPtr(hDlg, DWLP_USER);
  1782. int PrevPageId;
  1783. switch (wMsg) {
  1784. case WM_INITDIALOG: {
  1785. LPPROPSHEETPAGE lppsp = (LPPROPSHEETPAGE)lParam;
  1786. NewDevWiz = (PNEWDEVWIZ )lppsp->lParam;
  1787. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)NewDevWiz);
  1788. break;
  1789. }
  1790. case WM_DESTROY:
  1791. break;
  1792. case WM_NOTIFY:
  1793. switch (((NMHDR FAR *)lParam)->code) {
  1794. case PSN_SETACTIVE:
  1795. PrevPageId = NewDevWiz->PrevPage;
  1796. NewDevWiz->PrevPage = IDD_WIZARDEXT_FINISHINSTALL_END;
  1797. //
  1798. // We can't go backwards, so always go forward
  1799. //
  1800. SetDlgMsgResult(hDlg, wMsg, IDD_NEWDEVWIZ_FINISH);
  1801. break;
  1802. case PSN_WIZBACK:
  1803. case PSN_WIZNEXT:
  1804. SetDlgMsgResult(hDlg, wMsg, 0);
  1805. break;
  1806. }
  1807. break;
  1808. default:
  1809. return(FALSE);
  1810. }
  1811. return(TRUE);
  1812. }