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.

1333 lines
34 KiB

  1. /*++
  2. Copyright (C) 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. // CM_PROB_SETPROPERTIES_FAILED
  421. {
  422. TRUE,
  423. FIX_COMMAND_TROUBLESHOOTER,
  424. IDS_INST_TROUBLESHOOTER,
  425. 1,
  426. IDS_FIXIT_TROUBLESHOOTER
  427. },
  428. // UNKNOWN PROBLEM
  429. {
  430. TRUE,
  431. FIX_COMMAND_TROUBLESHOOTER,
  432. IDS_INST_TROUBLESHOOTER,
  433. 1,
  434. IDS_FIXIT_TROUBLESHOOTER
  435. },
  436. };
  437. //
  438. // CProblemAgent implementation
  439. //
  440. CProblemAgent::CProblemAgent(
  441. CDevice* pDevice,
  442. ULONG Problem,
  443. BOOL SeparateProcess
  444. )
  445. {
  446. m_pDevice = pDevice;
  447. m_Problem = Problem;
  448. ASSERT(pDevice);
  449. m_idInstFirst = ProblemInfo[min(Problem, DEVMGR_NUM_CM_PROB-1)].idInstFirst;
  450. m_idInstCount = ProblemInfo[min(Problem, DEVMGR_NUM_CM_PROB-1)].idInstCount;
  451. m_idFixit = ProblemInfo[min(Problem, DEVMGR_NUM_CM_PROB-1)].idFixit;
  452. m_FixCommand = ProblemInfo[min(Problem, DEVMGR_NUM_CM_PROB-1)].FixCommand;
  453. m_SeparateProcess = SeparateProcess;
  454. }
  455. DWORD
  456. CProblemAgent::InstructionText(
  457. LPTSTR Buffer,
  458. DWORD BufferSize
  459. )
  460. {
  461. String strLocalBuffer;
  462. SetLastError(ERROR_SUCCESS);
  463. if (m_idInstFirst) {
  464. strLocalBuffer.LoadString(g_hInstance, m_idInstFirst);
  465. String strTemp;
  466. for (int i = 1; i < m_idInstCount; i++) {
  467. strTemp.LoadString(g_hInstance, m_idInstFirst + i);
  468. strLocalBuffer += strTemp;
  469. }
  470. if (BufferSize > (DWORD)strLocalBuffer.GetLength()) {
  471. StringCchCopy(Buffer, BufferSize, (LPCTSTR)strLocalBuffer);
  472. }
  473. else if (strLocalBuffer.GetLength()) {
  474. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  475. }
  476. return strLocalBuffer.GetLength();
  477. }
  478. return 0;
  479. }
  480. DWORD
  481. CProblemAgent::FixitText(
  482. LPTSTR Buffer,
  483. DWORD BufferSize
  484. )
  485. {
  486. if (!Buffer && BufferSize)
  487. {
  488. SetLastError(ERROR_INVALID_PARAMETER);
  489. return 0;
  490. }
  491. SetLastError(ERROR_SUCCESS);
  492. if (m_idFixit)
  493. {
  494. return LoadResourceString(m_idFixit, Buffer, BufferSize);
  495. }
  496. return 0;
  497. }
  498. BOOL
  499. CProblemAgent::FixIt(
  500. HWND hwndOwner
  501. )
  502. /*++
  503. Lanuches a troubleshooter based on the m_FixCommand.
  504. Arguments:
  505. hwndOwner - Parent window handle
  506. Return Value:
  507. TRUE if launching the troubleshooter changed the device in some way
  508. so that the UI on the general tab needs to be refreshed.
  509. FALSE if launching the troubleshooter did not change the device in
  510. any way.
  511. --*/
  512. {
  513. BOOL Result = FALSE;
  514. SP_TROUBLESHOOTER_PARAMS tsp;
  515. DWORD RequiredSize;
  516. tsp.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
  517. tsp.ClassInstallHeader.InstallFunction = DIF_TROUBLESHOOTER;
  518. tsp.ChmFile[0] = TEXT('\0');
  519. tsp.HtmlTroubleShooter[0] = TEXT('\0');
  520. m_pDevice->m_pMachine->DiSetClassInstallParams(*m_pDevice,
  521. &tsp.ClassInstallHeader,
  522. sizeof(tsp)
  523. );
  524. //
  525. // If the class installer retuns NO_ERROR (SetupDiCallClassInstaller returns TRUE)
  526. // then don't launch the default troubleshooters because the class installer has
  527. // launched it's own troubleshooter
  528. //
  529. if (m_pDevice->m_pMachine->DiCallClassInstaller(DIF_TROUBLESHOOTER, *m_pDevice)) {
  530. return TRUE;
  531. } else if (ERROR_DI_DO_DEFAULT == GetLastError()) {
  532. m_pDevice->m_pMachine->DiGetClassInstallParams(*m_pDevice,
  533. &tsp.ClassInstallHeader,
  534. sizeof(tsp),
  535. &RequiredSize
  536. );
  537. }
  538. switch (m_FixCommand)
  539. {
  540. case FIX_COMMAND_UPGRADEDRIVERS:
  541. Result = UpgradeDriver(hwndOwner, m_pDevice);
  542. break;
  543. case FIX_COMMAND_REINSTALL:
  544. Result = Reinstall(hwndOwner, m_pDevice);
  545. break;
  546. case FIX_COMMAND_ENABLEDEVICE:
  547. Result = EnableDevice(hwndOwner, m_pDevice);
  548. break;
  549. case FIX_COMMAND_STARTDEVICE:
  550. Result = EnableDevice(hwndOwner, m_pDevice);
  551. break;
  552. case FIX_COMMAND_RESTARTCOMPUTER:
  553. Result = RestartComputer(hwndOwner, m_pDevice);
  554. break;
  555. case FIX_COMMAND_DRIVERBLOCKED:
  556. Result = FixDriverBlocked(hwndOwner, m_pDevice, tsp.ChmFile, ARRAYLEN(tsp.ChmFile), tsp.HtmlTroubleShooter, ARRAYLEN(tsp.HtmlTroubleShooter));
  557. break;
  558. case FIX_COMMAND_TROUBLESHOOTER:
  559. Result = StartTroubleShooter(hwndOwner, m_pDevice, tsp.ChmFile, tsp.HtmlTroubleShooter);
  560. break;
  561. case FIX_COMMAND_DONOTHING:
  562. Result = TRUE;
  563. break;
  564. default:
  565. Result = FALSE;
  566. }
  567. return Result;
  568. }
  569. BOOL
  570. CProblemAgent::UpgradeDriver(
  571. HWND hwndOwner,
  572. CDevice* pDevice
  573. )
  574. {
  575. DWORD Status = 0, Problem = 0;
  576. if (!pDevice || !pDevice->m_pMachine->IsLocal() || !g_IsAdmin) {
  577. //
  578. // Must be an admin and on the local machine to update a device.
  579. //
  580. ASSERT(FALSE);
  581. return FALSE;
  582. }
  583. //
  584. // If the device has the DN_WILL_BE_REMOVED flag set and the user is
  585. // attempting to update the driver then we will prompt them for a
  586. // reboot and include text in the prompt that explains this device
  587. // is in the process of being removed.
  588. //
  589. if (pDevice->GetStatus(&Status, &Problem) &&
  590. (Status & DN_WILL_BE_REMOVED)) {
  591. //
  592. // First try and send a MMCPropertyChangeNotify message to our
  593. // CComponent so that it can prompt for a reboot inside the
  594. // device manager thread instead of our thread. If this is not
  595. // done then the property sheet will hang around after device
  596. // manager has gone away...which will cause a "hung app" dialog
  597. // to appear.
  598. //
  599. CNotifyRebootRequest* pNRR = new CNotifyRebootRequest(hwndOwner, DI_NEEDRESTART, IDS_WILL_BE_REMOVED_NO_UPDATE_DRIVER);
  600. if (pNRR) {
  601. if (!pDevice->m_psd.PropertyChangeNotify(reinterpret_cast<LONG_PTR>(pNRR))) {
  602. //
  603. // There isn't a CComponent around, so this is just a property
  604. // sheet running outside of MMC.
  605. //
  606. pNRR->Release();
  607. PromptForRestart(hwndOwner, DI_NEEDRESTART, IDS_WILL_BE_REMOVED_NO_UPDATE_DRIVER);
  608. }
  609. } else {
  610. //
  611. // We couldn't allocate memory to create our CNotifyRebootRequest
  612. // instance, so just prompt for a reboot in this thread.
  613. //
  614. PromptForRestart(hwndOwner, DI_NEEDRESTART, IDS_WILL_BE_REMOVED_NO_UPDATE_DRIVER);
  615. }
  616. return FALSE;
  617. }
  618. pDevice->m_pMachine->InstallDevInst(hwndOwner, pDevice->GetDeviceID(), TRUE, NULL);
  619. return TRUE;
  620. }
  621. BOOL
  622. CProblemAgent::Reinstall(
  623. HWND hwndOwner,
  624. CDevice* pDevice
  625. )
  626. {
  627. return UpgradeDriver(hwndOwner, pDevice);
  628. }
  629. BOOL
  630. CProblemAgent::EnableDevice(
  631. HWND hwndOwner,
  632. CDevice* pDevice
  633. )
  634. {
  635. CWizard98 theSheet(hwndOwner);
  636. CTSEnableDeviceIntroPage* pEnableDeviceIntroPage = new CTSEnableDeviceIntroPage;
  637. if (!pEnableDeviceIntroPage) {
  638. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  639. return FALSE;
  640. }
  641. HPROPSHEETPAGE hIntroPage = pEnableDeviceIntroPage->Create(pDevice);
  642. theSheet.InsertPage(hIntroPage);
  643. CTSEnableDeviceFinishPage* pEnableDeviceFinishPage = new CTSEnableDeviceFinishPage;
  644. if (!pEnableDeviceFinishPage) {
  645. if (pEnableDeviceIntroPage) {
  646. delete pEnableDeviceIntroPage;
  647. }
  648. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  649. return FALSE;
  650. }
  651. HPROPSHEETPAGE hFinishPage = pEnableDeviceFinishPage->Create(pDevice);
  652. theSheet.InsertPage(hFinishPage);
  653. return (BOOL)theSheet.DoSheet();
  654. }
  655. BOOL
  656. CProblemAgent::RestartComputer(
  657. HWND hwndOwner,
  658. CDevice* pDevice
  659. )
  660. {
  661. HWND hwndFocus;
  662. if (!pDevice || !pDevice->m_pMachine)
  663. {
  664. SetLastError(ERROR_INVALID_PARAMETER);
  665. return FALSE;
  666. }
  667. hwndFocus = GetFocus();
  668. CWizard98 theSheet(hwndOwner);
  669. CTSRestartComputerFinishPage* pRestartComputerFinishPage = new CTSRestartComputerFinishPage;
  670. if (!pRestartComputerFinishPage) {
  671. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  672. return FALSE;
  673. }
  674. HPROPSHEETPAGE hPage = pRestartComputerFinishPage->Create(pDevice);
  675. theSheet.InsertPage(hPage);
  676. theSheet.DoSheet();
  677. // restore focus
  678. if (hwndFocus) {
  679. SetFocus(hwndFocus);
  680. }
  681. return TRUE;
  682. }
  683. BOOL
  684. CProblemAgent::FixDriverBlocked(
  685. HWND hwndOwner,
  686. CDevice* pDevice,
  687. LPTSTR ChmFile,
  688. ULONG ChmFileSize,
  689. LPTSTR HtmlTroubleShooter,
  690. ULONG HtmlTroubleShooterSize
  691. )
  692. {
  693. CDriver *pDriver = NULL;
  694. CDriverFile* pDrvFile = NULL;
  695. PVOID Context;
  696. LPCTSTR pBlockDriverHtmlHelpID = NULL;
  697. *ChmFile = TEXT('\0');
  698. pDriver = pDevice->CreateDriver();
  699. if (pDriver) {
  700. //
  701. // Build up a list of function and filter drivers for this device.
  702. //
  703. pDriver->BuildDriverList(TRUE);
  704. //
  705. // Enumerate through the list of drivers for this device until we find
  706. // one that has a blocked driver html help ID.
  707. //
  708. pDriver->GetFirstDriverFile(&pDrvFile, Context);
  709. if (pDrvFile) {
  710. do {
  711. if (pDrvFile &&
  712. ((pBlockDriverHtmlHelpID = pDrvFile->GetBlockedDriverHtmlHelpID()) != NULL) &&
  713. (*pBlockDriverHtmlHelpID != TEXT('\0')) &&
  714. (lstrlen(pBlockDriverHtmlHelpID) < (int)ChmFileSize)) {
  715. //
  716. // Found a Blocked Driver html help ID, assuming we can
  717. // copy it into our local ChmFile buffer, then break
  718. // out of the loop. If we can't then just continue, since
  719. // we can't launch a truncated help center page!
  720. //
  721. if (SUCCEEDED(StringCchCopy(ChmFile,
  722. ChmFileSize,
  723. pBlockDriverHtmlHelpID))) {
  724. break;
  725. }
  726. }
  727. } while (pDriver->GetNextDriverFile(&pDrvFile, Context));
  728. }
  729. }
  730. //
  731. // If we have a ChmFile then launch that troubleshooter, otherwise
  732. // Get the troubleshooter and launch it.
  733. //
  734. if (*ChmFile ||
  735. GetTroubleShooter(pDevice, ChmFile, ChmFileSize, HtmlTroubleShooter, HtmlTroubleShooterSize)) {
  736. LaunchHtlmTroubleShooter(hwndOwner, ChmFile, HtmlTroubleShooter);
  737. }
  738. if (pDriver) {
  739. delete pDriver;
  740. }
  741. return TRUE;
  742. }
  743. BOOL
  744. ParseTroubleShooter(
  745. LPCTSTR TSString,
  746. LPTSTR ChmFile,
  747. ULONG ChmFileSize,
  748. LPTSTR HtmlTroubleShooter,
  749. ULONG HtmlTroubleShooterSize
  750. )
  751. {
  752. //
  753. // Berify parameters
  754. //
  755. if (!TSString || TEXT('\0') == TSString[0] || !ChmFile || !HtmlTroubleShooter)
  756. {
  757. SetLastError(ERROR_INVALID_PARAMETER);
  758. return FALSE;
  759. }
  760. //
  761. // Make a copy of the string because we have to party on it
  762. //
  763. ULONG Len = lstrlen(TSString) + 1;
  764. TCHAR* psz = new TCHAR[Len];
  765. if (!psz) {
  766. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  767. return FALSE;
  768. }
  769. StringCchCopy(psz, Len, TSString);
  770. LPTSTR ChmName = NULL;
  771. LPTSTR ChmNameEnd = NULL;
  772. LPTSTR HtmName = NULL;
  773. LPTSTR HtmNameEnd = NULL;
  774. LPTSTR p;
  775. p = psz;
  776. SetLastError(ERROR_SUCCESS);
  777. //
  778. // the format of the string is "chmfile, htmlfile"
  779. //
  780. p = SkipBlankChars(p);
  781. if (TEXT('\0') != *p) {
  782. //
  783. // looking for CHM file which could be enclosed
  784. // inside double quote chars.
  785. // NOTE: not double quote chars inside double quoted string is allowed.
  786. //
  787. if (TEXT('\"') == *p) {
  788. ChmName = ++p;
  789. while (TEXT('\"') != *p && TEXT('\0') != *p) {
  790. p++;
  791. }
  792. ChmNameEnd = p;
  793. if (TEXT('\"') == *p) {
  794. p++;
  795. }
  796. } else {
  797. ChmName = p;
  798. while ((TEXT('\0') != *p) &&
  799. !IsBlankChar(*p) &&
  800. (TEXT(',') != *p)
  801. ) {
  802. p++;
  803. }
  804. ChmNameEnd = p;
  805. }
  806. //
  807. // looking for ','
  808. //
  809. if (TEXT('\0') != *p) {
  810. p = SkipBlankChars(p);
  811. if (TEXT('\0') != *p && TEXT(',') == *p) {
  812. p = SkipBlankChars(p + 1);
  813. if (TEXT('\0') != *p) {
  814. HtmName = p++;
  815. while (!IsBlankChar(*p) && TEXT('\0') != *p) {
  816. p++;
  817. }
  818. HtmNameEnd = p;
  819. }
  820. }
  821. }
  822. }
  823. if (HtmName && HtmNameEnd) {
  824. *HtmNameEnd = TEXT('\0');
  825. if (FAILED(StringCchCopy(HtmlTroubleShooter, HtmlTroubleShooterSize, HtmName))) {
  826. //
  827. // We could not copy all of the troubleshooter name into the buffer
  828. // so set HtmName and ChmName to NULL, so that we will FAIL the call.
  829. //
  830. HtmName = NULL;
  831. ChmName = NULL;
  832. }
  833. }
  834. if (ChmName && ChmNameEnd){
  835. *ChmNameEnd = TEXT('\0');
  836. if (FAILED(StringCchCopy(ChmFile, ChmFileSize, ChmName))) {
  837. //
  838. // We could not copy all of the Chm file name into the buffer
  839. // so set the HtmName and ChmName to NULL, so that we will FAIL this
  840. // call.
  841. //
  842. HtmName = NULL;
  843. ChmName = NULL;
  844. }
  845. }
  846. if (HtmName || ChmName) {
  847. return TRUE;
  848. }
  849. return FALSE;
  850. }
  851. //
  852. // This function looks for CHM and HTM troubleshooter files for this device.
  853. //
  854. // The troubleshoooter string value has the following form:
  855. // "TroubleShooter-xx" = "foo.chm, bar.htm"
  856. // where xx is the problem code for the device
  857. //
  858. // It first looks under the devices driver key.
  859. // If nothing is found there it looks under the class key.
  860. // If nothing is there it looks in the default troubleshooter location
  861. // If nothing is there it just displays the hard-coded generic troubleshooter.
  862. //
  863. BOOL
  864. CProblemAgent::GetTroubleShooter(
  865. CDevice* pDevice,
  866. LPTSTR ChmFile,
  867. ULONG ChmFileSize,
  868. LPTSTR HtmlTroubleShooter,
  869. ULONG HtmlTroubleShooterSize
  870. )
  871. {
  872. BOOL Result = FALSE;
  873. DWORD Status, Problem = 0;
  874. String strTroubleShooterKey;
  875. String strTroubleShooterValue;
  876. HKEY hKey;
  877. strTroubleShooterKey.Empty();
  878. strTroubleShooterValue.Empty();
  879. try {
  880. if (pDevice->GetStatus(&Status, &Problem)) {
  881. //
  882. // If the device is a phantom device, use the CM_PROB_DEVICE_NOT_THERE
  883. //
  884. if (pDevice->IsPhantom()) {
  885. Problem = CM_PROB_PHANTOM;
  886. }
  887. //
  888. // If the device is not started and no problem is assigned to it
  889. // fake the problem number to be failed start.
  890. //
  891. if (!(Status & DN_STARTED) && !Problem && pDevice->IsRAW()) {
  892. Problem = CM_PROB_FAILED_START;
  893. }
  894. }
  895. strTroubleShooterKey.Format(TEXT("TroubleShooter-%d"), Problem);
  896. //
  897. // First check the devices driver key
  898. //
  899. hKey = pDevice->m_pMachine->DiOpenDevRegKey(*pDevice, DICS_FLAG_GLOBAL,
  900. 0, DIREG_DRV, KEY_READ);
  901. if (INVALID_HANDLE_VALUE != hKey)
  902. {
  903. CSafeRegistry regDrv(hKey);
  904. //
  905. // Get the TroubleShooter value from the driver key
  906. //
  907. if (regDrv.GetValue((LPTSTR)strTroubleShooterKey, strTroubleShooterValue))
  908. {
  909. if (ParseTroubleShooter((LPTSTR)strTroubleShooterValue, ChmFile, ChmFileSize, HtmlTroubleShooter, HtmlTroubleShooterSize)) {
  910. Result = TRUE;
  911. }
  912. }
  913. }
  914. //
  915. // If we don't have a TroubleShooter yet then try the class key
  916. //
  917. if (!Result) {
  918. CClass* pClass = pDevice->GetClass();
  919. ASSERT(pClass);
  920. LPGUID pClassGuid = *pClass;
  921. hKey = pDevice->m_pMachine->DiOpenClassRegKey(pClassGuid, KEY_READ, DIOCR_INSTALLER);
  922. if (INVALID_HANDLE_VALUE != hKey)
  923. {
  924. CSafeRegistry regClass(hKey);
  925. // get the TroubleShooter value from the class key
  926. if (regClass.GetValue((LPTSTR)strTroubleShooterKey, strTroubleShooterValue))
  927. {
  928. if (ParseTroubleShooter((LPTSTR)strTroubleShooterValue, ChmFile, ChmFileSize, HtmlTroubleShooter, HtmlTroubleShooterSize)) {
  929. Result = TRUE;
  930. }
  931. }
  932. }
  933. }
  934. //
  935. // If we still don't have a TroubleShooter then try the default TroubleShooters
  936. // key.
  937. //
  938. if (!Result) {
  939. CSafeRegistry regDevMgr;
  940. CSafeRegistry regTroubleShooters;
  941. if (regDevMgr.Open(HKEY_LOCAL_MACHINE, REG_PATH_DEVICE_MANAGER) &&
  942. regTroubleShooters.Open(regDevMgr, REG_STR_TROUBLESHOOTERS)) {
  943. //
  944. // Get the TroubleShooter value from the default TroubleShooters key
  945. //
  946. if (regTroubleShooters.GetValue((LPTSTR)strTroubleShooterKey, strTroubleShooterValue))
  947. {
  948. if (ParseTroubleShooter((LPTSTR)strTroubleShooterValue, ChmFile, ChmFileSize, HtmlTroubleShooter, HtmlTroubleShooterSize)) {
  949. Result = TRUE;
  950. }
  951. }
  952. }
  953. }
  954. //
  955. // And finally, if still not TroubleShooter we will just use the default one
  956. //
  957. if (!Result) {
  958. if (SUCCEEDED(StringCchCopy(ChmFile, ChmFileSize, TEXT("hcp://help/tshoot/hdw_generic.htm")))) {
  959. HtmlTroubleShooter[0] = TEXT('\0');
  960. Result = TRUE;
  961. }
  962. }
  963. }
  964. catch (CMemoryException* e)
  965. {
  966. e->Delete();
  967. Result = FALSE;
  968. }
  969. return Result;
  970. }
  971. void
  972. CProblemAgent::LaunchHtlmTroubleShooter(
  973. HWND hwndOwner,
  974. LPTSTR ChmFile,
  975. LPTSTR HtmlTroubleShooter
  976. )
  977. {
  978. String strFormat, strCommand;
  979. if ((!ChmFile || !*ChmFile) &&
  980. (!HtmlTroubleShooter || !*HtmlTroubleShooter)) {
  981. //
  982. // If both ChmFile and HtmlTroubleShooter are NULL then
  983. // bail out.
  984. //
  985. return;
  986. }
  987. //
  988. // There are two different types of troubleshooters that can be launched.
  989. // HelpCenter troubleshooters and HtmlHelp troubleshooters. This API tells
  990. // the difference by checking if a HtmlTroubleShooter was specified or not.
  991. // If only a ChmFile was specified and it starts with hcp:// then this API
  992. // will send the entire string to help center. Otherwise we send the string
  993. // to HtmlHelp (or hh.exe if it is launched as a separate process).
  994. //
  995. if ((!HtmlTroubleShooter || (HtmlTroubleShooter[0] == TEXT('\0'))) &&
  996. (StrCmpNI(ChmFile, TEXT("hcp://"), lstrlen(TEXT("hcp://"))) == 0)) {
  997. //
  998. // This is a new HelpCenter troubleshooter
  999. //
  1000. strCommand.Format(TEXT(" -url %s"), ChmFile);
  1001. ShellExecute(hwndOwner,
  1002. TEXT("open"),
  1003. TEXT("HELPCTR.EXE"),
  1004. (LPTSTR)strCommand,
  1005. NULL,
  1006. SW_SHOWNORMAL
  1007. );
  1008. } else {
  1009. //
  1010. // This is an old HtlmHelp troubleshooter
  1011. //
  1012. if (m_SeparateProcess) {
  1013. STARTUPINFO si;
  1014. PROCESS_INFORMATION pi;
  1015. if (strFormat.GetSystemWindowsDirectory()) {
  1016. //
  1017. // Tack on an extra back slash if one is needed
  1018. //
  1019. if (_T('\\') != strFormat[strFormat.GetLength() - 1]) {
  1020. strFormat += (LPCTSTR)TEXT("\\");
  1021. }
  1022. strFormat += (LPCTSTR)TEXT("hh.exe ms-its:%s::/%s");
  1023. strCommand.Format((LPCTSTR)strFormat, ChmFile, HtmlTroubleShooter);
  1024. ZeroMemory(&si, sizeof(si));
  1025. si.cb = sizeof(si);
  1026. si.dwFlags = STARTF_USESHOWWINDOW;
  1027. si.wShowWindow = SW_NORMAL;
  1028. if (CreateProcess(NULL, (LPTSTR)strCommand, NULL, NULL, FALSE, 0, 0, NULL, &si, &pi)) {
  1029. CloseHandle(pi.hThread);
  1030. CloseHandle(pi.hProcess);
  1031. }
  1032. }
  1033. } else {
  1034. HtmlHelp(hwndOwner, ChmFile, HH_DISPLAY_TOPIC, (LPARAM)HtmlTroubleShooter);
  1035. }
  1036. }
  1037. }
  1038. BOOL
  1039. CProblemAgent::StartTroubleShooter(
  1040. HWND hwndOwner,
  1041. CDevice* pDevice,
  1042. LPTSTR ChmFile,
  1043. LPTSTR HtmlTroubleShooter
  1044. )
  1045. {
  1046. //
  1047. // If the class installers or one of the co-installers returned
  1048. // ERROR_DI_DO_DEFAULT then verify that they filled in either the ChmFile
  1049. // or the HtmlTroubleShooter, or both.
  1050. //
  1051. if ((ERROR_DI_DO_DEFAULT == GetLastError()) &&
  1052. (((ChmFile[0] != TEXT('\0')) ||
  1053. (HtmlTroubleShooter[0] != TEXT('\0'))))) {
  1054. LaunchHtlmTroubleShooter(hwndOwner, ChmFile, HtmlTroubleShooter);
  1055. } else {
  1056. SP_TROUBLESHOOTER_PARAMS tsp;
  1057. tsp.ChmFile[0] = TEXT('\0');
  1058. tsp.HtmlTroubleShooter[0] = TEXT('\0');
  1059. //
  1060. // Get CHM file and TroubleShooter file from the registry
  1061. //
  1062. if (GetTroubleShooter(pDevice, tsp.ChmFile, ARRAYLEN(tsp.ChmFile), tsp.HtmlTroubleShooter, ARRAYLEN(tsp.HtmlTroubleShooter))) {
  1063. LaunchHtlmTroubleShooter(hwndOwner, tsp.ChmFile, tsp.HtmlTroubleShooter);
  1064. }
  1065. }
  1066. //
  1067. // Return FALSE since launching the troubleshooter does not change the device
  1068. // in any way.
  1069. //
  1070. return FALSE;
  1071. }
  1072. CWizard98::CWizard98(
  1073. HWND hwndParent,
  1074. UINT MaxPages
  1075. )
  1076. {
  1077. m_MaxPages = 0;
  1078. if (MaxPages && MaxPages <= 32) {
  1079. m_MaxPages = MaxPages;
  1080. memset(&m_psh, 0, sizeof(m_psh));
  1081. m_psh.hInstance = g_hInstance;
  1082. m_psh.hwndParent = hwndParent;
  1083. m_psh.phpage = new HPROPSHEETPAGE[MaxPages];
  1084. m_psh.dwSize = sizeof(m_psh);
  1085. m_psh.dwFlags = PSH_WIZARD | PSH_USEICONID | PSH_USECALLBACK | PSH_WIZARD97 | PSH_WATERMARK | PSH_STRETCHWATERMARK | PSH_HEADER;
  1086. m_psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
  1087. m_psh.pszbmHeader = MAKEINTRESOURCE(IDB_BANNER);
  1088. m_psh.pszIcon = MAKEINTRESOURCE(IDI_DEVMGR);
  1089. m_psh.pszCaption = MAKEINTRESOURCE(IDS_TROUBLESHOOTING_NAME);
  1090. m_psh.pfnCallback = CWizard98::WizardCallback;
  1091. }
  1092. }
  1093. INT
  1094. CWizard98::WizardCallback(
  1095. IN HWND hwndDlg,
  1096. IN UINT uMsg,
  1097. IN LPARAM lParam
  1098. )
  1099. /*++
  1100. Routine Description:
  1101. Call back used to remove the "?" from the wizard page.
  1102. Arguments:
  1103. hwndDlg - Handle to the property sheet dialog box.
  1104. uMsg - Identifies the message being received. This parameter
  1105. is one of the following values:
  1106. PSCB_INITIALIZED - Indicates that the property sheet is
  1107. being initialized. The lParam value is zero for this message.
  1108. PSCB_PRECREATE Indicates that the property sheet is about
  1109. to be created. The hwndDlg parameter is NULL and the lParam
  1110. parameter is a pointer to a dialog template in memory. This
  1111. template is in the form of a DLGTEMPLATE structure followed
  1112. by one or more DLGITEMTEMPLATE structures.
  1113. lParam - Specifies additional information about the message. The
  1114. meaning of this value depends on the uMsg parameter.
  1115. Return Value:
  1116. The function returns zero.
  1117. --*/
  1118. {
  1119. UNREFERENCED_PARAMETER(hwndDlg);
  1120. switch( uMsg ) {
  1121. case PSCB_INITIALIZED:
  1122. break;
  1123. case PSCB_PRECREATE:
  1124. if( lParam ){
  1125. DLGTEMPLATE *pDlgTemplate = (DLGTEMPLATE *)lParam;
  1126. pDlgTemplate->style &= ~(DS_CONTEXTHELP | WS_SYSMENU);
  1127. }
  1128. break;
  1129. }
  1130. return FALSE;
  1131. }