623 lines
15 KiB
C++
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;
|
|
}
|