Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2139 lines
75 KiB

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