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.

622 lines
15 KiB

  1. /*++
  2. Copyright (c) 1993-2001 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. _TCHAR szHelpFileName[MAX_PATH];
  142. static DWORD AttachComplete=FALSE;
  143. static DWORD Cancel=FALSE;
  144. _TCHAR buf[MAX_PRINTF_BUF_SIZE];
  145. switch (message) {
  146. case WM_CREATE:
  147. return FALSE;
  148. case WM_INITDIALOG:
  149. SubclassControls( hwnd );
  150. //
  151. // OK is hidden until the debugger thread finishes
  152. //
  153. ShowWindow( GetDlgItem( hwnd, IDOK ), SW_HIDE );
  154. //
  155. // CANCEL is enabled right away
  156. //
  157. EnableWindow( GetDlgItem( hwnd, IDCANCEL ), TRUE );
  158. //
  159. // make sure that the user can see the dialog box
  160. //
  161. SetForegroundWindow( hwnd );
  162. //
  163. // get the task name and display it on the dialog box
  164. //
  165. dwSize = sizeof(szTaskName) / sizeof(_TCHAR);
  166. GetTaskName( dp->dwPidToDebug, szTaskName, &dwSize );
  167. //
  168. // prevent recursion in the case where drwatson faults
  169. //
  170. if (_tcsicmp(szTaskName, _T("drwtsn32")) == 0) {
  171. ExitProcess(0);
  172. }
  173. //
  174. // Add the text in the dialog box
  175. //
  176. memset(buf,0,sizeof(buf));
  177. GetNotifyBuf( buf, MAX_PRINTF_BUF_SIZE, MSG_NOTIFY, szTaskName );
  178. SetDlgItemText( hwnd, ID_TEXT1, buf);
  179. memset(buf,0,sizeof(buf));
  180. GetNotifyBuf( buf, MAX_PRINTF_BUF_SIZE, MSG_NOTIFY2 );
  181. SetDlgItemText( hwnd, ID_TEXT2, buf );
  182. return TRUE;
  183. case WM_ACTIVATEAPP:
  184. case WM_SETFOCUS:
  185. SetFocusToCurrentControl();
  186. return 0;
  187. case WM_TIMER:
  188. SendMessage( hwnd, WM_COMMAND, IDOK, 0 );
  189. return 0;
  190. case WM_COMMAND:
  191. switch (wParam) {
  192. case IDOK:
  193. SendMessage( hwnd, WM_DESTROY, 0, 0 );
  194. break;
  195. case IDCANCEL:
  196. Cancel = TRUE;
  197. // Make the window go away, but don't kill the
  198. // the process until the WM_ATTACHCOMPLETE has
  199. // occurred
  200. ShowWindow( hwnd, SW_HIDE );
  201. SendMessage( hwnd, WM_FINISH, 0, 0 );
  202. // Delete the dump file, since its invalid anyway
  203. DeleteCrashDump();
  204. break;
  205. }
  206. break;
  207. case WM_NEXTDLGCTL:
  208. DefDlgProc( hwnd, message, wParam, lParam );
  209. return 0;
  210. case WM_DUMPCOMPLETE:
  211. //
  212. // the message is received from the debugger thread
  213. // when the postmortem dump is finished. all we need to do
  214. // is enable the OK button and wait for the user to press the
  215. // OK button or for the timer to expire. in either case
  216. // DrWatson will terminate.
  217. //
  218. // Disable and hide the Cancel button
  219. EnableWindow( GetDlgItem( hwnd, IDCANCEL ), FALSE);
  220. ShowWindow( GetDlgItem(hwnd, IDCANCEL ), SW_HIDE);
  221. // Show and Enable the OK button
  222. ShowWindow( GetDlgItem( hwnd, IDOK ), SW_SHOW);
  223. EnableWindow( GetDlgItem( hwnd, IDOK ), TRUE );
  224. SetFocus( GetDlgItem(hwnd, IDOK) );
  225. SetFocusToCurrentControl();
  226. SetTimer( hwnd, 1, DEFAULT_WAIT_TIME, NULL );
  227. return 0;
  228. case WM_ATTACHCOMPLETE:
  229. //
  230. // the message is received from the debugger thread when
  231. // the debugactiveprocess() is completed.
  232. //
  233. AttachComplete = TRUE;
  234. SendMessage( hwnd, WM_FINISH, 0, 0 );
  235. return 0;
  236. case WM_FINISH:
  237. if (AttachComplete && Cancel) {
  238. //
  239. // terminate the debugger thread
  240. //
  241. if ( hThreadDebug ) TerminateThread( hThreadDebug, 0 );
  242. //
  243. // create a thread to terminate the debuggee
  244. // this is necessary if cancel is pressed before the
  245. // debugger thread finishes the postmortem dump
  246. //
  247. hThread = CreateThread( NULL,
  248. 16000,
  249. (LPTHREAD_START_ROUTINE)TerminationThread,
  250. dp,
  251. 0,
  252. &dwThreadId
  253. );
  254. //
  255. // wait for the termination thread to kill the debuggee
  256. //
  257. WaitForSingleObject( hThread, 30000 );
  258. CloseHandle( hThread );
  259. //
  260. // now post a quit message so that DrWatson will go away
  261. //
  262. SendMessage( hwnd, WM_DESTROY, 0, 0 );
  263. }
  264. return 0;
  265. case WM_EXCEPTIONINFO:
  266. return 0;
  267. case WM_DESTROY:
  268. KillTimer( hwnd, 1 );
  269. PostQuitMessage( 0 );
  270. return 0;
  271. }
  272. return DefWindowProc( hwnd, message, wParam, lParam );
  273. }
  274. BOOLEAN
  275. GetCommandLineArgs(
  276. LPDWORD dwPidToDebug,
  277. LPHANDLE hEventToSignal
  278. )
  279. /*++
  280. Routine Description:
  281. Parses the command line for the 3 possible command lines
  282. arguments:
  283. -p %ld process id
  284. -e %ld event id
  285. -g go
  286. Arguments:
  287. dwPidToDebug - Returns the process id of the process to debug
  288. hEventToSignal - Returns the handle to an event which will be signalled
  289. when the attach is complete.
  290. Return Value:
  291. None.
  292. --*/
  293. {
  294. _TCHAR *lpstrCmd = GetCommandLine();
  295. _TUCHAR ch;
  296. _TCHAR buf[4096];
  297. BOOLEAN rval = FALSE;
  298. // skip over program name
  299. do {
  300. ch = *lpstrCmd++;
  301. }
  302. while (ch != _T(' ') && ch != _T('\t') && ch != _T('\0'));
  303. // skip over any following white space
  304. while (ch == _T(' ') || ch == _T('\t')) {
  305. ch = *lpstrCmd++;
  306. }
  307. // process each switch character _T('-') as encountered
  308. while (ch == _T('-')) {
  309. ch = *lpstrCmd++;
  310. // process multiple switch characters as needed
  311. do {
  312. switch (ch) {
  313. case _T('e'):
  314. case _T('E'):
  315. // event to signal takes decimal argument
  316. // skip whitespace
  317. do {
  318. ch = *lpstrCmd++;
  319. }
  320. while (ch == _T(' ') || ch == _T('\t'));
  321. while (ch >= _T('0') && ch <= _T('9')) {
  322. *hEventToSignal = (HANDLE)((DWORD_PTR)*hEventToSignal * 10 + ch - _T('0'));
  323. ch = *lpstrCmd++;
  324. }
  325. rval = TRUE;
  326. break;
  327. case _T('p'):
  328. case _T('P'):
  329. // pid debug takes decimal argument
  330. do
  331. ch = *lpstrCmd++;
  332. while (ch == _T(' ') || ch == _T('\t'));
  333. if ( ch == _T('-') ) {
  334. ch = *lpstrCmd++;
  335. if ( ch == _T('1') ) {
  336. *dwPidToDebug = (DWORD)-1;
  337. ch = *lpstrCmd++;
  338. }
  339. }
  340. else {
  341. while (ch >= _T('0') && ch <= _T('9')) {
  342. *dwPidToDebug = *dwPidToDebug * 10 + ch - _T('0');
  343. ch = *lpstrCmd++;
  344. }
  345. }
  346. rval = TRUE;
  347. break;
  348. case _T('g'):
  349. case _T('G'):
  350. // GO
  351. // Ignored but provided for compatiblity with windbg & ntsd
  352. ch = *lpstrCmd++;
  353. break;
  354. case _T('?'):
  355. DialogBox( GetModuleHandle(NULL),
  356. MAKEINTRESOURCE(USAGEDIALOG),
  357. NULL,
  358. UsageDialogProc
  359. );
  360. rval = TRUE;
  361. ch = *lpstrCmd++;
  362. break;
  363. case _T('i'):
  364. case _T('I'):
  365. FormatMessage(
  366. FORMAT_MESSAGE_FROM_HMODULE,
  367. NULL,
  368. MSG_INSTALL_NOTIFY,
  369. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  370. buf,
  371. sizeof(buf) / sizeof(_TCHAR),
  372. NULL
  373. );
  374. RegInstallDrWatson( tolower(lpstrCmd[0]) == _T('q') );
  375. MessageBox( NULL,
  376. buf,
  377. _T("Dr. Watson"),
  378. MB_ICONINFORMATION | MB_OK |
  379. MB_SETFOREGROUND );
  380. rval = TRUE;
  381. ch = *lpstrCmd++;
  382. break;
  383. default:
  384. return rval;
  385. }
  386. } while (ch != _T(' ') && ch != _T('\t') && ch != _T('\0'));
  387. while (ch == _T(' ') || ch == _T('\t')) {
  388. ch = *lpstrCmd++;
  389. }
  390. }
  391. return rval;
  392. }
  393. INT_PTR
  394. CALLBACK
  395. UsageDialogProc (
  396. HWND hDlg,
  397. UINT message,
  398. WPARAM wParam,
  399. LPARAM lParam
  400. )
  401. /*++
  402. Routine Description:
  403. This is the dialog procedure for the assert dialog box. Normally
  404. an assertion box is simply a message box but in this case a Help
  405. button is desired so a dialog box is used.
  406. Arguments:
  407. hDlg - window handle to the dialog box
  408. message - message number
  409. wParam - first message parameter
  410. lParam - second message parameter
  411. Return Value:
  412. TRUE - did not process the message
  413. FALSE - did process the message
  414. --*/
  415. {
  416. _TCHAR buf[4096];
  417. switch (message) {
  418. case WM_INITDIALOG:
  419. FormatMessage(
  420. FORMAT_MESSAGE_FROM_HMODULE,
  421. NULL,
  422. MSG_USAGE,
  423. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  424. buf,
  425. sizeof(buf) / sizeof(_TCHAR),
  426. NULL
  427. );
  428. SetDlgItemText( hDlg, ID_USAGE, buf );
  429. break;
  430. case WM_COMMAND:
  431. switch (wParam) {
  432. case IDOK:
  433. EndDialog( hDlg, 0 );
  434. break;
  435. }
  436. break;
  437. }
  438. return FALSE;
  439. }
  440. void
  441. __cdecl
  442. GetNotifyBuf(
  443. LPTSTR buf,
  444. DWORD bufsize,
  445. DWORD dwFormatId,
  446. ...
  447. )
  448. /*++
  449. Routine Description:
  450. This is function is a printf style function for printing messages
  451. in a message file.
  452. Arguments:
  453. dwFormatId - format id in the message file
  454. ... - var args
  455. Return Value:
  456. None.
  457. --*/
  458. {
  459. DWORD dwCount;
  460. va_list args;
  461. va_start( args, dwFormatId );
  462. dwCount = FormatMessage(
  463. FORMAT_MESSAGE_FROM_HMODULE,
  464. NULL,
  465. dwFormatId,
  466. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //Default language
  467. buf,
  468. bufsize,
  469. &args
  470. );
  471. va_end(args);
  472. Assert( dwCount != 0 );
  473. return;
  474. }