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.

420 lines
8.4 KiB

  1. // Spewview: remote debug spew monitor
  2. //
  3. // Copyright (c) 2000 Microsoft Corp.
  4. //
  5. // Spew monitoring window: modeless dialog to capture spewage
  6. //
  7. // 16 Mar 2000 sburns
  8. #include "headers.hxx"
  9. #include "SpewDialog.hpp"
  10. #include "MainDialog.hpp"
  11. #include "ReaderThread.hpp"
  12. #include "resource.h"
  13. const int WM_UPDATE_SPEWAGE = WM_USER + 200;
  14. static const DWORD _help_map[] =
  15. {
  16. IDC_START, NO_HELP,
  17. IDC_STOP, NO_HELP,
  18. IDC_SPEWAGE, NO_HELP,
  19. IDC_LINE_COUNTER, NO_HELP,
  20. IDC_SELECT_ALL, NO_HELP,
  21. 0, 0
  22. };
  23. SpewDialog::SpewDialog(const String& clientName_, const String& appName_)
  24. :
  25. Dialog(IDD_SPEWAGE, _help_map),
  26. spewLineCount(0),
  27. textBoxLineCount(0),
  28. clientName(clientName_),
  29. appName(appName_),
  30. readerThreadCreated(false),
  31. endReaderThread(0)
  32. {
  33. LOG_CTOR(SpewDialog);
  34. }
  35. SpewDialog::~SpewDialog()
  36. {
  37. LOG_DTOR(SpewDialog);
  38. StopReadingSpewage();
  39. }
  40. void
  41. SpewDialog::OnStartButton()
  42. {
  43. LOG_FUNCTION(SpewDialog::OnStartButton);
  44. if (!readerThreadCreated)
  45. {
  46. Win::EnableWindow(Win::GetDlgItem(hwnd, IDC_START), false);
  47. StartReadingSpewage();
  48. }
  49. }
  50. void
  51. SpewDialog::OnStopButton()
  52. {
  53. LOG_FUNCTION(SpewDialog::OnStopButton);
  54. StopReadingSpewage();
  55. }
  56. bool
  57. SpewDialog::OnCommand(
  58. HWND /* windowFrom */ ,
  59. unsigned controlIDFrom,
  60. unsigned code)
  61. {
  62. switch (controlIDFrom)
  63. {
  64. case IDC_START:
  65. {
  66. if (code == BN_CLICKED)
  67. {
  68. OnStartButton();
  69. return true;
  70. }
  71. break;
  72. }
  73. case IDC_STOP:
  74. {
  75. if (code == BN_CLICKED)
  76. {
  77. OnStopButton();
  78. return true;
  79. }
  80. break;
  81. }
  82. case IDC_SELECT_ALL:
  83. {
  84. break;
  85. }
  86. case IDCANCEL:
  87. {
  88. if (code == BN_CLICKED)
  89. {
  90. // signal the reader thread to die.
  91. StopReadingSpewage();
  92. // signal the main dialog to kill us
  93. Win::PostMessage(
  94. Win::GetParent(hwnd),
  95. MainDialog::WM_KILL_SPEWVIEWER,
  96. 0,
  97. 0);
  98. return true;
  99. }
  100. break;
  101. }
  102. default:
  103. {
  104. // do nothing
  105. }
  106. }
  107. return false;
  108. }
  109. void
  110. SpewDialog::ResizeSpewWindow(int newParentWidth, int newParentHeight)
  111. {
  112. HRESULT hr = S_OK;
  113. HWND spewWindow = Win::GetDlgItem(hwnd, IDC_SPEWAGE);
  114. do
  115. {
  116. hr =
  117. Win::SetWindowPos(
  118. spewWindow,
  119. 0,
  120. 0,
  121. 0,
  122. newParentWidth - margins.left - margins.right,
  123. newParentHeight - margins.top - margins.bottom,
  124. SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER);
  125. BREAK_ON_FAILED_HRESULT(hr);
  126. }
  127. while (0);
  128. }
  129. bool
  130. SpewDialog::OnMessage(
  131. UINT message,
  132. WPARAM wparam,
  133. LPARAM lparam)
  134. {
  135. switch (message)
  136. {
  137. case WM_UPDATE_SPEWAGE:
  138. {
  139. // lparam is pointer to spewage buffer to dump into the edit
  140. // box.
  141. ASSERT(lparam);
  142. if (lparam)
  143. {
  144. String* spew = reinterpret_cast<String*>(lparam);
  145. ASSERT(!spew->empty());
  146. AppendMessage(wparam, *spew);
  147. delete spew;
  148. }
  149. return true;
  150. }
  151. case WM_ENABLE_START:
  152. {
  153. // The reader thread has disconnected and closed the pipe, and is
  154. // (nearly) dead, so it's ok to allow another reader thread to be
  155. // started.
  156. Win::EnableWindow(Win::GetDlgItem(hwnd, IDC_START), true);
  157. return true;
  158. }
  159. case WM_SIZE:
  160. {
  161. int newDlgWidth = LOWORD(lparam);
  162. int newDlgHeight = HIWORD(lparam);
  163. ResizeSpewWindow(newDlgWidth, newDlgHeight);
  164. return false;
  165. }
  166. default:
  167. {
  168. // do nothing;
  169. break;
  170. }
  171. }
  172. return false;
  173. }
  174. void
  175. SpewDialog::AppendMessage(WPARAM wparam, const String& message)
  176. {
  177. bool isSpew = (wparam != -1);
  178. if (isSpew)
  179. {
  180. ++spewLineCount;
  181. Win::SetDlgItemText(
  182. hwnd,
  183. IDC_LINE_COUNTER,
  184. String::format(L"%1!010d!", spewLineCount));
  185. }
  186. Win::Edit_AppendText(
  187. Win::GetDlgItem(hwnd, IDC_SPEWAGE),
  188. isSpew ? message : L">>>> " + message);
  189. ++textBoxLineCount;
  190. }
  191. void
  192. SpewDialog::OnInit()
  193. {
  194. LOG_FUNCTION(SpewDialog::OnInit);
  195. Win::SetWindowText(
  196. hwnd,
  197. String::format(
  198. L"Spewage from %1 on machine %2",
  199. appName.c_str(),
  200. clientName.c_str()));
  201. spewLineCount = 0;
  202. Win::SetDlgItemText(
  203. hwnd,
  204. IDC_LINE_COUNTER,
  205. String::format(L"%1!010d!", spewLineCount));
  206. // extend the amount of text that can be inserted into the spew
  207. // rich edit control
  208. HWND spewWindow = Win::GetDlgItem(hwnd, IDC_SPEWAGE);
  209. Win::SendMessage(
  210. spewWindow,
  211. EM_EXLIMITTEXT,
  212. 0,
  213. // 256K characters.
  214. (1 << 18));
  215. // Change the font in the spew window to fixed-width
  216. do
  217. {
  218. static String SPEW_FONT_NAME = L"Lucida Console";
  219. LOGFONT logFont;
  220. memset(&logFont, 0, sizeof(LOGFONT));
  221. SPEW_FONT_NAME.copy(
  222. logFont.lfFaceName,
  223. // don't copy over the last null
  224. min(LF_FACESIZE - 1, SPEW_FONT_NAME.length()));
  225. HDC hdc = 0;
  226. HRESULT hr = Win::GetDC(hwnd, hdc);
  227. BREAK_ON_FAILED_HRESULT(hr);
  228. logFont.lfHeight =
  229. - ::MulDiv(8, Win::GetDeviceCaps(hdc, LOGPIXELSY), 72);
  230. Win::ReleaseDC(hwnd, hdc);
  231. HFONT font = 0;
  232. hr = Win::CreateFontIndirect(logFont, font);
  233. BREAK_ON_FAILED_HRESULT(hr);
  234. Win::SetWindowFont(spewWindow, font, false);
  235. }
  236. while (0);
  237. ComputeMargins();
  238. // Disable the start button, as we start upon initialization
  239. Win::EnableWindow(Win::GetDlgItem(hwnd, IDC_START), false);
  240. // Start the reader thread. This will create and connect to the spew
  241. // pipe, and start reading messages from it.
  242. StartReadingSpewage();
  243. }
  244. void
  245. SpewDialog::ComputeMargins()
  246. {
  247. LOG_FUNCTION(SpewDialog::ComputeMargins);
  248. memset(&margins, 0, sizeof(margins));
  249. HRESULT hr = S_OK;
  250. do
  251. {
  252. HWND spewWindow = Win::GetDlgItem(hwnd, IDC_SPEWAGE);
  253. // get the current dimmensions of the dialog
  254. // use the client rect to remove non-client area from consideration
  255. RECT parentRect;
  256. hr = Win::GetClientRect(hwnd, parentRect);
  257. BREAK_ON_FAILED_HRESULT(hr);
  258. hr = Win::MapWindowPoints(hwnd, 0, parentRect);
  259. BREAK_ON_FAILED_HRESULT(hr);
  260. // get the dimmensions of the spew window, relative to the
  261. // parent dialog
  262. RECT spewRect;
  263. hr = Win::GetWindowRect(spewWindow, spewRect);
  264. BREAK_ON_FAILED_HRESULT(hr);
  265. // compute the margins between the spew window and the parent dialog
  266. margins.bottom = parentRect.bottom - spewRect.bottom;
  267. margins.right = parentRect.right - spewRect.right;
  268. margins.left = spewRect.left - parentRect.left;
  269. margins.top = spewRect.top - parentRect.top;
  270. }
  271. while (0);
  272. }
  273. void
  274. SpewDialog::StartReadingSpewage()
  275. {
  276. LOG_FUNCTION(SpewDialog::StartReadingSpewage);
  277. if (!readerThreadCreated)
  278. {
  279. // deleted in readerThreadProc
  280. ReaderThreadParams* params = new ReaderThreadParams;
  281. params->hwnd = hwnd;
  282. params->endFlag = &endReaderThread;
  283. params->appName = appName;
  284. // endReaderThread is shared among this thread and the thread we are
  285. // about to spawn. It does not need guarding, because it is an atomic
  286. // data type (int), and because we do not care about the order in which
  287. // the threads read/write to it. Further, this thread only writes to
  288. // the value, and the reader thread only reads it.
  289. endReaderThread = 0;
  290. // start the reader thread a-runnin'
  291. _beginthread(ReaderThreadProc, 0, params);
  292. readerThreadCreated = true;
  293. }
  294. }
  295. void
  296. SpewDialog::StopReadingSpewage()
  297. {
  298. LOG_FUNCTION(SpewDialog::StopReadingSpewage);
  299. if (readerThreadCreated)
  300. {
  301. // Tell the reader thread to die. This will cause the pipe to be
  302. // disconnected and closed, and a message sent (to this window)
  303. // that the start button can be enabled again.
  304. endReaderThread = 1;
  305. // We check for this in the start procedure. Since the start button
  306. // can't be enabled until the thread is about to die, we are safe
  307. // from a race condition where the user starts two reader threads.
  308. readerThreadCreated = false;
  309. }
  310. }