NOTIFY.C

/*++ 

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 <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <commdlg.h>
#include <mmsystem.h>
#include <direct.h>

#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;
}