/*++ Copyright (c) 1993 Microsoft Corporation Module Name: browse.c Abstract: This file implements the functions that make use of the common file open dialogs for browsing for files/directories. Author: Wesley Witt (wesw) 1-May-1993 Environment: User Mode --*/ #include #include #include #include #include #include #include #include "drwatson.h" #include "proto.h" #include "resource.h" #include "messages.h" // // defines // #define DEFAULT_WAIT_TIME (1000 * 60 * 5) // wait for 5 minutes // // static global variables // static HANDLE hThreadDebug; static PDEBUGPACKET dp; LRESULT NotifyWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); BOOL CALLBACK UsageDialogProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); void NotifyWinMain ( void ) /*++ Routine Description: This is the entry point for DRWTSN32 Arguments: None. Return Value: None. --*/ { MSG msg; WNDCLASS wndclass; DWORD dwThreadId; HINSTANCE hInst; dp = (PDEBUGPACKET) malloc( sizeof(DEBUGPACKET) ); memset( dp, 0, sizeof(DEBUGPACKET) ); GetCommandLineArgs( &dp->dwPidToDebug, &dp->hEventToSignal ); InitializeListHead(&dp->ThreadList); RegInitialize( &dp->options ); if (dp->options.fVisual) { hInst = GetModuleHandle( NULL ); wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = NotifyWndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = DLGWINDOWEXTRA; wndclass.hInstance = hInst; wndclass.hIcon = LoadIcon( hInst, MAKEINTRESOURCE(APPICON) ); wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); wndclass.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = "NotifyDialog"; RegisterClass( &wndclass ); dp->hwnd = CreateDialog( hInst, MAKEINTRESOURCE( NOTIFYDIALOG ), 0, NotifyWndProc ); } hThreadDebug = CreateThread( NULL, 16000, (LPTHREAD_START_ROUTINE)DispatchDebugEventThread, dp, 0, (LPDWORD)&dwThreadId ); if (dp->options.fSound) { if ((waveOutGetNumDevs() == 0) || (!strlen(dp->options.szWaveFile))) { MessageBeep( MB_ICONHAND ); MessageBeep( MB_ICONHAND ); } else { PlaySound( dp->options.szWaveFile, NULL, SND_FILENAME ); } } if (dp->options.fVisual) { ShowWindow( dp->hwnd, SW_SHOWNORMAL ); while (GetMessage (&msg, NULL, 0, 0)) { if (!IsDialogMessage( dp->hwnd, &msg )) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } } } else { WaitForSingleObject( hThreadDebug, INFINITE ); } CloseHandle( hThreadDebug ); return; } LRESULT NotifyWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) /*++ Routine Description: Window procedure for the DRWTSN32.EXE popup. This is the popup that is displayed when an application error occurs. Arguments: hwnd - window handle to the dialog box message - message number wParam - first message parameter lParam - second message parameter Return Value: TRUE - did not process the message FALSE - did process the message --*/ { DWORD dwThreadId; DWORD dwSize; HANDLE hThread; char szTaskName[MAX_PATH]; char szHelpFileName[MAX_PATH]; switch (message) { case WM_CREATE: return FALSE; case WM_INITDIALOG: SubclassControls( hwnd ); // // OK is not enabled until the debugger thread finishes // EnableWindow( GetDlgItem( hwnd, IDOK ), FALSE ); // // CANCEL is not enabled until debugactiveprocess is finished // EnableWindow( GetDlgItem( hwnd, IDCANCEL ), FALSE ); // // make sure that the user can see the dialog box // SetForegroundWindow( hwnd ); // // get the task name and display it on the dialog box // dwSize = sizeof(szTaskName); GetTaskName( dp->dwPidToDebug, szTaskName, &dwSize ); // // prevent recursion in the case where drwatson faults // if (_stricmp(szTaskName,"drwtsn32")==0) { ExitProcess(0); } SetDlgItemText( hwnd, ID_TEXT1, szTaskName); return TRUE; case WM_ACTIVATEAPP: case WM_SETFOCUS: SetFocusToCurrentControl(); return 0; case WM_COMMAND: switch (wParam) { case IDOK: PostQuitMessage( 0 ); break; case IDCANCEL: // // terminate the debugger thread // TerminateThread( hThreadDebug, 0 ); // // create a thread to terminate the debuggee // this is necessary if cancel is pressed before the // debugger thread finishes the postmortem dump // hThread = CreateThread( NULL, 16000, (LPTHREAD_START_ROUTINE)TerminationThread, dp, 0, (LPDWORD)&dwThreadId ); // // wait for the termination thread to kill the debuggee // WaitForSingleObject( hThread, 30000 ); CloseHandle( hThread ); // // now post a quit message so that DrWatson will go away // PostQuitMessage( 0 ); break; case ID_HELP: // // call winhelp // GetHelpFileName( szHelpFileName, sizeof(szHelpFileName) ); WinHelp( hwnd, szHelpFileName, HELP_FINDER, IDH_WHAT ); break; } break; case WM_NEXTDLGCTL: DefDlgProc( hwnd, message, wParam, lParam ); return 0; case WM_DUMPCOMPLETE: // // the message is received from the debugger thread // when the postmortem dump is finished. all we need to do // is enable the OK button and wait for the user to press the // OK button or for the timer to expire. in either case // DrWatson will terminate. // EnableWindow( GetDlgItem( hwnd, IDOK ), TRUE ); SetFocus( GetDlgItem(hwnd, IDOK) ); SetFocusToCurrentControl(); return 0; case WM_ATTACHCOMPLETE: // // the message is received from the debugger thread when // the debugactiveprocess() is completed // EnableWindow( GetDlgItem( hwnd, IDCANCEL ), TRUE ); return 0; case WM_EXCEPTIONINFO: SetDlgItemText( hwnd, ID_TEXT2, (char *) lParam); return 0; case WM_DESTROY: PostQuitMessage( 0 ); return 0; } return DefWindowProc( hwnd, message, wParam, lParam ); } BOOLEAN GetCommandLineArgs( LPDWORD dwPidToDebug, LPHANDLE hEventToSignal ) /*++ Routine Description: Parses the command line for the 3 possible command lines arguments: -p %ld process id -e %ld event id -g go Arguments: dp - pointer to a debug packet Return Value: None. --*/ { char *lpstrCmd = GetCommandLine(); UCHAR ch; char buf[4096]; BOOLEAN rval = FALSE; // skip over program name do { ch = *lpstrCmd++; } while (ch != ' ' && ch != '\t' && ch != '\0'); // skip over any following white space while (ch == ' ' || ch == '\t') { ch = *lpstrCmd++; } // process each switch character '-' as encountered while (ch == '-') { ch = *lpstrCmd++; // process multiple switch characters as needed do { switch (ch) { case 'e': case 'E': // event to signal takes decimal argument // skip whitespace do { ch = *lpstrCmd++; } while (ch == ' ' || ch == '\t'); while (ch >= '0' && ch <= '9') { (DWORD)*hEventToSignal = (DWORD)*hEventToSignal * 10 + ch - '0'; ch = *lpstrCmd++; } rval = TRUE; break; case 'p': case 'P': // pid debug takes decimal argument do ch = *lpstrCmd++; while (ch == ' ' || ch == '\t'); if ( ch == '-' ) { ch = *lpstrCmd++; if ( ch == '1' ) { *dwPidToDebug = 0xffffffff; ch = *lpstrCmd++; } } else { while (ch >= '0' && ch <= '9') { *dwPidToDebug = *dwPidToDebug * 10 + ch - '0'; ch = *lpstrCmd++; } } rval = TRUE; break; case 'g': case 'G': ch = *lpstrCmd++; break; case '?': DialogBox( GetModuleHandle(NULL), MAKEINTRESOURCE(USAGEDIALOG), NULL, UsageDialogProc ); rval = TRUE; ch = *lpstrCmd++; break; case 'i': case 'I': FormatMessage( FORMAT_MESSAGE_FROM_HMODULE, NULL, MSG_INSTALL_NOTIFY, 0, buf, sizeof(buf), NULL ); RegInstallDrWatson( tolower(lpstrCmd[0]) == 'q' ); MessageBox( NULL, buf, "Dr. Watson for Windows NT", MB_ICONINFORMATION | MB_OK | MB_SETFOREGROUND ); rval = TRUE; ch = *lpstrCmd++; break; default: return rval; } } while (ch != ' ' && ch != '\t' && ch != '\0'); while (ch == ' ' || ch == '\t') { ch = *lpstrCmd++; } } return rval; } BOOL CALLBACK UsageDialogProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) /*++ Routine Description: This is the dialog procedure for the assert dialog box. Normally an assertion box is simply a message box but in this case a Help button is desired so a dialog box is used. Arguments: hDlg - window handle to the dialog box message - message number wParam - first message parameter lParam - second message parameter Return Value: TRUE - did not process the message FALSE - did process the message --*/ { char buf[4096]; switch (message) { case WM_INITDIALOG: FormatMessage( FORMAT_MESSAGE_FROM_HMODULE, NULL, MSG_USAGE, 0, // GetUserDefaultLangID(), buf, sizeof(buf), NULL ); SetDlgItemText( hDlg, ID_USAGE, buf ); break; case WM_COMMAND: switch (wParam) { case IDOK: EndDialog( hDlg, 0 ); break; } break; } return FALSE; }