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.

1272 lines
29 KiB

  1. /*++
  2. Copyright (C) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. tsmain.cpp
  5. Abstract:
  6. This module implements Device Manager troubleshooting supporting classes
  7. Author:
  8. William Hsieh (williamh) created
  9. Revision History:
  10. --*/
  11. //
  12. #include "devmgr.h"
  13. #include "proppage.h"
  14. #include "devdrvpg.h"
  15. #include "tsmisc.h"
  16. #include "tswizard.h"
  17. #include "cdriver.h"
  18. const CMPROBLEM_INFO ProblemInfo[DEVMGR_NUM_CM_PROB] =
  19. {
  20. // no problem
  21. {
  22. TRUE,
  23. FIX_COMMAND_TROUBLESHOOTER,
  24. IDS_INST_WORKING_TROUBLESHOOTER,
  25. 1,
  26. IDS_FIXIT_TROUBLESHOOTER
  27. },
  28. // CM_PROB_NOT_CONFIGURED
  29. {
  30. TRUE,
  31. FIX_COMMAND_REINSTALL,
  32. IDS_INST_REINSTALL,
  33. 1,
  34. IDS_FIXIT_REINSTALL
  35. },
  36. // CM_PROB_DEVLOADER_FAILED
  37. {
  38. TRUE,
  39. FIX_COMMAND_TROUBLESHOOTER,
  40. IDS_INST_TROUBLESHOOTER,
  41. 1,
  42. IDS_FIXIT_TROUBLESHOOTER
  43. },
  44. // CM_PROB_OUT_OF_MEMORY
  45. {
  46. TRUE,
  47. FIX_COMMAND_TROUBLESHOOTER,
  48. IDS_INST_TROUBLESHOOTER,
  49. 1,
  50. IDS_FIXIT_TROUBLESHOOTER
  51. },
  52. // CM_PROB_IS_WRONG_TYPE
  53. {
  54. TRUE,
  55. FIX_COMMAND_TROUBLESHOOTER,
  56. IDS_INST_TROUBLESHOOTER,
  57. 1,
  58. IDS_FIXIT_TROUBLESHOOTER
  59. },
  60. // CM_PROB_LACKED_ARBITRATOR
  61. {
  62. TRUE,
  63. FIX_COMMAND_TROUBLESHOOTER,
  64. IDS_INST_TROUBLESHOOTER,
  65. 1,
  66. IDS_FIXIT_TROUBLESHOOTER
  67. },
  68. // CM_PROB_BOOT_CONFIG_CONFLICT
  69. {
  70. TRUE,
  71. FIX_COMMAND_TROUBLESHOOTER,
  72. IDS_INST_TROUBLESHOOTER,
  73. 1,
  74. IDS_FIXIT_TROUBLESHOOTER
  75. },
  76. // CM_PROB_FAILED_FILTER (Never used)
  77. {
  78. TRUE,
  79. FIX_COMMAND_TROUBLESHOOTER,
  80. IDS_INST_TROUBLESHOOTER,
  81. 1,
  82. IDS_FIXIT_TROUBLESHOOTER
  83. },
  84. // CM_PROB_DEVLOADER_NOT_FOUND (Never used)
  85. {
  86. TRUE,
  87. FIX_COMMAND_TROUBLESHOOTER,
  88. IDS_INST_TROUBLESHOOTER,
  89. 1,
  90. IDS_FIXIT_TROUBLESHOOTER
  91. },
  92. // CM_PROB_INVALID_DATA
  93. {
  94. TRUE,
  95. FIX_COMMAND_TROUBLESHOOTER,
  96. IDS_INST_TROUBLESHOOTER,
  97. 1,
  98. IDS_FIXIT_TROUBLESHOOTER
  99. },
  100. // CM_PROB_FAILED_START
  101. {
  102. TRUE,
  103. FIX_COMMAND_TROUBLESHOOTER,
  104. IDS_INST_TROUBLESHOOTER,
  105. 1,
  106. IDS_FIXIT_TROUBLESHOOTER
  107. },
  108. // CM_PROB_LIAR (Never used)
  109. {
  110. TRUE,
  111. FIX_COMMAND_TROUBLESHOOTER,
  112. IDS_INST_TROUBLESHOOTER,
  113. 1,
  114. IDS_FIXIT_TROUBLESHOOTER
  115. },
  116. // CM_PROB_NORMAL_CONFLICT
  117. {
  118. TRUE,
  119. FIX_COMMAND_TROUBLESHOOTER,
  120. IDS_INST_TROUBLESHOOTER,
  121. 1,
  122. IDS_FIXIT_TROUBLESHOOTER
  123. },
  124. // CM_PROB_NOT_VERIFIED (Never used)
  125. {
  126. TRUE,
  127. FIX_COMMAND_TROUBLESHOOTER,
  128. IDS_INST_TROUBLESHOOTER,
  129. 1,
  130. IDS_FIXIT_TROUBLESHOOTER
  131. },
  132. // CM_PROB_NEED_RESTART
  133. {
  134. TRUE,
  135. FIX_COMMAND_RESTARTCOMPUTER,
  136. IDS_INST_RESTARTCOMPUTER,
  137. 1,
  138. IDS_FIXIT_RESTARTCOMPUTER
  139. },
  140. // CM_PROB_REENUMERATION
  141. {
  142. TRUE,
  143. FIX_COMMAND_TROUBLESHOOTER,
  144. IDS_INST_TROUBLESHOOTER,
  145. 1,
  146. IDS_FIXIT_TROUBLESHOOTER
  147. },
  148. // CM_PROB_PARTIAL_LOG_CONF
  149. {
  150. TRUE,
  151. FIX_COMMAND_TROUBLESHOOTER,
  152. IDS_INST_TROUBLESHOOTER,
  153. 1,
  154. IDS_FIXIT_TROUBLESHOOTER
  155. },
  156. // CM_PROB_UNKNOWN_RESOURCE
  157. {
  158. TRUE,
  159. FIX_COMMAND_TROUBLESHOOTER,
  160. IDS_INST_TROUBLESHOOTER,
  161. 1,
  162. IDS_FIXIT_TROUBLESHOOTER
  163. },
  164. // CM_PROB_REINSTALL
  165. {
  166. TRUE,
  167. FIX_COMMAND_REINSTALL,
  168. IDS_INST_REINSTALL,
  169. 1,
  170. IDS_FIXIT_REINSTALL
  171. },
  172. // CM_PROB_REGISTRY (Never used)
  173. {
  174. TRUE,
  175. FIX_COMMAND_TROUBLESHOOTER,
  176. IDS_INST_TROUBLESHOOTER,
  177. 1,
  178. IDS_FIXIT_TROUBLESHOOTER
  179. },
  180. // CM_PROB_VXDLDR (Never used)
  181. {
  182. TRUE,
  183. FIX_COMMAND_TROUBLESHOOTER,
  184. IDS_INST_TROUBLESHOOTER,
  185. 1,
  186. IDS_FIXIT_TROUBLESHOOTER
  187. },
  188. // CM_PROB_WILL_BE_REMOVED (Never used)
  189. {
  190. TRUE,
  191. FIX_COMMAND_TROUBLESHOOTER,
  192. IDS_INST_TROUBLESHOOTER,
  193. 1,
  194. IDS_FIXIT_TROUBLESHOOTER
  195. },
  196. // CM_PROB_DISABLED
  197. {
  198. TRUE,
  199. FIX_COMMAND_ENABLEDEVICE,
  200. IDS_INST_ENABLEDEVICE,
  201. 1,
  202. IDS_FIXIT_ENABLEDEVICE
  203. },
  204. // CM_PROB_DEVLOADER_NOT_READY (Never used)
  205. {
  206. TRUE,
  207. FIX_COMMAND_TROUBLESHOOTER,
  208. IDS_INST_TROUBLESHOOTER,
  209. 1,
  210. IDS_FIXIT_TROUBLESHOOTER
  211. },
  212. // CM_PROB_DEVICE_NOT_THERE
  213. {
  214. TRUE,
  215. FIX_COMMAND_TROUBLESHOOTER,
  216. IDS_INST_TROUBLESHOOTER,
  217. 1,
  218. IDS_FIXIT_TROUBLESHOOTER
  219. },
  220. // CM_PROB_MOVED
  221. {
  222. TRUE,
  223. FIX_COMMAND_TROUBLESHOOTER,
  224. IDS_INST_TROUBLESHOOTER,
  225. 1,
  226. IDS_FIXIT_TROUBLESHOOTER
  227. },
  228. // CM_PROB_TOO_EARLY
  229. {
  230. TRUE,
  231. FIX_COMMAND_TROUBLESHOOTER,
  232. IDS_INST_TROUBLESHOOTER,
  233. 1,
  234. IDS_FIXIT_TROUBLESHOOTER
  235. },
  236. // CM_PROB_NO_VALID_LOG_CONF
  237. {
  238. TRUE,
  239. FIX_COMMAND_TROUBLESHOOTER,
  240. IDS_INST_TROUBLESHOOTER,
  241. 1,
  242. IDS_FIXIT_TROUBLESHOOTER
  243. },
  244. // CM_PROB_FAILED_INSTALL
  245. {
  246. TRUE,
  247. FIX_COMMAND_REINSTALL,
  248. IDS_INST_REINSTALL,
  249. 1,
  250. IDS_FIXIT_REINSTALL
  251. },
  252. // CM_PROB_HARDWARE_DISABLED
  253. {
  254. TRUE,
  255. FIX_COMMAND_TROUBLESHOOTER,
  256. IDS_INST_TROUBLESHOOTER,
  257. 1,
  258. IDS_FIXIT_TROUBLESHOOTER
  259. },
  260. // CM_PROB_CANT_SHARE_IRQ
  261. {
  262. TRUE,
  263. FIX_COMMAND_TROUBLESHOOTER,
  264. IDS_INST_TROUBLESHOOTER,
  265. 1,
  266. IDS_FIXIT_TROUBLESHOOTER
  267. },
  268. // CM_PROB_FAILED_ADD
  269. {
  270. TRUE,
  271. FIX_COMMAND_TROUBLESHOOTER,
  272. IDS_INST_TROUBLESHOOTER,
  273. 1,
  274. IDS_FIXIT_TROUBLESHOOTER
  275. },
  276. // CM_PROB_DISABLED_SERVICE
  277. {
  278. TRUE,
  279. FIX_COMMAND_TROUBLESHOOTER,
  280. IDS_INST_TROUBLESHOOTER,
  281. 1,
  282. IDS_FIXIT_TROUBLESHOOTER
  283. },
  284. // CM_PROB_TRANSLATION_FAILED
  285. {
  286. TRUE,
  287. FIX_COMMAND_TROUBLESHOOTER,
  288. IDS_INST_TROUBLESHOOTER,
  289. 1,
  290. IDS_FIXIT_TROUBLESHOOTER
  291. },
  292. // CM_PROB_NO_SOFTCONFIG
  293. {
  294. TRUE,
  295. FIX_COMMAND_TROUBLESHOOTER,
  296. IDS_INST_TROUBLESHOOTER,
  297. 1,
  298. IDS_FIXIT_TROUBLESHOOTER
  299. },
  300. // CM_PROB_BIOS_TABLE
  301. {
  302. TRUE,
  303. FIX_COMMAND_TROUBLESHOOTER,
  304. IDS_INST_TROUBLESHOOTER,
  305. 1,
  306. IDS_FIXIT_TROUBLESHOOTER
  307. },
  308. // CM_PROB_IRQ_TRANSLATION_FAILED
  309. {
  310. TRUE,
  311. FIX_COMMAND_TROUBLESHOOTER,
  312. IDS_INST_TROUBLESHOOTER,
  313. 1,
  314. IDS_FIXIT_TROUBLESHOOTER
  315. },
  316. // CM_PROB_FAILED_DRIVER_ENTRY
  317. {
  318. TRUE,
  319. FIX_COMMAND_TROUBLESHOOTER,
  320. IDS_INST_TROUBLESHOOTER,
  321. 1,
  322. IDS_FIXIT_TROUBLESHOOTER
  323. },
  324. // CM_PROB_DRIVER_FAILED_PRIOR_UNLOAD
  325. {
  326. TRUE,
  327. FIX_COMMAND_TROUBLESHOOTER,
  328. IDS_INST_TROUBLESHOOTER,
  329. 1,
  330. IDS_FIXIT_TROUBLESHOOTER
  331. },
  332. // CM_PROB_DRIVER_FAILED_LOAD
  333. {
  334. TRUE,
  335. FIX_COMMAND_TROUBLESHOOTER,
  336. IDS_INST_TROUBLESHOOTER,
  337. 1,
  338. IDS_FIXIT_TROUBLESHOOTER
  339. },
  340. // CM_PROB_DRIVER_SERVICE_KEY_INVALID
  341. {
  342. TRUE,
  343. FIX_COMMAND_TROUBLESHOOTER,
  344. IDS_INST_TROUBLESHOOTER,
  345. 1,
  346. IDS_FIXIT_TROUBLESHOOTER
  347. },
  348. // CM_PROB_LEGACY_SERVICE_NO_DEVICES
  349. {
  350. TRUE,
  351. FIX_COMMAND_TROUBLESHOOTER,
  352. IDS_INST_TROUBLESHOOTER,
  353. 1,
  354. IDS_FIXIT_TROUBLESHOOTER
  355. },
  356. // CM_PROB_DUPLICATE_DEVICE
  357. {
  358. TRUE,
  359. FIX_COMMAND_TROUBLESHOOTER,
  360. IDS_INST_TROUBLESHOOTER,
  361. 1,
  362. IDS_FIXIT_TROUBLESHOOTER
  363. },
  364. // CM_PROB_FAILED_POST_START
  365. {
  366. TRUE,
  367. FIX_COMMAND_TROUBLESHOOTER,
  368. IDS_INST_TROUBLESHOOTER,
  369. 1,
  370. IDS_FIXIT_TROUBLESHOOTER
  371. },
  372. // CM_PROB_HALTED
  373. {
  374. TRUE,
  375. FIX_COMMAND_TROUBLESHOOTER,
  376. IDS_INST_TROUBLESHOOTER,
  377. 1,
  378. IDS_FIXIT_TROUBLESHOOTER
  379. },
  380. // CM_PROB_PHANTOM
  381. {
  382. TRUE,
  383. FIX_COMMAND_TROUBLESHOOTER,
  384. IDS_INST_TROUBLESHOOTER,
  385. 1,
  386. IDS_FIXIT_TROUBLESHOOTER
  387. },
  388. // CM_PROB_SYSTEM_SHUTDOWN
  389. {
  390. TRUE,
  391. FIX_COMMAND_TROUBLESHOOTER,
  392. IDS_INST_TROUBLESHOOTER,
  393. 1,
  394. IDS_FIXIT_TROUBLESHOOTER
  395. },
  396. // CM_PROB_HELD_FOR_EJECT
  397. {
  398. TRUE,
  399. FIX_COMMAND_TROUBLESHOOTER,
  400. IDS_INST_TROUBLESHOOTER,
  401. 1,
  402. IDS_FIXIT_TROUBLESHOOTER
  403. },
  404. // CM_PROB_DRIVER_BLOCKED
  405. {
  406. TRUE,
  407. FIX_COMMAND_DRIVERBLOCKED,
  408. IDS_INST_TROUBLESHOOTER,
  409. 1,
  410. IDS_FIXIT_TROUBLESHOOTER
  411. },
  412. // CM_PROB_REGISTRY_TOO_LARGE
  413. {
  414. TRUE,
  415. FIX_COMMAND_TROUBLESHOOTER,
  416. IDS_INST_TROUBLESHOOTER,
  417. 1,
  418. IDS_FIXIT_TROUBLESHOOTER
  419. },
  420. // UNKNOWN PROBLEM
  421. {
  422. TRUE,
  423. FIX_COMMAND_TROUBLESHOOTER,
  424. IDS_INST_TROUBLESHOOTER,
  425. 1,
  426. IDS_FIXIT_TROUBLESHOOTER
  427. },
  428. };
  429. //
  430. // CProblemAgent implementation
  431. //
  432. CProblemAgent::CProblemAgent(
  433. CDevice* pDevice,
  434. ULONG Problem,
  435. BOOL SeparateProcess
  436. )
  437. {
  438. m_pDevice = pDevice;
  439. m_Problem = Problem;
  440. ASSERT(pDevice);
  441. m_idInstFirst = ProblemInfo[min(Problem, DEVMGR_NUM_CM_PROB-1)].idInstFirst;
  442. m_idInstCount = ProblemInfo[min(Problem, DEVMGR_NUM_CM_PROB-1)].idInstCount;
  443. m_idFixit = ProblemInfo[min(Problem, DEVMGR_NUM_CM_PROB-1)].idFixit;
  444. m_FixCommand = ProblemInfo[min(Problem, DEVMGR_NUM_CM_PROB-1)].FixCommand;
  445. m_SeparateProcess = SeparateProcess;
  446. }
  447. DWORD
  448. CProblemAgent::InstructionText(
  449. LPTSTR Buffer,
  450. DWORD BufferSize
  451. )
  452. {
  453. TCHAR LocalBuffer[512];
  454. LocalBuffer[0] = TEXT('\0');
  455. SetLastError(ERROR_SUCCESS);
  456. if (m_idInstFirst)
  457. {
  458. TCHAR Temp[256];
  459. for (int i = 0; i < m_idInstCount; i++)
  460. {
  461. LoadString(g_hInstance, m_idInstFirst + i, Temp, ARRAYLEN(Temp));
  462. lstrcat(LocalBuffer, Temp);
  463. }
  464. }
  465. DWORD Len = lstrlen(LocalBuffer);
  466. if (BufferSize > Len) {
  467. lstrcpyn(Buffer, LocalBuffer, Len + 1);
  468. }
  469. else if (Len) {
  470. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  471. }
  472. return Len;
  473. }
  474. DWORD
  475. CProblemAgent::FixitText(
  476. LPTSTR Buffer,
  477. DWORD BufferSize
  478. )
  479. {
  480. if (!Buffer && BufferSize)
  481. {
  482. SetLastError(ERROR_INVALID_PARAMETER);
  483. return 0;
  484. }
  485. SetLastError(ERROR_SUCCESS);
  486. if (m_idFixit)
  487. {
  488. return LoadResourceString(m_idFixit, Buffer, BufferSize);
  489. }
  490. return 0;
  491. }
  492. BOOL
  493. CProblemAgent::FixIt(
  494. HWND hwndOwner
  495. )
  496. /*++
  497. Lanuches a troubleshooter based on the m_FixCommand.
  498. Arguments:
  499. hwndOwner - Parent window handle
  500. Return Value:
  501. TRUE if launching the troubleshooter changed the device in some way
  502. so that the UI on the general tab needs to be refreshed.
  503. FALSE if launching the troubleshooter did not change the device in
  504. any way.
  505. --*/
  506. {
  507. BOOL Result;
  508. SP_TROUBLESHOOTER_PARAMS tsp;
  509. DWORD RequiredSize;
  510. tsp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  511. tsp.ClassInstallHeader.InstallFunction = DIF_TROUBLESHOOTER;
  512. tsp.ChmFile[0] = TEXT('\0');
  513. tsp.HtmlTroubleShooter[0] = TEXT('\0');
  514. m_pDevice->m_pMachine->DiSetClassInstallParams(*m_pDevice,
  515. &tsp.ClassInstallHeader,
  516. sizeof(tsp)
  517. );
  518. //
  519. // If the class installer retuns NO_ERROR (SetupDiCallClassInstaller returns TRUE)
  520. // then don't launch the default troubleshooters because the class installer has
  521. // launched it's own troubleshooter
  522. //
  523. if (m_pDevice->m_pMachine->DiCallClassInstaller(DIF_TROUBLESHOOTER, *m_pDevice)) {
  524. return TRUE;
  525. } else if (ERROR_DI_DO_DEFAULT == GetLastError()) {
  526. m_pDevice->m_pMachine->DiGetClassInstallParams(*m_pDevice,
  527. &tsp.ClassInstallHeader,
  528. sizeof(tsp),
  529. &RequiredSize
  530. );
  531. }
  532. switch (m_FixCommand)
  533. {
  534. case FIX_COMMAND_UPGRADEDRIVERS:
  535. Result = UpgradeDriver(hwndOwner, m_pDevice);
  536. break;
  537. case FIX_COMMAND_REINSTALL:
  538. Result = Reinstall(hwndOwner, m_pDevice);
  539. break;
  540. case FIX_COMMAND_ENABLEDEVICE:
  541. Result = EnableDevice(hwndOwner, m_pDevice);
  542. break;
  543. case FIX_COMMAND_STARTDEVICE:
  544. Result = EnableDevice(hwndOwner, m_pDevice);
  545. break;
  546. case FIX_COMMAND_RESTARTCOMPUTER:
  547. Result = RestartComputer(hwndOwner, m_pDevice);
  548. break;
  549. case FIX_COMMAND_DRIVERBLOCKED:
  550. FixDriverBlocked(hwndOwner, m_pDevice, tsp.ChmFile, tsp.HtmlTroubleShooter);
  551. break;
  552. case FIX_COMMAND_TROUBLESHOOTER:
  553. Result = StartTroubleShooter(hwndOwner, m_pDevice, tsp.ChmFile, tsp.HtmlTroubleShooter);
  554. break;
  555. case FIX_COMMAND_DONOTHING:
  556. Result = TRUE;
  557. break;
  558. default:
  559. Result = FALSE;
  560. }
  561. return Result;
  562. }
  563. BOOL
  564. CProblemAgent::UpgradeDriver(
  565. HWND hwndOwner,
  566. CDevice* pDevice
  567. )
  568. {
  569. DWORD Status = 0, Problem = 0;
  570. if (!pDevice || !pDevice->m_pMachine->IsLocal() || !g_HasLoadDriverNamePrivilege) {
  571. // Must be an admin and on the local machine to update a device.
  572. ASSERT(FALSE);
  573. return FALSE;
  574. }
  575. //
  576. // If the device has the DN_WILL_BE_REMOVED flag set and the user is
  577. // attempting to update the driver then we will prompt them for a
  578. // reboot and include text in the prompt that explains this device
  579. // is in the process of being removed.
  580. //
  581. if (pDevice->GetStatus(&Status, &Problem) &&
  582. (Status & DN_WILL_BE_REMOVED)) {
  583. PromptForRestart(hwndOwner, DI_NEEDRESTART, IDS_WILL_BE_REMOVED_NO_UPDATE_DRIVER);
  584. return FALSE;
  585. }
  586. pDevice->m_pMachine->InstallDevInst(hwndOwner, pDevice->GetDeviceID(), TRUE, NULL);
  587. return TRUE;
  588. }
  589. BOOL
  590. CProblemAgent::Reinstall(
  591. HWND hwndOwner,
  592. CDevice* pDevice
  593. )
  594. {
  595. return UpgradeDriver(hwndOwner, pDevice);
  596. }
  597. BOOL
  598. CProblemAgent::EnableDevice(
  599. HWND hwndOwner,
  600. CDevice* pDevice
  601. )
  602. {
  603. CWizard98 theSheet(hwndOwner);
  604. CTSEnableDeviceIntroPage* pEnableDeviceIntroPage = new CTSEnableDeviceIntroPage;
  605. if (!pEnableDeviceIntroPage) {
  606. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  607. return FALSE;
  608. }
  609. HPROPSHEETPAGE hIntroPage = pEnableDeviceIntroPage->Create(pDevice);
  610. theSheet.InsertPage(hIntroPage);
  611. CTSEnableDeviceFinishPage* pEnableDeviceFinishPage = new CTSEnableDeviceFinishPage;
  612. if (!pEnableDeviceFinishPage) {
  613. if (pEnableDeviceIntroPage) {
  614. delete pEnableDeviceIntroPage;
  615. }
  616. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  617. return FALSE;
  618. }
  619. HPROPSHEETPAGE hFinishPage = pEnableDeviceFinishPage->Create(pDevice);
  620. theSheet.InsertPage(hFinishPage);
  621. return (BOOL)theSheet.DoSheet();
  622. }
  623. BOOL
  624. CProblemAgent::RestartComputer(
  625. HWND hwndOwner,
  626. CDevice* pDevice
  627. )
  628. {
  629. HWND hwndFocus;
  630. if (!pDevice || !pDevice->m_pMachine)
  631. {
  632. SetLastError(ERROR_INVALID_PARAMETER);
  633. return FALSE;
  634. }
  635. hwndFocus = GetFocus();
  636. CWizard98 theSheet(hwndOwner);
  637. CTSRestartComputerFinishPage* pRestartComputerFinishPage = new CTSRestartComputerFinishPage;
  638. if (!pRestartComputerFinishPage) {
  639. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  640. return FALSE;
  641. }
  642. HPROPSHEETPAGE hPage = pRestartComputerFinishPage->Create(pDevice);
  643. theSheet.InsertPage(hPage);
  644. theSheet.DoSheet();
  645. // restore focus
  646. if (hwndFocus) {
  647. SetFocus(hwndFocus);
  648. }
  649. return TRUE;
  650. }
  651. BOOL
  652. CProblemAgent::FixDriverBlocked(
  653. HWND hwndOwner,
  654. CDevice* pDevice,
  655. LPTSTR ChmFile,
  656. LPTSTR HtmlTroubleShooter
  657. )
  658. {
  659. CDriver *pDriver = NULL;
  660. CDriverFile* pDrvFile = NULL;
  661. PVOID Context;
  662. LPCTSTR pBlockDriverHtmlHelpID = NULL;
  663. *ChmFile = TEXT('\0');
  664. pDriver = pDevice->CreateDriver();
  665. if (pDriver) {
  666. //
  667. // Build up a list of function and filter drivers for this device.
  668. //
  669. pDriver->BuildDriverList(NULL, TRUE);
  670. //
  671. // Enumerate through the list of drivers for this device until we find
  672. // one that has a blocked driver html help ID.
  673. //
  674. pDriver->GetFirstDriverFile(&pDrvFile, Context);
  675. if (pDrvFile) {
  676. do {
  677. if (pDrvFile &&
  678. ((pBlockDriverHtmlHelpID = pDrvFile->GetBlockedDriverHtmlHelpID()) != NULL) &&
  679. (*pBlockDriverHtmlHelpID != TEXT('\0'))) {
  680. //
  681. // Found a Blocked Driver html help ID so break out of the loop.
  682. //
  683. lstrcpy(ChmFile, pBlockDriverHtmlHelpID);
  684. break;
  685. }
  686. } while (pDriver->GetNextDriverFile(&pDrvFile, Context));
  687. }
  688. }
  689. if (!(*ChmFile)) {
  690. //
  691. // If we couldn't get a troubleshooter for one of the drivers then just
  692. // do the default troubleshooter code.
  693. //
  694. GetTroubleShooter(pDevice, ChmFile, HtmlTroubleShooter);
  695. }
  696. LaunchHtlmTroubleShooter(hwndOwner, ChmFile, HtmlTroubleShooter);
  697. if (pDriver) {
  698. delete pDriver;
  699. }
  700. return TRUE;
  701. }
  702. BOOL
  703. ParseTroubleShooter(
  704. LPCTSTR TSString,
  705. LPTSTR ChmFile,
  706. LPTSTR HtmlTroubleShooter
  707. )
  708. {
  709. //
  710. // Berify parameters
  711. //
  712. if (!TSString || TEXT('\0') == TSString[0] || !ChmFile || !HtmlTroubleShooter)
  713. {
  714. SetLastError(ERROR_INVALID_PARAMETER);
  715. return FALSE;
  716. }
  717. //
  718. // Make a copy of the string because we have to party on it
  719. //
  720. TCHAR* psz = new TCHAR[lstrlen(TSString) + 1];
  721. if (!psz) {
  722. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  723. return FALSE;
  724. }
  725. lstrcpy(psz, TSString);
  726. LPTSTR ChmName = NULL;
  727. LPTSTR ChmNameEnd;
  728. LPTSTR HtmName = NULL;
  729. LPTSTR HtmNameEnd;
  730. LPTSTR p;
  731. p = psz;
  732. SetLastError(ERROR_SUCCESS);
  733. //
  734. // the format of the string is "chmfile, htmlfile"
  735. //
  736. p = SkipBlankChars(p);
  737. if (TEXT('\0') != *p) {
  738. //
  739. // looking for CHM file which could be enclosed
  740. // inside double quote chars.
  741. // NOTE: not double quote chars inside double quoted string is allowed.
  742. //
  743. if (TEXT('\"') == *p) {
  744. ChmName = ++p;
  745. while (TEXT('\"') != *p && TEXT('\0') != *p) {
  746. p++;
  747. }
  748. ChmNameEnd = p;
  749. if (TEXT('\"') == *p) {
  750. p++;
  751. }
  752. } else {
  753. ChmName = p;
  754. while ((TEXT('\0') != *p) &&
  755. !IsBlankChar(*p) &&
  756. (TEXT(',') != *p)
  757. ) {
  758. p++;
  759. }
  760. ChmNameEnd = p;
  761. }
  762. //
  763. // looking for ','
  764. //
  765. if (TEXT('\0') != *p) {
  766. p = SkipBlankChars(p);
  767. if (TEXT('\0') != *p && TEXT(',') == *p) {
  768. p = SkipBlankChars(p + 1);
  769. if (TEXT('\0') != *p) {
  770. HtmName = p++;
  771. while (!IsBlankChar(*p) && TEXT('\0') != *p) {
  772. p++;
  773. }
  774. HtmNameEnd = p;
  775. }
  776. }
  777. }
  778. }
  779. if (HtmName) {
  780. *HtmNameEnd = TEXT('\0');
  781. lstrcpy(HtmlTroubleShooter, HtmName);
  782. }
  783. if (ChmName){
  784. *ChmNameEnd = TEXT('\0');
  785. lstrcpy(ChmFile, ChmName);
  786. }
  787. if (HtmName || ChmName) {
  788. return TRUE;
  789. }
  790. return FALSE;
  791. }
  792. //
  793. // This function looks for CHM and HTM troubleshooter files for this device.
  794. //
  795. // The troubleshoooter string value has the following form:
  796. // "TroubleShooter-xx" = "foo.chm, bar.htm"
  797. // where xx is the problem code for the device
  798. //
  799. // It first looks under the devices driver key.
  800. // If nothing is found there it looks under the class key.
  801. // If nothing is there it looks in the default troubleshooter location
  802. // If nothing is there it just displays the hard-coded generic troubleshooter.
  803. //
  804. BOOL
  805. CProblemAgent::GetTroubleShooter(
  806. CDevice* pDevice,
  807. LPTSTR ChmFile,
  808. LPTSTR HtmlTroubleShooter
  809. )
  810. {
  811. BOOL Result = FALSE;
  812. DWORD Status, Problem = 0;
  813. TCHAR TroubleShooterKey[MAX_PATH];
  814. TCHAR TroubleShooterValue[MAX_PATH * 2];
  815. HKEY hKey;
  816. try {
  817. if (pDevice->GetStatus(&Status, &Problem)) {
  818. //
  819. // If the device is a phantom device, use the CM_PROB_DEVICE_NOT_THERE
  820. //
  821. if (pDevice->IsPhantom()) {
  822. Problem = CM_PROB_PHANTOM;
  823. }
  824. //
  825. // If the device is not started and no problem is assigned to it
  826. // fake the problem number to be failed start.
  827. //
  828. if (!(Status & DN_STARTED) && !Problem && pDevice->IsRAW()) {
  829. Problem = CM_PROB_FAILED_START;
  830. }
  831. }
  832. wsprintf(TroubleShooterKey, TEXT("TroubleShooter-%d"), Problem);
  833. //
  834. // First check the devices driver key
  835. //
  836. hKey = pDevice->m_pMachine->DiOpenDevRegKey(*pDevice, DICS_FLAG_GLOBAL,
  837. 0, DIREG_DRV, KEY_READ);
  838. if (INVALID_HANDLE_VALUE != hKey)
  839. {
  840. DWORD regType;
  841. DWORD Len = sizeof(TroubleShooterValue);
  842. CSafeRegistry regDrv(hKey);
  843. //
  844. // Get the TroubleShooter value from the driver key
  845. //
  846. if (regDrv.GetValue(TroubleShooterKey, &regType,
  847. (PBYTE)TroubleShooterValue,
  848. &Len))
  849. {
  850. if (ParseTroubleShooter(TroubleShooterValue, ChmFile, HtmlTroubleShooter)) {
  851. Result = TRUE;
  852. }
  853. }
  854. }
  855. //
  856. // If we don't have a TroubleShooter yet then try the class key
  857. //
  858. if (!Result) {
  859. CClass* pClass = pDevice->GetClass();
  860. ASSERT(pClass);
  861. LPGUID pClassGuid = *pClass;
  862. hKey = pDevice->m_pMachine->DiOpenClassRegKey(pClassGuid, KEY_READ, DIOCR_INSTALLER);
  863. if (INVALID_HANDLE_VALUE != hKey)
  864. {
  865. DWORD regType;
  866. DWORD Len = sizeof(TroubleShooterValue);
  867. CSafeRegistry regClass(hKey);
  868. // get the TroubleShooter value from the class key
  869. if (regClass.GetValue(TroubleShooterKey, &regType,
  870. (PBYTE)TroubleShooterValue,
  871. &Len))
  872. {
  873. if (ParseTroubleShooter(TroubleShooterValue, ChmFile, HtmlTroubleShooter)) {
  874. Result = TRUE;
  875. }
  876. }
  877. }
  878. }
  879. //
  880. // If we still don't have a TroubleShooter then try the default TroubleShooters
  881. // key.
  882. //
  883. if (!Result) {
  884. CSafeRegistry regDevMgr;
  885. CSafeRegistry regTroubleShooters;
  886. if (regDevMgr.Open(HKEY_LOCAL_MACHINE, REG_PATH_DEVICE_MANAGER) &&
  887. regTroubleShooters.Open(regDevMgr, REG_STR_TROUBLESHOOTERS)) {
  888. DWORD regType;
  889. DWORD Len = sizeof(TroubleShooterValue);
  890. // get the TroubleShooter value from the default TroubleShooters key
  891. if (regTroubleShooters.GetValue(TroubleShooterKey, &regType,
  892. (PBYTE)TroubleShooterValue,
  893. &Len))
  894. {
  895. if (ParseTroubleShooter(TroubleShooterValue, ChmFile, HtmlTroubleShooter)) {
  896. Result = TRUE;
  897. }
  898. }
  899. }
  900. }
  901. //
  902. // And finally, if still not TroubleShooter we will just use the default one
  903. //
  904. if (!Result) {
  905. lstrcpy(ChmFile, TEXT("hcp://help/tshoot/hdw_generic.htm"));
  906. HtmlTroubleShooter[0] = TEXT('\0');
  907. Result = TRUE;
  908. }
  909. }
  910. catch (CMemoryException* e)
  911. {
  912. e->Delete();
  913. Result = FALSE;
  914. }
  915. return Result;
  916. }
  917. void
  918. CProblemAgent::LaunchHtlmTroubleShooter(
  919. HWND hwndOwner,
  920. LPTSTR ChmFile,
  921. LPTSTR HtmlTroubleShooter
  922. )
  923. {
  924. String StringCommand;
  925. if ((!ChmFile || !*ChmFile) &&
  926. (!HtmlTroubleShooter || !*HtmlTroubleShooter)) {
  927. //
  928. // If both ChmFile and HtmlTroubleShooter are NULL then
  929. // bail out.
  930. //
  931. return;
  932. }
  933. //
  934. // There are two different types of troubleshooters that can be launched.
  935. // HelpCenter troubleshooters and HtmlHelp troubleshooters. This API tells
  936. // the difference by checking if a HtmlTroubleShooter was specified or not.
  937. // If only a ChmFile was specified and it starts with hcp:// then this API
  938. // will send the entire string to help center. Otherwise we send the string
  939. // to HtmlHelp (or hh.exe if it is launched as a separate process).
  940. //
  941. if ((!HtmlTroubleShooter || (HtmlTroubleShooter[0] == TEXT('\0'))) &&
  942. (StrCmpNI(ChmFile, TEXT("hcp://"), lstrlen(TEXT("hcp://"))) == 0)) {
  943. //
  944. // This is a new HelpCenter troubleshooter
  945. //
  946. StringCommand.Format(TEXT(" -url %s"), ChmFile);
  947. ShellExecute(hwndOwner,
  948. TEXT("open"),
  949. TEXT("HELPCTR.EXE"),
  950. (LPTSTR)StringCommand,
  951. NULL,
  952. SW_SHOWNORMAL
  953. );
  954. } else {
  955. //
  956. // This is an old HtlmHelp troubleshooter
  957. //
  958. if (m_SeparateProcess) {
  959. STARTUPINFO si;
  960. PROCESS_INFORMATION pi;
  961. StringCommand.Format(TEXT("hh.exe ms-its:%s::/%s"), ChmFile, HtmlTroubleShooter);
  962. ZeroMemory(&si, sizeof(si));
  963. si.cb = sizeof(si);
  964. si.dwFlags = STARTF_USESHOWWINDOW;
  965. si.wShowWindow = SW_NORMAL;
  966. if (CreateProcess(NULL, (LPTSTR)StringCommand, NULL, NULL, FALSE, 0, 0, NULL, &si, &pi)) {
  967. CloseHandle(pi.hThread);
  968. CloseHandle(pi.hProcess);
  969. }
  970. } else {
  971. HtmlHelp(hwndOwner, ChmFile, HH_DISPLAY_TOPIC, (LPARAM)HtmlTroubleShooter);
  972. }
  973. }
  974. }
  975. BOOL
  976. CProblemAgent::StartTroubleShooter(
  977. HWND hwndOwner,
  978. CDevice* pDevice,
  979. LPTSTR ChmFile,
  980. LPTSTR HtmlTroubleShooter
  981. )
  982. {
  983. //
  984. // If the class installers or one of the co-installers returned
  985. // ERROR_DI_DO_DEFAULT then verify that they filled in either the ChmFile
  986. // or the HtmlTroubleShooter, or both.
  987. //
  988. if ((ERROR_DI_DO_DEFAULT == GetLastError()) &&
  989. (((ChmFile[0] != TEXT('\0')) ||
  990. (HtmlTroubleShooter[0] != TEXT('\0'))))) {
  991. LaunchHtlmTroubleShooter(hwndOwner, ChmFile, HtmlTroubleShooter);
  992. } else {
  993. //
  994. // Get CHM file and TroubleShooter file from the registry
  995. //
  996. if (GetTroubleShooter(pDevice, ChmFile, HtmlTroubleShooter)) {
  997. LaunchHtlmTroubleShooter(hwndOwner, ChmFile, HtmlTroubleShooter);
  998. }
  999. }
  1000. //
  1001. // Return FALSE since launching the troubleshooter does not change the device
  1002. // in any way.
  1003. //
  1004. return FALSE;
  1005. }
  1006. CWizard98::CWizard98(
  1007. HWND hwndParent,
  1008. UINT MaxPages
  1009. )
  1010. {
  1011. m_MaxPages = 0;
  1012. if (MaxPages && MaxPages <= 32) {
  1013. m_MaxPages = MaxPages;
  1014. memset(&m_psh, 0, sizeof(m_psh));
  1015. m_psh.hInstance = g_hInstance;
  1016. m_psh.hwndParent = hwndParent;
  1017. m_psh.phpage = new HPROPSHEETPAGE[MaxPages];
  1018. m_psh.dwSize = sizeof(m_psh);
  1019. m_psh.dwFlags = PSH_WIZARD | PSH_USEICONID | PSH_USECALLBACK | PSH_WIZARD97 | PSH_WATERMARK | PSH_STRETCHWATERMARK | PSH_HEADER;
  1020. m_psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
  1021. m_psh.pszbmHeader = MAKEINTRESOURCE(IDB_BANNER);
  1022. PSH_STRETCHWATERMARK;
  1023. m_psh.pszIcon = MAKEINTRESOURCE(IDI_DEVMGR);
  1024. m_psh.pszCaption = MAKEINTRESOURCE(IDS_TROUBLESHOOTING_NAME);
  1025. m_psh.pfnCallback = CWizard98::WizardCallback;
  1026. }
  1027. }
  1028. INT
  1029. CWizard98::WizardCallback(
  1030. IN HWND hwndDlg,
  1031. IN UINT uMsg,
  1032. IN LPARAM lParam
  1033. )
  1034. /*++
  1035. Routine Description:
  1036. Call back used to remove the "?" from the wizard page.
  1037. Arguments:
  1038. hwndDlg - Handle to the property sheet dialog box.
  1039. uMsg - Identifies the message being received. This parameter
  1040. is one of the following values:
  1041. PSCB_INITIALIZED - Indicates that the property sheet is
  1042. being initialized. The lParam value is zero for this message.
  1043. PSCB_PRECREATE Indicates that the property sheet is about
  1044. to be created. The hwndDlg parameter is NULL and the lParam
  1045. parameter is a pointer to a dialog template in memory. This
  1046. template is in the form of a DLGTEMPLATE structure followed
  1047. by one or more DLGITEMTEMPLATE structures.
  1048. lParam - Specifies additional information about the message. The
  1049. meaning of this value depends on the uMsg parameter.
  1050. Return Value:
  1051. The function returns zero.
  1052. --*/
  1053. {
  1054. switch( uMsg ) {
  1055. case PSCB_INITIALIZED:
  1056. break;
  1057. case PSCB_PRECREATE:
  1058. if( lParam ){
  1059. DLGTEMPLATE *pDlgTemplate = (DLGTEMPLATE *)lParam;
  1060. pDlgTemplate->style &= ~(DS_CONTEXTHELP | WS_SYSMENU);
  1061. }
  1062. break;
  1063. }
  1064. return FALSE;
  1065. }