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.

490 lines
16 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. #include "devmgr.h"
  12. #include "proppage.h"
  13. #include "tsmain.h"
  14. #include "tswizard.h"
  15. const TCHAR* REG_PATH_TROUBLESHOOTERS = TEXT("Troubleshooters");
  16. const TCHAR* REG_VALUE_WIZARD32 = TEXT("Wizard32");
  17. //
  18. // class CWizard implementation
  19. //
  20. BOOL
  21. CWizard::Query(
  22. CDevice* pDevice,
  23. ULONG Problem
  24. )
  25. {
  26. if (!m_WizardEntry)
  27. return FALSE;
  28. TSHOOTER_QUERYPARAM QueryParam;
  29. TCHAR Description[MAX_PATH];
  30. m_pDevice = pDevice;
  31. QueryParam.Header.cbSize = sizeof(QueryParam);
  32. QueryParam.Header.Command = TSHOOTER_QUERY;
  33. QueryParam.DeviceId = pDevice->GetDeviceID();
  34. QueryParam.Problem = Problem;
  35. QueryParam.DescBuffer = Description;
  36. QueryParam.DescBufferSize = ARRAYLEN(Description);
  37. if ((*m_WizardEntry)((PTSHOOTER_PARAMHEADER) &QueryParam)) {
  38. m_DeviceRank = QueryParam.DeviceRank;
  39. m_ProblemRank = QueryParam.ProblemRank;
  40. m_strDescription = Description;
  41. return TRUE;
  42. }
  43. return FALSE;
  44. }
  45. BOOL
  46. CWizard::About(HWND hwndOwner)
  47. {
  48. if (!m_WizardEntry)
  49. return FALSE;
  50. TSHOOTER_ABOUTPARAM AboutParam;
  51. AboutParam.Header.cbSize = sizeof(AboutParam);
  52. AboutParam.Header.Command = TSHOOTER_ABOUT;
  53. AboutParam.hwndOwner = hwndOwner;
  54. return(*m_WizardEntry)((PTSHOOTER_PARAMHEADER)&AboutParam);
  55. }
  56. BOOL
  57. CWizard::AddPages(
  58. LPPROPSHEETHEADER ppsh,
  59. DWORD MaxPages
  60. )
  61. {
  62. if (!m_WizardEntry)
  63. return FALSE;
  64. if (!m_pDevice) {
  65. SetLastError(ERROR_INVALID_FUNCTION);
  66. return FALSE;
  67. }
  68. TSHOOTER_ADDPAGESPARAM AddPagesParam;
  69. AddPagesParam.Header.cbSize = sizeof(AddPagesParam);
  70. AddPagesParam.Header.Command = TSHOOTER_ADDPAGES;
  71. AddPagesParam.Problem = m_Problem;
  72. AddPagesParam.DeviceId = m_pDevice->GetDeviceID();
  73. AddPagesParam.PropSheetHeader = ppsh;
  74. AddPagesParam.MaxPages = MaxPages;
  75. return(*m_WizardEntry)((PTSHOOTER_PARAMHEADER)&AddPagesParam);
  76. }
  77. //
  78. // class CWizardList implementation
  79. //
  80. BOOL
  81. CWizardList::Create(
  82. CDevice* pDevice,
  83. ULONG Problem
  84. )
  85. {
  86. CSafeRegistry regDevMgr;
  87. CSafeRegistry regTShooters;
  88. DWORD RegType, Size, Type;
  89. if (regDevMgr.Open(HKEY_LOCAL_MACHINE, REG_PATH_DEVICE_MANAGER) &&
  90. regTShooters.Open(regDevMgr, REG_PATH_TROUBLESHOOTERS)) {
  91. if (TWT_ANY == m_Type || TWT_PROBLEM_SPECIFIC == m_Type) {
  92. // create problem specific wizards list first
  93. // convert problem number to subkey name
  94. TCHAR ProblemSubkey[10];
  95. wsprintf(ProblemSubkey, TEXT("%08X"), Problem);
  96. // see if there are registered for the problem.
  97. CSafeRegistry regProblem;
  98. if (regProblem.Open(regTShooters, ProblemSubkey)) {
  99. Size = 0;
  100. if (regProblem.GetValue(REG_VALUE_WIZARD32, &Type, NULL, &Size) &&
  101. REG_MULTI_SZ == Type && Size) {
  102. BufferPtr<BYTE> WizardPtr(Size);
  103. regProblem.GetValue(REG_VALUE_WIZARD32, &Type, WizardPtr, &Size);
  104. CreateWizardsFromStrings((LPTSTR)(BYTE*)WizardPtr, pDevice, Problem);
  105. }
  106. }
  107. }
  108. if (TWT_ANY == m_Type || TWT_CLASS_SPECIFIC == m_Type) {
  109. TCHAR GuidSubkey[MAX_GUID_STRING_LEN];
  110. GUID ClassGuid;
  111. pDevice->ClassGuid(ClassGuid);
  112. ULONG Size;
  113. if (GuidToString(&ClassGuid, GuidSubkey, ARRAYLEN(GuidSubkey))) {
  114. CSafeRegistry regGuid;
  115. if (regGuid.Open(regTShooters, GuidSubkey)) {
  116. Size = 0;
  117. if (regGuid.GetValue(REG_VALUE_WIZARD32, &Type, NULL, &Size) &&
  118. REG_MULTI_SZ == Type && Size) {
  119. BufferPtr<BYTE> WizardPtr(Size);
  120. regGuid.GetValue(REG_VALUE_WIZARD32, &Type, WizardPtr, &Size);
  121. CreateWizardsFromStrings((LPTSTR)(BYTE*)WizardPtr, pDevice, Problem);
  122. }
  123. }
  124. }
  125. }
  126. if (TWT_ANY == m_Type || TWT_GENERAL_PURPOSE == m_Type) {
  127. if (regTShooters.GetValue(REG_VALUE_WIZARD32, &Type, NULL, &Size) &&
  128. REG_MULTI_SZ == Type && Size) {
  129. BufferPtr<BYTE> WizardPtr(Size);
  130. regTShooters.GetValue(REG_VALUE_WIZARD32, &Type, WizardPtr, &Size);
  131. CreateWizardsFromStrings((LPTSTR)(BYTE*)WizardPtr, pDevice, Problem);
  132. }
  133. }
  134. }
  135. if (TWT_ANY == m_Type || TWT_DEVMGR_DEFAULT == m_Type) {
  136. SafePtr<CDefaultWizard> WizardPtr;
  137. CDefaultWizard* pWizard = new CDefaultWizard;
  138. WizardPtr.Attach(pWizard);
  139. if (pWizard->Query(pDevice, Problem)) {
  140. m_listWizards.AddTail(pWizard);
  141. WizardPtr.Detach();
  142. }
  143. }
  144. return !m_listWizards.IsEmpty();
  145. }
  146. CWizardList::~CWizardList()
  147. {
  148. if (!m_listWizards.IsEmpty()) {
  149. POSITION pos = m_listWizards.GetHeadPosition();
  150. while (NULL != pos) {
  151. delete (CWizard*)m_listWizards.GetNext(pos);
  152. }
  153. m_listWizards.RemoveAll();
  154. }
  155. }
  156. BOOL
  157. CWizardList::CreateWizardsFromStrings(
  158. LPTSTR msz,
  159. CDevice* pDevice,
  160. ULONG Problem
  161. )
  162. {
  163. LPTSTR p;
  164. p = msz;
  165. SetLastError(ERROR_SUCCESS);
  166. BOOL Result = TRUE;
  167. // the format of each string is "dllname, dllentryname"
  168. while (Result && _T('\0') != *p) {
  169. HMODULE hDll;
  170. FARPROC ProcAddress;
  171. Result = LoadEnumPropPage32(p, &hDll, &ProcAddress);
  172. if (Result) {
  173. SafePtr<CWizard> WizardPtr;
  174. CWizard* pWizard = new CWizard(hDll, ProcAddress);
  175. WizardPtr.Attach(pWizard);
  176. if (pWizard->Query(pDevice, Problem)) {
  177. m_listWizards.AddTail(pWizard);
  178. WizardPtr.Detach();
  179. }
  180. }
  181. p += lstrlen(p) + 1;
  182. }
  183. return Result;
  184. }
  185. BOOL
  186. CWizardList::GetFirstWizard(
  187. CWizard** ppWizard,
  188. PVOID* pContext
  189. )
  190. {
  191. if (!ppWizard || !pContext) {
  192. SetLastError(ERROR_INVALID_PARAMETER);
  193. return FALSE;
  194. }
  195. if (!m_listWizards.IsEmpty()) {
  196. POSITION pos = m_listWizards.GetHeadPosition();
  197. if (NULL != pos) {
  198. *ppWizard = m_listWizards.GetNext(pos);
  199. *pContext = (PVOID)pos;
  200. return TRUE;
  201. }
  202. }
  203. SetLastError(ERROR_NO_MORE_ITEMS);
  204. *ppWizard = NULL;
  205. *pContext = NULL;
  206. return FALSE;
  207. }
  208. BOOL
  209. CWizardList::GetNextWizard(
  210. CWizard** ppWizard,
  211. PVOID& Context
  212. )
  213. {
  214. if (!ppWizard) {
  215. SetLastError(ERROR_INVALID_PARAMETER);
  216. return FALSE;
  217. }
  218. POSITION pos = (POSITION)Context;
  219. if (NULL != pos) {
  220. *ppWizard = m_listWizards.GetNext(pos);
  221. Context = pos;
  222. return TRUE;
  223. }
  224. *ppWizard = NULL;
  225. Context = NULL;
  226. SetLastError(ERROR_NO_MORE_ITEMS);
  227. return FALSE;
  228. }
  229. CWizard98::CWizard98(
  230. HWND hwndParent,
  231. UINT MaxPages
  232. )
  233. {
  234. m_MaxPages = 0;
  235. if (MaxPages && MaxPages <= 32) {
  236. m_MaxPages = MaxPages;
  237. memset(&m_psh, 0, sizeof(m_psh));
  238. m_psh.hInstance = g_hInstance;
  239. m_psh.hwndParent = hwndParent;
  240. m_psh.phpage = new HPROPSHEETPAGE[MaxPages];
  241. m_psh.dwSize = sizeof(m_psh);
  242. m_psh.dwFlags = PSH_WIZARD | PSH_WIZARD97 | PSH_HEADER |
  243. PSH_WATERMARK | PSH_STRETCHWATERMARK;
  244. m_psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK);
  245. m_psh.pszbmHeader = MAKEINTRESOURCE(IDB_BANNER);
  246. PSH_STRETCHWATERMARK;
  247. m_psh.pszCaption = MAKEINTRESOURCE(IDS_TROUBLESHOOTING_NAME);
  248. }
  249. }
  250. BOOL
  251. CWizard98::CreateIntroPage(
  252. CDevice* pDevice
  253. )
  254. {
  255. CWizardIntro* pIntroPage = new CWizardIntro;
  256. HPROPSHEETPAGE hPage = pIntroPage->Create(pDevice);
  257. if (hPage) {
  258. m_psh.phpage[m_psh.nPages++] = hPage;
  259. return TRUE;
  260. }
  261. return FALSE;
  262. }
  263. HPROPSHEETPAGE
  264. CWizardIntro::Create(
  265. CDevice* pDevice
  266. )
  267. {
  268. if (!m_pDevice) {
  269. ASSERT(m_pDevice);
  270. m_pDevice = pDevice;
  271. m_psp.dwFlags = PSP_DEFAULT | PSP_USETITLE | PSP_HIDEHEADER;
  272. m_psp.pszTitle = MAKEINTRESOURCE(IDS_TROUBLESHOOTING_NAME);
  273. m_psp.lParam = (LPARAM)this;
  274. m_pSelectedWizard = NULL;
  275. DWORD Problem, Status;
  276. if (pDevice->GetStatus(&Status, &Problem) &&
  277. m_Wizards.Create(pDevice, Problem)) {
  278. m_Problem = Problem;
  279. return CPropSheetPage::CreatePage();
  280. }
  281. }
  282. return NULL;
  283. }
  284. BOOL
  285. CWizardIntro::OnInitDialog(
  286. LPPROPSHEETPAGE ppsp
  287. )
  288. {
  289. try {
  290. ASSERT(!m_hFontBold && !m_hFontBigBold);
  291. HFONT hFont = (HFONT)SendMessage(GetDlgItem(m_hDlg, IDC_WIZINTRO_WELCOME),
  292. WM_GETFONT, 0, 0);
  293. LOGFONT LogFont;
  294. GetObject(hFont, sizeof(LogFont), &LogFont);
  295. LogFont.lfWeight = FW_BOLD;
  296. m_hFontBold = CreateFontIndirect(&LogFont);
  297. int PtsPixels = GetDeviceCaps(GetDC(m_hDlg), LOGPIXELSY);
  298. int FontSize = (LogFont.lfHeight * 72 / PtsPixels) * 2;
  299. LogFont.lfHeight = PtsPixels * FontSize / 72;
  300. m_hFontBigBold = CreateFontIndirect(&LogFont);
  301. if (m_hFontBigBold && m_hFontBold) {
  302. SendMessage(GetDlgItem(m_hDlg, IDC_WIZINTRO_WELCOME),
  303. WM_SETFONT, (WPARAM)m_hFontBold, (LPARAM)TRUE);
  304. SendMessage(GetDlgItem(m_hDlg, IDC_WIZINTRO_NAME),
  305. WM_SETFONT, (WPARAM)m_hFontBigBold, (LPARAM)TRUE);
  306. }
  307. int Count = 0;
  308. CWizard* pWizard;
  309. PVOID Context;
  310. Count = m_Wizards.NumberOfWizards();
  311. if (Count > 1) {
  312. //
  313. // enumerate all registered wizard32 based troubleshooters
  314. //
  315. if (m_Wizards.GetFirstWizard(&pWizard, &Context)) {
  316. do {
  317. int iItem;
  318. iItem = SendDlgItemMessage(m_hDlg, IDC_WIZINTRO_WIZARDLIST,
  319. LB_ADDSTRING, Count,
  320. (LPARAM)(LPCTSTR)pWizard->GetDescription()
  321. );
  322. if (LB_ERR != iItem) {
  323. SendDlgItemMessage(m_hDlg, IDC_WIZINTRO_WIZARDLIST,
  324. LB_SETITEMDATA, iItem, (LPARAM)pWizard);
  325. Count++;
  326. }
  327. } while (m_Wizards.GetNextWizard(&pWizard, Context));
  328. }
  329. }
  330. // if we have any troubleshooters listed at all,
  331. // display the list and change the instruction text
  332. //
  333. if (Count > 1) {
  334. // make the default selection to the first one
  335. SendDlgItemMessage(m_hDlg, IDC_WIZINTRO_WIZARDLIST,
  336. LB_SETCURSEL, 0, 0);
  337. } else {
  338. // we have only one wizard in the list,
  339. // hide the wizard list box and necessary text and
  340. // select the only wizard as the selected wizard
  341. ShowWindow(GetControl(IDC_WIZINTRO_WIZARDS_GROUP), SW_HIDE);
  342. ShowWindow(GetControl(IDC_WIZINTRO_WIZARDS_TEXT), SW_HIDE);
  343. ShowWindow(GetControl(IDC_WIZINTRO_WIZARDLIST), SW_HIDE);
  344. m_Wizards.GetFirstWizard(&m_pSelectedWizard, &Context);
  345. ASSERT(m_pSelectedWizard);
  346. }
  347. } catch (CMemoryException* e) {
  348. e->Delete();
  349. MsgBoxParam(m_hDlg, 0, 0, 0);
  350. }
  351. return TRUE;
  352. }
  353. BOOL
  354. CWizardIntro::OnWizNext()
  355. {
  356. try {
  357. CWizard* pNewSelectedWizard = NULL;
  358. // get the current selected wizard from the list box
  359. // The list box is hidden when there is only one wizard
  360. // available.
  361. if (IsWindowVisible(GetControl(IDC_WIZINTRO_WIZARDLIST))) {
  362. int iItem = SendDlgItemMessage(m_hDlg, IDC_WIZINTRO_WIZARDLIST,
  363. LB_GETCURSEL, 0, 0);
  364. if (LB_ERR != iItem) {
  365. pNewSelectedWizard = (CWizard*) SendDlgItemMessage(m_hDlg,
  366. IDC_WIZINTRO_WIZARDLIST,
  367. LB_GETITEMDATA, iItem, 0);
  368. }
  369. }
  370. if (m_pSelectedWizard != pNewSelectedWizard) {
  371. if (m_pSelectedWizard) {
  372. // user has changed the wizard selection
  373. // remove all the pages added by the previous wizard
  374. UINT TotalPages = m_pSelectedWizard->m_AddedPages;
  375. // do not remove page 0 which is our introduction page
  376. for (UINT PageIndex = 1; TotalPages; TotalPages--, PageIndex++) {
  377. // PSM_REMOVEPAGE should also destroy the page, therefore,
  378. // we do not call DestroyPropertySheetPage on that page
  379. // here.
  380. ::SendMessage(GetParent(m_hDlg), PSM_REMOVEPAGE, PageIndex, 0);
  381. }
  382. }
  383. m_pSelectedWizard = NULL;
  384. // Let the newly selected wizard to create pages
  385. // We need a local copy of PROPERSHEETHEADER here
  386. // because we have to add each page to the active property
  387. // sheet(already displayed).
  388. CWizard98 theSheet(GetParent(GetParent(m_hDlg)));
  389. LONG Error;
  390. if (pNewSelectedWizard->AddPages(&theSheet.m_psh,
  391. theSheet.GetMaxPages()
  392. )) {
  393. // Remember how many pages the wizard added to the sheet.
  394. // It is used to removed page when we switch troubleshooters
  395. pNewSelectedWizard->m_AddedPages = theSheet.m_psh.nPages;
  396. // Add new pages to the property sheet
  397. for (UINT i = 0; i < theSheet.m_psh.nPages; i++) {
  398. SendMessage(GetParent(m_hDlg), PSM_ADDPAGE, 0,
  399. (LPARAM)theSheet.m_psh.phpage[i]);
  400. }
  401. m_pSelectedWizard = pNewSelectedWizard;
  402. } else {
  403. SetWindowLong(m_hDlg, DWL_MSGRESULT, -1);
  404. }
  405. }
  406. } catch (CMemoryException* e) {
  407. e->Delete();
  408. MsgBoxParam(m_hDlg, 0, 0, 0);
  409. }
  410. return CPropSheetPage::OnWizNext();
  411. }
  412. BOOL
  413. CWizardIntro::OnSetActive()
  414. {
  415. PropSheet_SetWizButtons(GetParent(m_hDlg), PSWIZB_NEXT);
  416. return CPropSheetPage::OnSetActive();
  417. }
  418. BOOL
  419. CWizardIntro::OnCommand(
  420. WPARAM wParam,
  421. LPARAM lParam
  422. )
  423. {
  424. if (LBN_DBLCLK == HIWORD(wParam) && IDC_WIZINTRO_WIZARDLIST == LOWORD(wParam)) {
  425. int iItem = SendDlgItemMessage(m_hDlg, IDC_WIZINTRO_WIZARDLIST,
  426. LB_GETCURSEL, 0, 0);
  427. if (LB_ERR != iItem && m_pSelectedWizard) {
  428. m_pSelectedWizard->About(m_hDlg);
  429. }
  430. }
  431. return CPropSheetPage::OnCommand(wParam, lParam);
  432. }
  433. INT_PTR
  434. StartTroubleshootingWizard(
  435. HWND hwndParent,
  436. CDevice* pDevice
  437. )
  438. {
  439. try {
  440. CWizard98 theSheet(hwndParent);
  441. if (theSheet.CreateIntroPage(pDevice))
  442. return theSheet.DoSheet();
  443. } catch (CMemoryException* e) {
  444. e->Delete();
  445. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  446. }
  447. return 0;
  448. }