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.

938 lines
19 KiB

  1. // Spewview: remote debug spew monitor
  2. //
  3. // Copyright (c) 2000 Microsoft Corp.
  4. //
  5. // Main dialog window
  6. //
  7. // 16 Mar 2000 sburns
  8. #include "headers.hxx"
  9. #include "MainDialog.hpp"
  10. #include "SpewDialog.hpp"
  11. #include "resource.h"
  12. static const DWORD _help_map[] =
  13. {
  14. IDC_CLIENT_NAME, NO_HELP,
  15. IDC_APP_NAME, NO_HELP,
  16. IDC_GET_FLAGS, NO_HELP,
  17. IDC_SET_FLAGS, NO_HELP,
  18. IDC_VIEW_SPEW, NO_HELP,
  19. IDC_FLAGS_GROUP, NO_HELP,
  20. IDC_OUTPUT_TO_FILE, NO_HELP,
  21. IDC_OUTPUT_TO_DEBUGGER, NO_HELP,
  22. IDC_OUTPUT_TO_SPEWVIEW, NO_HELP,
  23. IDC_OUTPUT_LOGS, NO_HELP,
  24. IDC_OUTPUT_HEADER, NO_HELP,
  25. IDC_OUTPUT_ERRORS, NO_HELP,
  26. IDC_OUTPUT_CTORS, NO_HELP,
  27. IDC_OUTPUT_ADDREFS, NO_HELP,
  28. IDC_OUTPUT_FUNCCALLS, NO_HELP,
  29. IDC_OUTPUT_TIME_OF_DAY, NO_HELP,
  30. IDC_OUTPUT_RUN_TIME, NO_HELP,
  31. IDC_OUTPUT_SCOPE_EXIT, NO_HELP,
  32. IDC_FLAGS, NO_HELP,
  33. IDC_STATUS, NO_HELP,
  34. 0, 0
  35. };
  36. static const DWORD ID_TO_FLAGMAP[] =
  37. {
  38. IDC_OUTPUT_TO_FILE, Burnslib::Log::OUTPUT_TO_FILE,
  39. IDC_OUTPUT_TO_DEBUGGER, Burnslib::Log::OUTPUT_TO_DEBUGGER,
  40. IDC_OUTPUT_TO_SPEWVIEW, Burnslib::Log::OUTPUT_TO_SPEWVIEW,
  41. IDC_OUTPUT_LOGS, Burnslib::Log::OUTPUT_LOGS,
  42. IDC_OUTPUT_HEADER, Burnslib::Log::OUTPUT_HEADER,
  43. IDC_OUTPUT_ERRORS, Burnslib::Log::OUTPUT_ERRORS,
  44. IDC_OUTPUT_CTORS, Burnslib::Log::OUTPUT_CTORS,
  45. IDC_OUTPUT_ADDREFS, Burnslib::Log::OUTPUT_ADDREFS,
  46. IDC_OUTPUT_FUNCCALLS, Burnslib::Log::OUTPUT_FUNCCALLS,
  47. IDC_OUTPUT_TIME_OF_DAY, Burnslib::Log::OUTPUT_TIME_OF_DAY,
  48. IDC_OUTPUT_RUN_TIME, Burnslib::Log::OUTPUT_RUN_TIME,
  49. IDC_OUTPUT_SCOPE_EXIT, Burnslib::Log::OUTPUT_SCOPE_EXIT,
  50. 0, 0
  51. };
  52. MainDialog::MainDialog()
  53. :
  54. Dialog(IDD_MAIN, _help_map),
  55. spewviewer(0),
  56. setFlagsOnStart(false)
  57. {
  58. LOG_CTOR(MainDialog);
  59. }
  60. MainDialog::~MainDialog()
  61. {
  62. LOG_DTOR(MainDialog);
  63. SaveUiHistory();
  64. delete spewviewer;
  65. spewviewer = 0;
  66. }
  67. void
  68. MainDialog::SetStatusText(const String& text)
  69. {
  70. LOG_FUNCTION2(MainDialog::SetStatusText, text);
  71. Win::SetDlgItemText(hwnd, IDC_STATUS, text);
  72. }
  73. void
  74. MainDialog::EnableControls()
  75. {
  76. LOG_FUNCTION(MainDialog::EnableControls);
  77. String c = Win::GetTrimmedDlgItemText(hwnd, IDC_CLIENT_NAME);
  78. String a = Win::GetTrimmedDlgItemText(hwnd, IDC_APP_NAME);
  79. bool enableButtons =
  80. !Win::GetTrimmedDlgItemText(hwnd, IDC_CLIENT_NAME).empty()
  81. && !Win::GetTrimmedDlgItemText(hwnd, IDC_APP_NAME).empty();
  82. Win::EnableWindow(Win::GetDlgItem(hwnd, IDC_GET_FLAGS), enableButtons);
  83. Win::EnableWindow(Win::GetDlgItem(hwnd, IDC_SET_FLAGS), enableButtons);
  84. Win::EnableWindow(Win::GetDlgItem(hwnd, IDC_VIEW_SPEW), enableButtons);
  85. Win::EnableWindow(Win::GetDlgItem(hwnd, IDC_FLAGS_GROUP), enableButtons);
  86. for (int i = 0; ID_TO_FLAGMAP[i]; i += 2)
  87. {
  88. Win::EnableWindow(
  89. Win::GetDlgItem(hwnd, ID_TO_FLAGMAP[i]),
  90. enableButtons);
  91. }
  92. }
  93. void
  94. MainDialog::AddToUiHistory(const String& clientName, const String& appName)
  95. {
  96. LOG_FUNCTION(MainDialog::AddToUiHistory);
  97. ASSERT(!clientName.empty());
  98. ASSERT(!appName.empty());
  99. push_back_unique(clientNameHistory, clientName);
  100. push_back_unique(appNameHistory, appName);
  101. lastClientNameUsed = clientName;
  102. lastAppNameUsed = appName;
  103. }
  104. // Caller must call Win::RegCloseKey(remoteHKLM)
  105. HRESULT
  106. MainDialog::ConnectToClientRegistry(
  107. HKEY& remoteHKLM,
  108. String& clientName,
  109. String& appName)
  110. {
  111. LOG_FUNCTION(MainDialog::ConnectToClientRegistry);
  112. ASSERT(!remoteHKLM);
  113. remoteHKLM = 0;
  114. clientName = Win::GetTrimmedDlgItemText(hwnd, IDC_CLIENT_NAME);
  115. appName = Win::GetTrimmedDlgItemText(hwnd, IDC_APP_NAME);
  116. if (clientName.empty() or appName.empty())
  117. {
  118. popup.Error(
  119. hwnd,
  120. L"You need to specify a client machine and application");
  121. return E_INVALIDARG;
  122. }
  123. HRESULT hr = S_OK;
  124. do
  125. {
  126. SetStatusText(
  127. String::format(
  128. L"Attempting to attach to machine %1",
  129. clientName.c_str()));
  130. Computer comp(clientName);
  131. hr = comp.Refresh();
  132. if (FAILED(hr))
  133. {
  134. String msg =
  135. String::format(
  136. L"Can't attach to client machine %1",
  137. clientName.c_str());
  138. SetStatusText(msg);
  139. popup.Error(hwnd, hr, msg);
  140. break;
  141. }
  142. // connect to the client machine's registry
  143. hr =
  144. Win::RegConnectRegistry(
  145. comp.IsLocal() ? String() : L"\\\\" + comp.GetNetbiosName(),
  146. HKEY_LOCAL_MACHINE,
  147. remoteHKLM);
  148. if (FAILED(hr))
  149. {
  150. String msg =
  151. String::format(
  152. L"Can't connect to registry of client machine %1",
  153. clientName.c_str());
  154. SetStatusText(msg);
  155. popup.Error(hwnd, hr, msg);
  156. break;
  157. }
  158. }
  159. while (0);
  160. #ifdef DBG
  161. if (SUCCEEDED(hr))
  162. {
  163. ASSERT(remoteHKLM);
  164. }
  165. #endif
  166. return hr;
  167. }
  168. DWORD
  169. CollectFlags(HWND dialogParent)
  170. {
  171. LOG_FUNCTION(CollectFlags);
  172. ASSERT(Win::IsWindow(dialogParent));
  173. DWORD outputFlags = 0;
  174. for (int i = 0; ID_TO_FLAGMAP[i]; i += 2)
  175. {
  176. if (Win::IsDlgButtonChecked(dialogParent, ID_TO_FLAGMAP[i]))
  177. {
  178. outputFlags |= ID_TO_FLAGMAP[i + 1];
  179. }
  180. }
  181. return outputFlags;
  182. }
  183. void
  184. UpdateFlagsEdit(HWND dialogParent)
  185. {
  186. LOG_FUNCTION(UpdateFlagsEdit);
  187. ASSERT(Win::IsWindow(dialogParent));
  188. DWORD flags = CollectFlags(dialogParent);
  189. Win::SetDlgItemText(
  190. dialogParent,
  191. IDC_FLAGS,
  192. String::format(L"%1!08X!", flags));
  193. }
  194. // Set the logging options
  195. //
  196. // remoteHKLM - already opened registry handle. Not closed by this
  197. // function.
  198. HRESULT
  199. SetLoggingOptions(
  200. HWND dialogParent,
  201. HKEY remoteHKLM,
  202. const String& clientName,
  203. const String& appName)
  204. {
  205. LOG_FUNCTION(SetLoggingOptions);
  206. ASSERT(Win::IsWindow(dialogParent));
  207. ASSERT(remoteHKLM);
  208. ASSERT(!clientName.empty());
  209. ASSERT(!appName.empty());
  210. HRESULT hr = S_OK;
  211. do
  212. {
  213. String logKey = String(REG_ADMIN_RUNTIME_OPTIONS) + appName;
  214. RegistryKey key;
  215. hr = key.Create(remoteHKLM, logKey);
  216. if (FAILED(hr))
  217. {
  218. popup.Error(
  219. dialogParent,
  220. hr,
  221. String::format(
  222. L"Can't create logging registry key %1 on client machine %2",
  223. logKey.c_str(),
  224. clientName.c_str()));
  225. break;
  226. }
  227. DWORD outputFlags = CollectFlags(dialogParent);
  228. hr = key.SetValue(L"LogFlags", outputFlags);
  229. if (FAILED(hr))
  230. {
  231. popup.Error(
  232. dialogParent,
  233. hr,
  234. String::format(
  235. L"Can't set logging registry value on client machine %1",
  236. clientName.c_str()));
  237. break;
  238. }
  239. }
  240. while (0);
  241. return hr;
  242. }
  243. HRESULT
  244. MainDialog::SetFlags()
  245. {
  246. LOG_FUNCTION(MainDialog::SetFlags);
  247. HRESULT hr = S_OK;
  248. HKEY remoteHKLM = 0;
  249. String clientName;
  250. String appName;
  251. do
  252. {
  253. hr = ConnectToClientRegistry(remoteHKLM, clientName, appName);
  254. // if that failed, the connect function will have griped to the user
  255. // already, so just bail out here
  256. BREAK_ON_FAILED_HRESULT(hr);
  257. hr = SetLoggingOptions(hwnd, remoteHKLM, clientName, appName);
  258. // ditto about griping here
  259. BREAK_ON_FAILED_HRESULT(hr);
  260. }
  261. while (0);
  262. Win::RegCloseKey(remoteHKLM);
  263. if (SUCCEEDED(hr))
  264. {
  265. // Since we could successfully perform the operation, save the
  266. // client name and app name in the ui history
  267. AddToUiHistory(clientName, appName);
  268. }
  269. return hr;
  270. }
  271. void
  272. MainDialog::OnSetFlagsButton()
  273. {
  274. LOG_FUNCTION(MainDialog::OnSetFlagsButton);
  275. if (SUCCEEDED(SetFlags()))
  276. {
  277. // refresh the flags
  278. HRESULT hr = GetFlags();
  279. ASSERT(SUCCEEDED(hr));
  280. SetStatusText(L"Flags set successfully.");
  281. }
  282. }
  283. void
  284. MainDialog::OnGetFlagsButton()
  285. {
  286. LOG_FUNCTION(MainDialog::OnGetFlagsButton);
  287. if (SUCCEEDED(GetFlags()))
  288. {
  289. SetStatusText(L"Flags read successfully.");
  290. }
  291. }
  292. void
  293. MainDialog::UpdateCheckboxen(DWORD flags)
  294. {
  295. LOG_FUNCTION(MainDialog::UpdateCheckboxen);
  296. for (int i = 0; ID_TO_FLAGMAP[i]; i += 2)
  297. {
  298. Win::CheckDlgButton(
  299. hwnd,
  300. ID_TO_FLAGMAP[i],
  301. (flags & ID_TO_FLAGMAP[i + 1])
  302. ? BST_CHECKED
  303. : BST_UNCHECKED);
  304. }
  305. }
  306. void
  307. MainDialog::ResetFlagsDisplay()
  308. {
  309. LOG_FUNCTION(MainDialog::ResetFlagsDisplay);
  310. Win::SetDlgItemText(hwnd, IDC_FLAGS, L"");
  311. Win::UpdateWindow(Win::GetDlgItem(hwnd, IDC_FLAGS));
  312. // clear all the checkboxes
  313. UpdateCheckboxen(0);
  314. }
  315. HRESULT
  316. MainDialog::GetFlags()
  317. {
  318. LOG_FUNCTION(MainDialog::GetFlags);
  319. HRESULT hr = S_OK;
  320. HKEY remoteHKLM = 0;
  321. String clientName;
  322. String appName;
  323. Win::WaitCursor wait;
  324. do
  325. {
  326. ResetFlagsDisplay();
  327. hr = ConnectToClientRegistry(remoteHKLM, clientName, appName);
  328. // if that failed, the connect function will have griped to the user
  329. // already, so just bail out here
  330. BREAK_ON_FAILED_HRESULT(hr);
  331. // Set the logging options
  332. String logKey = String(REG_ADMIN_RUNTIME_OPTIONS) + appName;
  333. RegistryKey key;
  334. hr = key.Open(remoteHKLM, logKey);
  335. if (FAILED(hr))
  336. {
  337. String msg =
  338. String::format(
  339. L"Can't open logging registry key %1 on client machine %2",
  340. logKey.c_str(),
  341. clientName.c_str());
  342. SetStatusText(msg);
  343. popup.Error(hwnd, hr, msg);
  344. break;
  345. }
  346. DWORD outputFlags = 0;
  347. hr = key.GetValue(L"LogFlags", outputFlags);
  348. if (FAILED(hr))
  349. {
  350. String msg =
  351. String::format(
  352. L"Can't get logging registry value on client machine %1",
  353. clientName.c_str());
  354. SetStatusText(msg);
  355. popup.Error(hwnd, hr, msg);
  356. break;
  357. }
  358. // here, we've got the flags, so update the checkboxen
  359. UpdateCheckboxen(outputFlags);
  360. UpdateFlagsEdit(hwnd);
  361. }
  362. while (0);
  363. Win::RegCloseKey(remoteHKLM);
  364. if (SUCCEEDED(hr))
  365. {
  366. // Since we could successfully perform the operation, save the
  367. // client name and app name in the ui history
  368. AddToUiHistory(clientName, appName);
  369. }
  370. return hr;
  371. }
  372. HRESULT
  373. MainDialog::SetClientConfiguration()
  374. {
  375. LOG_FUNCTION(MainDialog::SetClientConfiguration);
  376. HRESULT hr = S_OK;
  377. HKEY remoteHKLM = 0;
  378. String clientName;
  379. String appName;
  380. Win::WaitCursor wait;
  381. do
  382. {
  383. hr = ConnectToClientRegistry(remoteHKLM, clientName, appName);
  384. // if that failed, the connect function will have griped to the user
  385. // already, so just bail out here
  386. BREAK_ON_FAILED_HRESULT(hr);
  387. // create the spewview key with the name of the server (this machine)
  388. RegistryKey key;
  389. hr =
  390. key.Create(
  391. remoteHKLM,
  392. SPEWVIEW_KEY_NAME + appName,
  393. REG_OPTION_VOLATILE);
  394. if (FAILED(hr))
  395. {
  396. popup.Error(
  397. hwnd,
  398. hr,
  399. String::format(
  400. L"Can't create spewview registry key on client machine %1",
  401. clientName.c_str()));
  402. break;
  403. }
  404. hr =
  405. key.SetValue(
  406. L"Server",
  407. Win::GetComputerNameEx(ComputerNameNetBIOS));
  408. if (FAILED(hr))
  409. {
  410. popup.Error(
  411. hwnd,
  412. hr,
  413. String::format(
  414. L"Can't set spewview server registry value on client machine %1",
  415. clientName.c_str()));
  416. break;
  417. }
  418. if (setFlagsOnStart)
  419. {
  420. hr = SetLoggingOptions(hwnd, remoteHKLM, clientName, appName);
  421. // if that failed, the function will have griped to the user already,
  422. // so just bail out here
  423. BREAK_ON_FAILED_HRESULT(hr);
  424. }
  425. }
  426. while (0);
  427. Win::RegCloseKey(remoteHKLM);
  428. if (SUCCEEDED(hr))
  429. {
  430. // Since we could successfully perform the operation, save the
  431. // client name and app name in the ui history
  432. AddToUiHistory(clientName, appName);
  433. }
  434. return hr;
  435. }
  436. void
  437. MainDialog::OnStartButton()
  438. {
  439. LOG_FUNCTION(MainDialog::OnStartButton);
  440. HRESULT hr = S_OK;
  441. do
  442. {
  443. if (spewviewer)
  444. {
  445. popup.Error(
  446. hwnd,
  447. L"Spew Viewing has already commenced.");
  448. break;
  449. }
  450. String clientName = Win::GetTrimmedDlgItemText(hwnd, IDC_CLIENT_NAME);
  451. String appName = Win::GetTrimmedDlgItemText(hwnd, IDC_APP_NAME);
  452. if (clientName.empty() or appName.empty())
  453. {
  454. popup.Error(
  455. hwnd,
  456. L"You need to specify a client machine and application");
  457. break;
  458. }
  459. if (!setFlagsOnStart)
  460. {
  461. GetFlags();
  462. }
  463. // configure the client
  464. hr = SetClientConfiguration();
  465. // if that call failed, it will have griped at the user.
  466. BREAK_ON_FAILED_HRESULT(hr);
  467. // deleted either in dtor or in WM_KILL_SPEWVIEWER handler
  468. spewviewer = new SpewDialog(clientName, appName);
  469. spewviewer->ModelessExecute(hwnd);
  470. }
  471. while (0);
  472. }
  473. bool
  474. MainDialog::OnCommand(
  475. HWND windowFrom,
  476. unsigned controlIDFrom,
  477. unsigned code)
  478. {
  479. // LOG_FUNCTION(MainDialog::OnCommand);
  480. switch (controlIDFrom)
  481. {
  482. case IDC_VIEW_SPEW:
  483. {
  484. if (code == BN_CLICKED)
  485. {
  486. OnStartButton();
  487. return true;
  488. }
  489. break;
  490. }
  491. case IDC_GET_FLAGS:
  492. {
  493. if (code == BN_CLICKED)
  494. {
  495. OnGetFlagsButton();
  496. return true;
  497. }
  498. break;
  499. }
  500. case IDC_SET_FLAGS:
  501. {
  502. if (code == BN_CLICKED)
  503. {
  504. OnSetFlagsButton();
  505. return true;
  506. }
  507. break;
  508. }
  509. case IDCANCEL:
  510. {
  511. if (code == BN_CLICKED)
  512. {
  513. // kill the spew window...
  514. Win::EndDialog(hwnd, 0);
  515. return true;
  516. }
  517. break;
  518. }
  519. case IDC_CLIENT_NAME:
  520. case IDC_APP_NAME:
  521. {
  522. if (code == CBN_EDITCHANGE)
  523. {
  524. EnableControls();
  525. }
  526. if (code == CBN_CLOSEUP)
  527. {
  528. // move the list box selection into the combo box edit control
  529. Win::SetWindowText(
  530. windowFrom,
  531. Win::ComboBox_GetCurText(windowFrom));
  532. EnableControls();
  533. }
  534. break;
  535. }
  536. case IDC_OUTPUT_TO_FILE:
  537. case IDC_OUTPUT_TO_DEBUGGER:
  538. case IDC_OUTPUT_TO_SPEWVIEW:
  539. case IDC_OUTPUT_LOGS:
  540. case IDC_OUTPUT_HEADER:
  541. case IDC_OUTPUT_ERRORS:
  542. case IDC_OUTPUT_CTORS:
  543. case IDC_OUTPUT_ADDREFS:
  544. case IDC_OUTPUT_FUNCCALLS:
  545. case IDC_OUTPUT_TIME_OF_DAY:
  546. case IDC_OUTPUT_RUN_TIME:
  547. case IDC_OUTPUT_SCOPE_EXIT:
  548. {
  549. if (code == BN_CLICKED)
  550. {
  551. UpdateFlagsEdit(hwnd);
  552. setFlagsOnStart = true;
  553. }
  554. break;
  555. }
  556. case IDC_FLAGS:
  557. {
  558. switch (code)
  559. {
  560. case EN_CHANGE:
  561. {
  562. setFlagsOnStart = true;
  563. // update the display
  564. String text = Win::GetWindowText(windowFrom);
  565. DWORD flags = 0;
  566. text.convert(flags, 16);
  567. UpdateCheckboxen(flags);
  568. break;
  569. }
  570. case EN_UPDATE:
  571. {
  572. }
  573. default:
  574. {
  575. // do nothing
  576. break;
  577. }
  578. break;
  579. }
  580. }
  581. default:
  582. {
  583. // do nothing
  584. }
  585. }
  586. return false;
  587. }
  588. void
  589. AddLastUsedNameToCombo(
  590. HWND combo,
  591. const StringList& historyList,
  592. const String& lastNameUsed)
  593. {
  594. typedef std::binder1st<String::EqualIgnoreCase> FindIfPredicate;
  595. if (!lastNameUsed.empty())
  596. {
  597. if (
  598. std::find_if(
  599. historyList.begin(),
  600. historyList.end(),
  601. FindIfPredicate(String::EqualIgnoreCase(), lastNameUsed))
  602. == historyList.end() )
  603. {
  604. // last name used not present in history list, so add it
  605. Win::ComboBox_AddString(combo, lastNameUsed);
  606. }
  607. Win::ComboBox_SelectString(combo, lastNameUsed);
  608. }
  609. }
  610. void
  611. MainDialog::OnInit()
  612. {
  613. LOG_FUNCTION(MainDialog::OnInit);
  614. LoadUiHistory();
  615. // Load the client and app name combo boxes with the historical values
  616. HWND clientCombo = Win::GetDlgItem(hwnd, IDC_CLIENT_NAME);
  617. Win::ComboBox_AddStrings(
  618. clientCombo,
  619. clientNameHistory.begin(),
  620. clientNameHistory.end());
  621. HWND appCombo = Win::GetDlgItem(hwnd, IDC_APP_NAME);
  622. Win::ComboBox_AddStrings(
  623. appCombo,
  624. appNameHistory.begin(),
  625. appNameHistory.end());
  626. AddLastUsedNameToCombo(clientCombo, clientNameHistory, lastClientNameUsed);
  627. AddLastUsedNameToCombo(appCombo, appNameHistory, lastAppNameUsed);
  628. // Limit to number of hex digits in a DWORD
  629. Win::Edit_LimitText(Win::GetDlgItem(hwnd, IDC_FLAGS), 8);
  630. SetStatusText(L"");
  631. ResetFlagsDisplay();
  632. EnableControls();
  633. }
  634. void
  635. MainDialog::LoadUiHistory()
  636. {
  637. LOG_FUNCTION(MainDialog::LoadUiHistory);
  638. HRESULT hr = S_OK;
  639. do
  640. {
  641. RegistryKey key;
  642. hr = key.Open(HKEY_LOCAL_MACHINE, SPEWVIEW_KEY_NAME);
  643. BREAK_ON_FAILED_HRESULT(hr);
  644. hr =
  645. key.GetValue(
  646. L"ClientNameHistory",
  647. std::back_inserter(clientNameHistory));
  648. LOG_HRESULT(hr);
  649. // don't break on failure, try to read the app name history too.
  650. hr =
  651. key.GetValue(
  652. L"AppNameHistory",
  653. std::back_inserter(appNameHistory));
  654. LOG_HRESULT(hr);
  655. // don't break on failure, try to read the last names used, too.
  656. hr = key.GetValue(L"LastClientNameUsed", lastClientNameUsed);
  657. LOG_HRESULT(hr);
  658. hr = key.GetValue(L"LastAppNameUsed", lastAppNameUsed);
  659. LOG_HRESULT(hr);
  660. }
  661. while (0);
  662. }
  663. void
  664. MainDialog::SaveUiHistory()
  665. {
  666. LOG_FUNCTION(MainDialog::SaveUiHistory);
  667. HRESULT hr = S_OK;
  668. do
  669. {
  670. RegistryKey key;
  671. hr = key.Create(HKEY_LOCAL_MACHINE, SPEWVIEW_KEY_NAME);
  672. BREAK_ON_FAILED_HRESULT(hr);
  673. hr =
  674. key.SetValue(
  675. L"ClientNameHistory",
  676. clientNameHistory.begin(),
  677. clientNameHistory.end());
  678. LOG_HRESULT(hr);
  679. // don't break on failure, try to write the app name history too.
  680. hr =
  681. key.SetValue(
  682. L"AppNameHistory",
  683. appNameHistory.begin(),
  684. appNameHistory.end());
  685. LOG_HRESULT(hr);
  686. // don't break on failure, try to write the last names used, too.
  687. hr = key.SetValue(L"LastClientNameUsed", lastClientNameUsed);
  688. LOG_HRESULT(hr);
  689. hr = key.SetValue(L"LastAppNameUsed", lastAppNameUsed);
  690. LOG_HRESULT(hr);
  691. }
  692. while (0);
  693. }
  694. bool
  695. MainDialog::OnMessage(
  696. UINT message,
  697. WPARAM /* wparam */ ,
  698. LPARAM /* lparam */ )
  699. {
  700. switch (message)
  701. {
  702. case WM_KILL_SPEWVIEWER:
  703. {
  704. delete spewviewer;
  705. spewviewer = 0;
  706. return true;
  707. }
  708. default:
  709. {
  710. // do nothing
  711. break;
  712. }
  713. }
  714. return false;
  715. }