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.

633 lines
16 KiB

  1. /*++
  2. Copyright (c) 1993-2002 Microsoft Corporation
  3. Module Name:
  4. notify.cpp
  5. Abstract:
  6. This file implements the functions that make use of the common
  7. file open dialogs for browsing for files/directories.
  8. Author:
  9. Wesley Witt (wesw) 1-May-1993
  10. Environment:
  11. User Mode
  12. --*/
  13. #include "pch.cpp"
  14. //
  15. // defines
  16. //
  17. #define DEFAULT_WAIT_TIME (1000 * 60 * 5) // wait for 5 minutes
  18. #define MAX_PRINTF_BUF_SIZE (1024 * 4)
  19. HANDLE hThreadDebug = 0;
  20. PDEBUGPACKET dp;
  21. INT_PTR
  22. CALLBACK
  23. NotifyDialogProc (
  24. HWND hwnd,
  25. UINT message,
  26. WPARAM wParam,
  27. LPARAM lParam
  28. );
  29. INT_PTR
  30. CALLBACK
  31. UsageDialogProc (
  32. HWND hDlg,
  33. UINT message,
  34. WPARAM wParam,
  35. LPARAM lParam
  36. );
  37. void
  38. NotifyWinMain (
  39. void
  40. )
  41. /*++
  42. Routine Description:
  43. This is the entry point for DRWTSN32
  44. Arguments:
  45. None.
  46. Return Value:
  47. None.
  48. --*/
  49. {
  50. MSG msg;
  51. DWORD dwThreadId;
  52. HINSTANCE hInst;
  53. dp = (PDEBUGPACKET) calloc( sizeof(DEBUGPACKET), sizeof(BYTE) );
  54. if ( dp == NULL) {
  55. return;
  56. }
  57. GetCommandLineArgs( &dp->dwPidToDebug, &dp->hEventToSignal );
  58. RegInitialize( &dp->options );
  59. if (dp->options.fVisual) {
  60. WNDCLASS wndclass;
  61. hInst = GetModuleHandle( NULL );
  62. wndclass.style = CS_HREDRAW | CS_VREDRAW;
  63. wndclass.lpfnWndProc = (WNDPROC)NotifyDialogProc;
  64. wndclass.cbClsExtra = 0;
  65. wndclass.cbWndExtra = DLGWINDOWEXTRA;
  66. wndclass.hInstance = hInst;
  67. wndclass.hIcon = LoadIcon( hInst, MAKEINTRESOURCE(APPICON) );
  68. wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
  69. wndclass.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
  70. wndclass.lpszMenuName = NULL;
  71. wndclass.lpszClassName = _T("NotifyDialog");
  72. RegisterClass( &wndclass );
  73. dp->hwnd = CreateDialog( hInst,
  74. MAKEINTRESOURCE( NOTIFYDIALOG ),
  75. 0,
  76. NotifyDialogProc );
  77. if (dp->hwnd == NULL) {
  78. return;
  79. }
  80. }
  81. hThreadDebug = CreateThread( NULL,
  82. 16000,
  83. (LPTHREAD_START_ROUTINE)DispatchDebugEventThread,
  84. dp,
  85. 0,
  86. &dwThreadId
  87. );
  88. if (hThreadDebug == NULL) {
  89. return;
  90. }
  91. if (dp->options.fSound) {
  92. if ((waveOutGetNumDevs() == 0) || (!_tcslen(dp->options.szWaveFile))) {
  93. MessageBeep( MB_ICONHAND );
  94. MessageBeep( MB_ICONHAND );
  95. }
  96. else {
  97. PlaySound( dp->options.szWaveFile, NULL, SND_FILENAME );
  98. }
  99. }
  100. if (dp->options.fVisual) {
  101. ShowWindow( dp->hwnd, SW_SHOWNORMAL );
  102. while (GetMessage (&msg, NULL, 0, 0)) {
  103. if (!IsDialogMessage( dp->hwnd, &msg )) {
  104. TranslateMessage (&msg) ;
  105. DispatchMessage (&msg) ;
  106. }
  107. }
  108. }
  109. else {
  110. WaitForSingleObject( hThreadDebug, INFINITE );
  111. }
  112. CloseHandle( hThreadDebug );
  113. return;
  114. }
  115. INT_PTR
  116. CALLBACK
  117. NotifyDialogProc (
  118. HWND hwnd,
  119. UINT message,
  120. WPARAM wParam,
  121. LPARAM lParam
  122. )
  123. /*++
  124. Routine Description:
  125. Window procedure for the DRWTSN32.EXE popup. This is the popup
  126. that is displayed when an application error occurs.
  127. Arguments:
  128. hwnd - window handle to the dialog box
  129. message - message number
  130. wParam - first message parameter
  131. lParam - second message parameter
  132. Return Value:
  133. TRUE - did not process the message
  134. FALSE - did process the message
  135. --*/
  136. {
  137. DWORD dwThreadId;
  138. DWORD dwSize;
  139. HANDLE hThread;
  140. _TCHAR szTaskName[MAX_PATH];
  141. static DWORD AttachComplete=FALSE;
  142. static DWORD Cancel=FALSE;
  143. _TCHAR buf[MAX_PRINTF_BUF_SIZE];
  144. switch (message) {
  145. case WM_CREATE:
  146. return FALSE;
  147. case WM_INITDIALOG:
  148. SubclassControls( hwnd );
  149. //
  150. // OK is hidden until the debugger thread finishes
  151. //
  152. ShowWindow( GetDlgItem( hwnd, IDOK ), SW_HIDE );
  153. //
  154. // CANCEL is enabled right away
  155. //
  156. EnableWindow( GetDlgItem( hwnd, IDCANCEL ), TRUE );
  157. //
  158. // make sure that the user can see the dialog box
  159. //
  160. SetForegroundWindow( hwnd );
  161. //
  162. // get the task name and display it on the dialog box
  163. //
  164. dwSize = sizeof(szTaskName) / sizeof(_TCHAR);
  165. GetTaskName( dp->dwPidToDebug, szTaskName, &dwSize );
  166. //
  167. // prevent recursion in the case where drwatson faults
  168. //
  169. if (_tcsicmp(szTaskName, _T("drwtsn32")) == 0) {
  170. ExitProcess(0);
  171. }
  172. //
  173. // Add the text in the dialog box
  174. //
  175. memset(buf,0,sizeof(buf));
  176. GetNotifyBuf( buf, MAX_PRINTF_BUF_SIZE, MSG_NOTIFY, szTaskName );
  177. SetDlgItemText( hwnd, ID_TEXT1, buf);
  178. memset(buf,0,sizeof(buf));
  179. GetNotifyBuf( buf, MAX_PRINTF_BUF_SIZE, MSG_NOTIFY2 );
  180. SetDlgItemText( hwnd, ID_TEXT2, buf );
  181. return TRUE;
  182. case WM_ACTIVATEAPP:
  183. case WM_SETFOCUS:
  184. SetFocusToCurrentControl();
  185. return 0;
  186. case WM_TIMER:
  187. SendMessage( hwnd, WM_COMMAND, IDOK, 0 );
  188. return 0;
  189. case WM_COMMAND:
  190. switch (wParam) {
  191. case IDOK:
  192. SendMessage( hwnd, WM_DESTROY, 0, 0 );
  193. break;
  194. case IDCANCEL:
  195. Cancel = TRUE;
  196. // Make the window go away, but don't kill the
  197. // the process until the WM_ATTACHCOMPLETE has
  198. // occurred
  199. ShowWindow( hwnd, SW_HIDE );
  200. SendMessage( hwnd, WM_FINISH, 0, 0 );
  201. // Delete the dump file, since its invalid anyway
  202. DeleteCrashDump();
  203. break;
  204. }
  205. break;
  206. case WM_NEXTDLGCTL:
  207. DefDlgProc( hwnd, message, wParam, lParam );
  208. return 0;
  209. case WM_DUMPCOMPLETE:
  210. //
  211. // the message is received from the debugger thread
  212. // when the postmortem dump is finished. all we need to do
  213. // is enable the OK button and wait for the user to press the
  214. // OK button or for the timer to expire. in either case
  215. // DrWatson will terminate.
  216. //
  217. // Disable and hide the Cancel button
  218. EnableWindow( GetDlgItem( hwnd, IDCANCEL ), FALSE);
  219. ShowWindow( GetDlgItem(hwnd, IDCANCEL ), SW_HIDE);
  220. // Show and Enable the OK button
  221. ShowWindow( GetDlgItem( hwnd, IDOK ), SW_SHOW);
  222. EnableWindow( GetDlgItem( hwnd, IDOK ), TRUE );
  223. SetFocus( GetDlgItem(hwnd, IDOK) );
  224. SetFocusToCurrentControl();
  225. SetTimer( hwnd, 1, DEFAULT_WAIT_TIME, NULL );
  226. return 0;
  227. case WM_ATTACHCOMPLETE:
  228. //
  229. // the message is received from the debugger thread when
  230. // the debugactiveprocess() is completed.
  231. //
  232. AttachComplete = TRUE;
  233. SendMessage( hwnd, WM_FINISH, 0, 0 );
  234. return 0;
  235. case WM_FINISH:
  236. if (AttachComplete && Cancel) {
  237. //
  238. // terminate the debugger thread
  239. //
  240. if ( hThreadDebug ) TerminateThread( hThreadDebug, 0 );
  241. //
  242. // create a thread to terminate the debuggee
  243. // this is necessary if cancel is pressed before the
  244. // debugger thread finishes the postmortem dump
  245. //
  246. hThread = CreateThread( NULL,
  247. 16000,
  248. (LPTHREAD_START_ROUTINE)TerminationThread,
  249. dp,
  250. 0,
  251. &dwThreadId
  252. );
  253. //
  254. // wait for the termination thread to kill the debuggee
  255. //
  256. WaitForSingleObject( hThread, 30000 );
  257. CloseHandle( hThread );
  258. //
  259. // now post a quit message so that DrWatson will go away
  260. //
  261. SendMessage( hwnd, WM_DESTROY, 0, 0 );
  262. }
  263. return 0;
  264. case WM_EXCEPTIONINFO:
  265. return 0;
  266. case WM_DESTROY:
  267. KillTimer( hwnd, 1 );
  268. PostQuitMessage( 0 );
  269. return 0;
  270. }
  271. return DefWindowProc( hwnd, message, wParam, lParam );
  272. }
  273. BOOLEAN
  274. GetCommandLineArgs(
  275. LPDWORD dwPidToDebug,
  276. LPHANDLE hEventToSignal
  277. )
  278. /*++
  279. Routine Description:
  280. Parses the command line for the 3 possible command lines
  281. arguments:
  282. -p %ld process id
  283. -e %ld event id
  284. -g go
  285. Arguments:
  286. dwPidToDebug - Returns the process id of the process to debug
  287. hEventToSignal - Returns the handle to an event which will be signalled
  288. when the attach is complete.
  289. Return Value:
  290. None.
  291. --*/
  292. {
  293. _TCHAR *lpstrCmd = GetCommandLine();
  294. _TUCHAR ch;
  295. _TCHAR buf[4096];
  296. BOOLEAN rval = FALSE;
  297. BOOLEAN ParsedEvent = FALSE;
  298. BOOLEAN ParsedPid = FALSE;
  299. // skip over program name
  300. do {
  301. ch = *lpstrCmd++;
  302. }
  303. while (ch != _T(' ') && ch != _T('\t') && ch != _T('\0'));
  304. // skip over any following white space
  305. while (ch == _T(' ') || ch == _T('\t')) {
  306. ch = *lpstrCmd++;
  307. }
  308. // process each switch character _T('-') as encountered
  309. while (ch == _T('-')) {
  310. ch = *lpstrCmd++;
  311. // process multiple switch characters as needed
  312. do {
  313. switch (ch) {
  314. case _T('e'):
  315. case _T('E'):
  316. // event to signal takes decimal argument
  317. // skip whitespace
  318. do {
  319. ch = *lpstrCmd++;
  320. }
  321. while (ch == _T(' ') || ch == _T('\t'));
  322. while (ch >= _T('0') && ch <= _T('9')) {
  323. if (!ParsedEvent) {
  324. *hEventToSignal = (HANDLE)
  325. ((DWORD_PTR)*hEventToSignal * 10 + ch - _T('0'));
  326. }
  327. ch = *lpstrCmd++;
  328. }
  329. rval = TRUE;
  330. ParsedEvent = TRUE;
  331. break;
  332. case _T('p'):
  333. case _T('P'):
  334. // pid debug takes decimal argument
  335. do
  336. ch = *lpstrCmd++;
  337. while (ch == _T(' ') || ch == _T('\t'));
  338. if ( ch == _T('-') ) {
  339. ch = *lpstrCmd++;
  340. if ( ch == _T('1') ) {
  341. if (!ParsedPid) {
  342. *dwPidToDebug = (DWORD)-1;
  343. }
  344. ch = *lpstrCmd++;
  345. }
  346. }
  347. else {
  348. while (ch >= _T('0') && ch <= _T('9')) {
  349. if (!ParsedPid) {
  350. *dwPidToDebug =
  351. *dwPidToDebug * 10 + ch - _T('0');
  352. }
  353. ch = *lpstrCmd++;
  354. }
  355. }
  356. rval = TRUE;
  357. ParsedPid = TRUE;
  358. break;
  359. case _T('g'):
  360. case _T('G'):
  361. // GO
  362. // Ignored but provided for compatiblity with windbg & ntsd
  363. ch = *lpstrCmd++;
  364. break;
  365. case _T('?'):
  366. DialogBox( GetModuleHandle(NULL),
  367. MAKEINTRESOURCE(USAGEDIALOG),
  368. NULL,
  369. UsageDialogProc
  370. );
  371. rval = TRUE;
  372. ch = *lpstrCmd++;
  373. break;
  374. case _T('i'):
  375. case _T('I'):
  376. FormatMessage(
  377. FORMAT_MESSAGE_FROM_HMODULE,
  378. NULL,
  379. MSG_INSTALL_NOTIFY,
  380. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  381. buf,
  382. sizeof(buf) / sizeof(_TCHAR),
  383. NULL
  384. );
  385. RegInstallDrWatson( tolower(lpstrCmd[0]) == _T('q') );
  386. MessageBox( NULL,
  387. buf,
  388. _T("Dr. Watson"),
  389. MB_ICONINFORMATION | MB_OK |
  390. MB_SETFOREGROUND );
  391. rval = TRUE;
  392. ch = *lpstrCmd++;
  393. break;
  394. default:
  395. return rval;
  396. }
  397. } while (ch != _T(' ') && ch != _T('\t') && ch != _T('\0'));
  398. while (ch == _T(' ') || ch == _T('\t')) {
  399. ch = *lpstrCmd++;
  400. }
  401. }
  402. return rval;
  403. }
  404. INT_PTR
  405. CALLBACK
  406. UsageDialogProc (
  407. HWND hDlg,
  408. UINT message,
  409. WPARAM wParam,
  410. LPARAM lParam
  411. )
  412. /*++
  413. Routine Description:
  414. This is the dialog procedure for the assert dialog box. Normally
  415. an assertion box is simply a message box but in this case a Help
  416. button is desired so a dialog box is used.
  417. Arguments:
  418. hDlg - window handle to the dialog box
  419. message - message number
  420. wParam - first message parameter
  421. lParam - second message parameter
  422. Return Value:
  423. TRUE - did not process the message
  424. FALSE - did process the message
  425. --*/
  426. {
  427. _TCHAR buf[4096];
  428. switch (message) {
  429. case WM_INITDIALOG:
  430. FormatMessage(
  431. FORMAT_MESSAGE_FROM_HMODULE,
  432. NULL,
  433. MSG_USAGE,
  434. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  435. buf,
  436. sizeof(buf) / sizeof(_TCHAR),
  437. NULL
  438. );
  439. SetDlgItemText( hDlg, ID_USAGE, buf );
  440. break;
  441. case WM_COMMAND:
  442. switch (wParam) {
  443. case IDOK:
  444. EndDialog( hDlg, 0 );
  445. break;
  446. }
  447. break;
  448. }
  449. return FALSE;
  450. }
  451. void
  452. __cdecl
  453. GetNotifyBuf(
  454. LPTSTR buf,
  455. DWORD bufsize,
  456. DWORD dwFormatId,
  457. ...
  458. )
  459. /*++
  460. Routine Description:
  461. This is function is a printf style function for printing messages
  462. in a message file.
  463. Arguments:
  464. dwFormatId - format id in the message file
  465. ... - var args
  466. Return Value:
  467. None.
  468. --*/
  469. {
  470. DWORD dwCount;
  471. va_list args;
  472. va_start( args, dwFormatId );
  473. dwCount = FormatMessage(
  474. FORMAT_MESSAGE_FROM_HMODULE,
  475. NULL,
  476. dwFormatId,
  477. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //Default language
  478. buf,
  479. bufsize,
  480. &args
  481. );
  482. va_end(args);
  483. Assert( dwCount != 0 );
  484. return;
  485. }