windows-nt/Source/XPSP1/NT/sdktools/debuggers/drwatson/notify.cpp
2020-09-26 16:20:57 +08:00

623 lines
15 KiB
C++

/*++
Copyright (c) 1993-2001 Microsoft Corporation
Module Name:
notify.cpp
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 "pch.cpp"
//
// defines
//
#define DEFAULT_WAIT_TIME (1000 * 60 * 5) // wait for 5 minutes
#define MAX_PRINTF_BUF_SIZE (1024 * 4)
HANDLE hThreadDebug = 0;
PDEBUGPACKET dp;
INT_PTR
CALLBACK
NotifyDialogProc (
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam
);
INT_PTR
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;
DWORD dwThreadId;
HINSTANCE hInst;
dp = (PDEBUGPACKET) calloc( sizeof(DEBUGPACKET), sizeof(BYTE) );
if ( dp == NULL) {
return;
}
GetCommandLineArgs( &dp->dwPidToDebug, &dp->hEventToSignal );
RegInitialize( &dp->options );
if (dp->options.fVisual) {
WNDCLASS wndclass;
hInst = GetModuleHandle( NULL );
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = (WNDPROC)NotifyDialogProc;
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 = _T("NotifyDialog");
RegisterClass( &wndclass );
dp->hwnd = CreateDialog( hInst,
MAKEINTRESOURCE( NOTIFYDIALOG ),
0,
NotifyDialogProc );
if (dp->hwnd == NULL) {
return;
}
}
hThreadDebug = CreateThread( NULL,
16000,
(LPTHREAD_START_ROUTINE)DispatchDebugEventThread,
dp,
0,
&dwThreadId
);
if (hThreadDebug == NULL) {
return;
}
if (dp->options.fSound) {
if ((waveOutGetNumDevs() == 0) || (!_tcslen(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;
}
INT_PTR
CALLBACK
NotifyDialogProc (
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;
_TCHAR szTaskName[MAX_PATH];
_TCHAR szHelpFileName[MAX_PATH];
static DWORD AttachComplete=FALSE;
static DWORD Cancel=FALSE;
_TCHAR buf[MAX_PRINTF_BUF_SIZE];
switch (message) {
case WM_CREATE:
return FALSE;
case WM_INITDIALOG:
SubclassControls( hwnd );
//
// OK is hidden until the debugger thread finishes
//
ShowWindow( GetDlgItem( hwnd, IDOK ), SW_HIDE );
//
// CANCEL is enabled right away
//
EnableWindow( GetDlgItem( hwnd, IDCANCEL ), TRUE );
//
// 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) / sizeof(_TCHAR);
GetTaskName( dp->dwPidToDebug, szTaskName, &dwSize );
//
// prevent recursion in the case where drwatson faults
//
if (_tcsicmp(szTaskName, _T("drwtsn32")) == 0) {
ExitProcess(0);
}
//
// Add the text in the dialog box
//
memset(buf,0,sizeof(buf));
GetNotifyBuf( buf, MAX_PRINTF_BUF_SIZE, MSG_NOTIFY, szTaskName );
SetDlgItemText( hwnd, ID_TEXT1, buf);
memset(buf,0,sizeof(buf));
GetNotifyBuf( buf, MAX_PRINTF_BUF_SIZE, MSG_NOTIFY2 );
SetDlgItemText( hwnd, ID_TEXT2, buf );
return TRUE;
case WM_ACTIVATEAPP:
case WM_SETFOCUS:
SetFocusToCurrentControl();
return 0;
case WM_TIMER:
SendMessage( hwnd, WM_COMMAND, IDOK, 0 );
return 0;
case WM_COMMAND:
switch (wParam) {
case IDOK:
SendMessage( hwnd, WM_DESTROY, 0, 0 );
break;
case IDCANCEL:
Cancel = TRUE;
// Make the window go away, but don't kill the
// the process until the WM_ATTACHCOMPLETE has
// occurred
ShowWindow( hwnd, SW_HIDE );
SendMessage( hwnd, WM_FINISH, 0, 0 );
// Delete the dump file, since its invalid anyway
DeleteCrashDump();
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.
//
// Disable and hide the Cancel button
EnableWindow( GetDlgItem( hwnd, IDCANCEL ), FALSE);
ShowWindow( GetDlgItem(hwnd, IDCANCEL ), SW_HIDE);
// Show and Enable the OK button
ShowWindow( GetDlgItem( hwnd, IDOK ), SW_SHOW);
EnableWindow( GetDlgItem( hwnd, IDOK ), TRUE );
SetFocus( GetDlgItem(hwnd, IDOK) );
SetFocusToCurrentControl();
SetTimer( hwnd, 1, DEFAULT_WAIT_TIME, NULL );
return 0;
case WM_ATTACHCOMPLETE:
//
// the message is received from the debugger thread when
// the debugactiveprocess() is completed.
//
AttachComplete = TRUE;
SendMessage( hwnd, WM_FINISH, 0, 0 );
return 0;
case WM_FINISH:
if (AttachComplete && Cancel) {
//
// terminate the debugger thread
//
if ( hThreadDebug ) 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,
&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
//
SendMessage( hwnd, WM_DESTROY, 0, 0 );
}
return 0;
case WM_EXCEPTIONINFO:
return 0;
case WM_DESTROY:
KillTimer( hwnd, 1 );
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:
dwPidToDebug - Returns the process id of the process to debug
hEventToSignal - Returns the handle to an event which will be signalled
when the attach is complete.
Return Value:
None.
--*/
{
_TCHAR *lpstrCmd = GetCommandLine();
_TUCHAR ch;
_TCHAR buf[4096];
BOOLEAN rval = FALSE;
// skip over program name
do {
ch = *lpstrCmd++;
}
while (ch != _T(' ') && ch != _T('\t') && ch != _T('\0'));
// skip over any following white space
while (ch == _T(' ') || ch == _T('\t')) {
ch = *lpstrCmd++;
}
// process each switch character _T('-') as encountered
while (ch == _T('-')) {
ch = *lpstrCmd++;
// process multiple switch characters as needed
do {
switch (ch) {
case _T('e'):
case _T('E'):
// event to signal takes decimal argument
// skip whitespace
do {
ch = *lpstrCmd++;
}
while (ch == _T(' ') || ch == _T('\t'));
while (ch >= _T('0') && ch <= _T('9')) {
*hEventToSignal = (HANDLE)((DWORD_PTR)*hEventToSignal * 10 + ch - _T('0'));
ch = *lpstrCmd++;
}
rval = TRUE;
break;
case _T('p'):
case _T('P'):
// pid debug takes decimal argument
do
ch = *lpstrCmd++;
while (ch == _T(' ') || ch == _T('\t'));
if ( ch == _T('-') ) {
ch = *lpstrCmd++;
if ( ch == _T('1') ) {
*dwPidToDebug = (DWORD)-1;
ch = *lpstrCmd++;
}
}
else {
while (ch >= _T('0') && ch <= _T('9')) {
*dwPidToDebug = *dwPidToDebug * 10 + ch - _T('0');
ch = *lpstrCmd++;
}
}
rval = TRUE;
break;
case _T('g'):
case _T('G'):
// GO
// Ignored but provided for compatiblity with windbg & ntsd
ch = *lpstrCmd++;
break;
case _T('?'):
DialogBox( GetModuleHandle(NULL),
MAKEINTRESOURCE(USAGEDIALOG),
NULL,
UsageDialogProc
);
rval = TRUE;
ch = *lpstrCmd++;
break;
case _T('i'):
case _T('I'):
FormatMessage(
FORMAT_MESSAGE_FROM_HMODULE,
NULL,
MSG_INSTALL_NOTIFY,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
buf,
sizeof(buf) / sizeof(_TCHAR),
NULL
);
RegInstallDrWatson( tolower(lpstrCmd[0]) == _T('q') );
MessageBox( NULL,
buf,
_T("Dr. Watson"),
MB_ICONINFORMATION | MB_OK |
MB_SETFOREGROUND );
rval = TRUE;
ch = *lpstrCmd++;
break;
default:
return rval;
}
} while (ch != _T(' ') && ch != _T('\t') && ch != _T('\0'));
while (ch == _T(' ') || ch == _T('\t')) {
ch = *lpstrCmd++;
}
}
return rval;
}
INT_PTR
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
--*/
{
_TCHAR buf[4096];
switch (message) {
case WM_INITDIALOG:
FormatMessage(
FORMAT_MESSAGE_FROM_HMODULE,
NULL,
MSG_USAGE,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
buf,
sizeof(buf) / sizeof(_TCHAR),
NULL
);
SetDlgItemText( hDlg, ID_USAGE, buf );
break;
case WM_COMMAND:
switch (wParam) {
case IDOK:
EndDialog( hDlg, 0 );
break;
}
break;
}
return FALSE;
}
void
__cdecl
GetNotifyBuf(
LPTSTR buf,
DWORD bufsize,
DWORD dwFormatId,
...
)
/*++
Routine Description:
This is function is a printf style function for printing messages
in a message file.
Arguments:
dwFormatId - format id in the message file
... - var args
Return Value:
None.
--*/
{
DWORD dwCount;
va_list args;
va_start( args, dwFormatId );
dwCount = FormatMessage(
FORMAT_MESSAGE_FROM_HMODULE,
NULL,
dwFormatId,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), //Default language
buf,
bufsize,
&args
);
va_end(args);
Assert( dwCount != 0 );
return;
}