windows-nt/Source/XPSP1/NT/windows/richedit/re30/debug.cpp
2020-09-26 16:20:57 +08:00

1464 lines
46 KiB
C++

/*
* DEBUG.CPP
*
* Purpose:
* RICHEDIT debugging support--commented out in ship builds
*
* History: <nl>
* 7/29/98 KeithCu Wrote it stealing much from Rich Arneson's code
*
* Copyright (c) 1995-1998, Microsoft Corporation. All rights reserved.
*/
#include "_common.h"
//Module is empty if this is a retail build.
#if defined(DEBUG) || defined(_RELEASE_ASSERTS_)
DWORD dwDebugOptions = 0; //Debug option flags
PFNASSERTHOOK pfnAssert = NULL; //Assert hook function
PFNTRACEHOOK pfnTrace = NULL; //Trace hook function
// Static variables
static HINSTANCE ghMod; //Dll module handle
static DWORD TlsIndex; //Debug output indent level
static HANDLE hLogFile = NULL; //Log file handle
static BOOL fIgnoreAsserts = FALSE; //Ignore all asserts if true
static CRITICAL_SECTION csLog; //Critical section for log file i/o
static CRITICAL_SECTION csAssert; //Critical section for asserts
static HANDLE hEventAssert1 = NULL; //Event for assert syncing
static HANDLE hEventAssert2 = NULL; //Event for assert syncing
static HWND hwndAssert = NULL; //Assert dialog window handle
static HANDLE hAssertThrd = NULL; //Assert thread handle
static char szAssert[MAXDEBUGSTRLEN]; //Assert message buffer
static int idAssert = -1; //Assert button pressed by user
DWORD WINAPI AssertThread(LPVOID lParam); //Assert thread entry point
static BOOL fDllDetach = FALSE; //True if we are in dll detach
//Strings for subsystem element of message
static char* TrcSubsys [] =
{
"",
"Display",
"Wrapper",
"Edit",
"TextServices",
"TOM",
"OLE Object Support",
"Store",
"Selection",
"WinHost",
"DataXfer",
"MultiUndo",
"Range",
"Util",
"Notification Mgr.",
"RTF Reader",
"RTF Writer",
"Printing",
"Far East",
"Font"
};
//Strings for severity element of message
static char* TrcSeverity [] =
{
"",
"WARNING",
"ERROR",
"ASSERT",
"INFO",
"MEMORY"
};
//Strings for scope element of message
static char* TrcScope [] =
{
"",
"External",
"Internal"
};
//Structure for lookup tables
typedef struct
{
DWORD dwKey;
char * sz;
} TabElem;
//Lookup table for CTrace param strings
static TabElem TrcParamTab [] =
{
//Richedit Messages
{(DWORD)EM_GETLIMITTEXT, "EM_GETLIMITTEXT"},
{(DWORD)EM_POSFROMCHAR, "EM_POSFROMCHAR"},
{(DWORD)EM_CHARFROMPOS, "EM_CHARFROMPOS"},
{(DWORD)EM_SCROLLCARET, "EM_SCROLLCARET"},
{(DWORD)EM_CANPASTE, "EM_CANPASTE"},
{(DWORD)EM_DISPLAYBAND, "EM_DISPLAYBAND"},
{(DWORD)EM_EXGETSEL, "EM_EXGETSEL"},
{(DWORD)EM_EXLIMITTEXT, "EM_EXLIMITTEXT"},
{(DWORD)EM_EXLINEFROMCHAR, "EM_EXLINEFROMCHAR"},
{(DWORD)EM_EXSETSEL, "EM_EXSETSEL"},
{(DWORD)EM_FINDTEXT, "EM_FINDTEXT"},
{(DWORD)EM_FORMATRANGE, "EM_FORMATRANGE"},
{(DWORD)EM_GETCHARFORMAT, "EM_GETCHARFORMAT"},
{(DWORD)EM_GETEVENTMASK, "EM_GETEVENTMASK"},
{(DWORD)EM_GETOLEINTERFACE, "EM_GETOLEINTERFACE"},
{(DWORD)EM_GETPARAFORMAT, "EM_GETPARAFORMAT"},
{(DWORD)EM_GETSELTEXT, "EM_GETSELTEXT"},
{(DWORD)EM_HIDESELECTION, "EM_HIDESELECTION"},
{(DWORD)EM_PASTESPECIAL, "EM_PASTESPECIAL"},
{(DWORD)EM_REQUESTRESIZE, "EM_REQUESTRESIZE"},
{(DWORD)EM_SELECTIONTYPE, "EM_SELECTIONTYPE"},
{(DWORD)EM_SETBKGNDCOLOR, "EM_SETBKGNDCOLOR"},
{(DWORD)EM_SETCHARFORMAT, "EM_SETCHARFORMAT"},
{(DWORD)EM_SETEVENTMASK, "EM_SETEVENTMASK"},
{(DWORD)EM_SETOLECALLBACK, "EM_SETOLECALLBACK"},
{(DWORD)EM_SETPARAFORMAT, "EM_SETPARAFORMAT"},
{(DWORD)EM_SETTARGETDEVICE, "EM_SETTARGETDEVICE"},
{(DWORD)EM_STREAMIN, "EM_STREAMIN"},
{(DWORD)EM_STREAMOUT, "EM_STREAMOUT"},
{(DWORD)EM_GETTEXTRANGE, "EM_GETTEXTRANGE"},
{(DWORD)EM_FINDWORDBREAK, "EM_FINDWORDBREAK"},
{(DWORD)EM_SETOPTIONS, "EM_SETOPTIONS"},
{(DWORD)EM_GETOPTIONS, "EM_GETOPTIONS"},
{(DWORD)EM_FINDTEXTEX, "EM_FINDTEXTEX"},
{(DWORD)EM_GETWORDBREAKPROCEX, "EM_GETWORDBREAKPROCEX"},
{(DWORD)EM_SETWORDBREAKPROCEX, "EM_SETWORDBREAKPROCEX"},
{(DWORD)EM_SETUNDOLIMIT, "EM_SETUNDOLIMIT"},
{(DWORD)EM_REDO, "EM_REDO"},
{(DWORD)EM_CANREDO, "EM_CANREDO"},
{(DWORD)EM_SETPUNCTUATION, "EM_SETPUNCTUATION"},
{(DWORD)EM_GETPUNCTUATION, "EM_GETPUNCTUATION"},
{(DWORD)EM_SETWORDWRAPMODE, "EM_SETWORDWRAPMODE"},
{(DWORD)EM_GETWORDWRAPMODE, "EM_GETWORDWRAPMODE"},
{(DWORD)EM_SETIMECOLOR, "EM_SETIMECOLOR"},
{(DWORD)EM_GETIMECOLOR, "EM_GETIMECOLOR"},
{(DWORD)EM_SETIMEOPTIONS, "EM_SETIMEOPTIONS"},
{(DWORD)EM_GETIMEOPTIONS, "EM_GETIMEOPTIONS"},
{(DWORD)EN_MSGFILTER, "EN_MSGFILTER"},
{(DWORD)EN_REQUESTRESIZE, "EN_REQUESTRESIZE"},
{(DWORD)EN_SELCHANGE, "EN_SELCHANGE"},
{(DWORD)EN_DROPFILES, "EN_DROPFILES"},
{(DWORD)EN_PROTECTED, "EN_PROTECTED"},
{(DWORD)EN_CORRECTTEXT, "EN_CORRECTTEXT"},
{(DWORD)EN_STOPNOUNDO, "EN_STOPNOUNDO"},
{(DWORD)EN_IMECHANGE, "EN_IMECHANGE"},
{(DWORD)EN_SAVECLIPBOARD, "EN_SAVECLIPBOARD"},
{(DWORD)EN_OLEOPFAILED, "EN_OLEOPFAILED"},
//Window Messages
{(DWORD)WM_NULL, "WM_NULL"},
{(DWORD)WM_CREATE, "WM_CREATE"},
{(DWORD)WM_DESTROY, "WM_DESTROY"},
{(DWORD)WM_MOVE, "WM_MOVE"},
{(DWORD)WM_SIZE, "WM_SIZE"},
{(DWORD)WM_ACTIVATE, "WM_ACTIVATE"},
{(DWORD)WM_SETFOCUS, "WM_SETFOCUS"},
{(DWORD)WM_KILLFOCUS, "WM_KILLFOCUS"},
{(DWORD)WM_ENABLE, "WM_ENABLE"},
{(DWORD)WM_SETREDRAW, "WM_SETREDRAW"},
{(DWORD)WM_SETTEXT, "WM_SETTEXT"},
{(DWORD)WM_GETTEXT, "WM_GETTEXT"},
{(DWORD)WM_GETTEXTLENGTH, "WM_GETTEXTLENGTH"},
{(DWORD)WM_PAINT, "WM_PAINT"},
{(DWORD)WM_CLOSE, "WM_CLOSE"},
{(DWORD)WM_QUERYENDSESSION, "WM_QUERYENDSESSION"},
{(DWORD)WM_QUIT, "WM_QUIT"},
{(DWORD)WM_QUERYOPEN, "WM_QUERYOPEN"},
{(DWORD)WM_ERASEBKGND, "WM_ERASEBKGND"},
{(DWORD)WM_SYSCOLORCHANGE, "WM_SYSCOLORCHANGE"},
{(DWORD)WM_ENDSESSION, "WM_ENDSESSION"},
{(DWORD)WM_SHOWWINDOW, "WM_SHOWWINDOW"},
{(DWORD)WM_WININICHANGE, "WM_WININICHANGE"},
{(DWORD)WM_SETTINGCHANGE, "WM_SETTINGCHANGE"},
{(DWORD)WM_DEVMODECHANGE, "WM_DEVMODECHANGE"},
{(DWORD)WM_ACTIVATEAPP, "WM_ACTIVATEAPP"},
{(DWORD)WM_FONTCHANGE, "WM_FONTCHANGE"},
{(DWORD)WM_TIMECHANGE, "WM_TIMECHANGE"},
{(DWORD)WM_CANCELMODE, "WM_CANCELMODE"},
{(DWORD)WM_SETCURSOR, "WM_SETCURSOR"},
{(DWORD)WM_MOUSEACTIVATE, "WM_MOUSEACTIVATE"},
{(DWORD)WM_CHILDACTIVATE, "WM_CHILDACTIVATE"},
{(DWORD)WM_QUEUESYNC, "WM_QUEUESYNC"},
{(DWORD)WM_GETMINMAXINFO, "WM_GETMINMAXINFO"},
{(DWORD)WM_PAINTICON, "WM_PAINTICON"},
{(DWORD)WM_ICONERASEBKGND, "WM_ICONERASEBKGND"},
{(DWORD)WM_NEXTDLGCTL, "WM_NEXTDLGCTL"},
{(DWORD)WM_SPOOLERSTATUS, "WM_SPOOLERSTATUS"},
{(DWORD)WM_DRAWITEM, "WM_DRAWITEM"},
{(DWORD)WM_MEASUREITEM, "WM_MEASUREITEM"},
{(DWORD)WM_DELETEITEM, "WM_DELETEITEM"},
{(DWORD)WM_VKEYTOITEM, "WM_VKEYTOITEM"},
{(DWORD)WM_CHARTOITEM, "WM_CHARTOITEM"},
{(DWORD)WM_SETFONT, "WM_SETFONT"},
{(DWORD)WM_GETFONT, "WM_GETFONT"},
{(DWORD)WM_SETHOTKEY, "WM_SETHOTKEY"},
{(DWORD)WM_GETHOTKEY, "WM_GETHOTKEY"},
{(DWORD)WM_QUERYDRAGICON, "WM_QUERYDRAGICON"},
{(DWORD)WM_COMPAREITEM, "WM_COMPAREITEM"},
{(DWORD)WM_COMPACTING, "WM_COMPACTING"},
{(DWORD)WM_COMMNOTIFY, "WM_COMMNOTIFY"},
{(DWORD)WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING"},
{(DWORD)WM_WINDOWPOSCHANGED, "WM_WINDOWPOSCHANGED"},
{(DWORD)WM_POWER, "WM_POWER"},
{(DWORD)WM_COPYDATA, "WM_COPYDATA"},
{(DWORD)WM_CANCELJOURNAL, "WM_CANCELJOURNAL"},
{(DWORD)WM_NOTIFY, "WM_NOTIFY"},
{(DWORD)WM_INPUTLANGCHANGEREQUEST, "WM_INPUTLANGCHANGEREQUEST"},
{(DWORD)WM_INPUTLANGCHANGE, "WM_INPUTLANGCHANGE"},
{(DWORD)WM_TCARD, "WM_TCARD"},
{(DWORD)WM_HELP, "WM_HELP"},
{(DWORD)WM_USERCHANGED, "WM_USERCHANGED"},
{(DWORD)WM_NOTIFYFORMAT, "WM_NOTIFYFORMAT"},
{(DWORD)WM_CONTEXTMENU, "WM_CONTEXTMENU"},
{(DWORD)WM_STYLECHANGING, "WM_STYLECHANGING"},
{(DWORD)WM_STYLECHANGED, "WM_STYLECHANGED"},
{(DWORD)WM_DISPLAYCHANGE, "WM_DISPLAYCHANGE"},
{(DWORD)WM_GETICON, "WM_GETICON"},
{(DWORD)WM_SETICON, "WM_SETICON"},
{(DWORD)WM_NCCREATE, "WM_NCCREATE"},
{(DWORD)WM_NCDESTROY, "WM_NCDESTROY"},
{(DWORD)WM_NCCALCSIZE, "WM_NCCALCSIZE"},
{(DWORD)WM_NCHITTEST, "WM_NCHITTEST"},
{(DWORD)WM_NCPAINT, "WM_NCPAINT"},
{(DWORD)WM_NCACTIVATE, "WM_NCACTIVATE"},
{(DWORD)WM_GETDLGCODE, "WM_GETDLGCODE"},
{(DWORD)WM_NCMOUSEMOVE, "WM_NCMOUSEMOVE"},
{(DWORD)WM_NCLBUTTONDOWN, "WM_NCLBUTTONDOWN"},
{(DWORD)WM_NCLBUTTONUP, "WM_NCLBUTTONUP"},
{(DWORD)WM_NCLBUTTONDBLCLK, "WM_NCLBUTTONDBLCLK"},
{(DWORD)WM_NCRBUTTONDOWN, "WM_NCRBUTTONDOWN"},
{(DWORD)WM_NCRBUTTONUP, "WM_NCRBUTTONUP"},
{(DWORD)WM_NCRBUTTONDBLCLK, "WM_NCRBUTTONDBLCLK"},
{(DWORD)WM_NCMBUTTONDOWN, "WM_NCMBUTTONDOWN"},
{(DWORD)WM_NCMBUTTONUP, "WM_NCMBUTTONUP"},
{(DWORD)WM_NCMBUTTONDBLCLK, "WM_NCMBUTTONDBLCLK"},
{(DWORD)WM_KEYFIRST, "WM_KEYFIRST"},
{(DWORD)WM_KEYDOWN, "WM_KEYDOWN"},
{(DWORD)WM_KEYUP, "WM_KEYUP"},
{(DWORD)WM_CHAR, "WM_CHAR"},
{(DWORD)WM_DEADCHAR, "WM_DEADCHAR"},
{(DWORD)WM_SYSKEYDOWN, "WM_SYSKEYDOWN"},
{(DWORD)WM_SYSKEYUP, "WM_SYSKEYUP"},
{(DWORD)WM_SYSCHAR, "WM_SYSCHAR"},
{(DWORD)WM_SYSDEADCHAR, "WM_SYSDEADCHAR"},
{(DWORD)WM_KEYLAST, "WM_KEYLAST"},
{(DWORD)WM_IME_STARTCOMPOSITION, "WM_IME_STARTCOMPOSITION"},
{(DWORD)WM_IME_ENDCOMPOSITION, "WM_IME_ENDCOMPOSITION"},
{(DWORD)WM_IME_COMPOSITION, "WM_IME_COMPOSITION"},
{(DWORD)WM_IME_KEYLAST, "WM_IME_KEYLAST"},
{(DWORD)WM_INITDIALOG, "WM_INITDIALOG"},
{(DWORD)WM_COMMAND, "WM_COMMAND"},
{(DWORD)WM_SYSCOMMAND, "WM_SYSCOMMAND"},
{(DWORD)WM_TIMER, "WM_TIMER"},
{(DWORD)WM_HSCROLL, "WM_HSCROLL"},
{(DWORD)WM_VSCROLL, "WM_VSCROLL"},
{(DWORD)WM_INITMENU, "WM_INITMENU"},
{(DWORD)WM_INITMENUPOPUP, "WM_INITMENUPOPUP"},
{(DWORD)WM_MENUSELECT, "WM_MENUSELECT"},
{(DWORD)WM_MENUCHAR, "WM_MENUCHAR"},
{(DWORD)WM_ENTERIDLE, "WM_ENTERIDLE"},
{(DWORD)WM_CTLCOLORMSGBOX, "WM_CTLCOLORMSGBOX"},
{(DWORD)WM_CTLCOLOREDIT, "WM_CTLCOLOREDIT"},
{(DWORD)WM_CTLCOLORLISTBOX, "WM_CTLCOLORLISTBOX"},
{(DWORD)WM_CTLCOLORBTN, "WM_CTLCOLORBTN"},
{(DWORD)WM_CTLCOLORDLG, "WM_CTLCOLORDLG"},
{(DWORD)WM_CTLCOLORSCROLLBAR, "WM_CTLCOLORSCROLLBAR"},
{(DWORD)WM_CTLCOLORSTATIC, "WM_CTLCOLORSTATIC"},
{(DWORD)WM_MOUSEFIRST, "WM_MOUSEFIRST"},
{(DWORD)WM_MOUSEMOVE, "WM_MOUSEMOVE"},
{(DWORD)WM_LBUTTONDOWN, "WM_LBUTTONDOWN"},
{(DWORD)WM_LBUTTONUP, "WM_LBUTTONUP"},
{(DWORD)WM_LBUTTONDBLCLK, "WM_LBUTTONDBLCLK"},
{(DWORD)WM_RBUTTONDOWN, "WM_RBUTTONDOWN"},
{(DWORD)WM_RBUTTONUP, "WM_RBUTTONUP"},
{(DWORD)WM_RBUTTONDBLCLK, "WM_RBUTTONDBLCLK"},
{(DWORD)WM_MBUTTONDOWN, "WM_MBUTTONDOWN"},
{(DWORD)WM_MBUTTONUP, "WM_MBUTTONUP"},
{(DWORD)WM_MBUTTONDBLCLK, "WM_MBUTTONDBLCLK"},
{(DWORD)WM_MOUSELAST, "WM_MOUSELAST"},
{(DWORD)WM_PARENTNOTIFY, "WM_PARENTNOTIFY"},
{(DWORD)WM_ENTERMENULOOP, "WM_ENTERMENULOOP"},
{(DWORD)WM_EXITMENULOOP, "WM_EXITMENULOOP"},
{(DWORD)WM_NEXTMENU, "WM_NEXTMENU"},
{(DWORD)WM_SIZING, "WM_SIZING"},
{(DWORD)WM_CAPTURECHANGED, "WM_CAPTURECHANGED"},
{(DWORD)WM_MOVING, "WM_MOVING"},
{(DWORD)WM_POWERBROADCAST, "WM_POWERBROADCAST"},
{(DWORD)WM_DEVICECHANGE, "WM_DEVICECHANGE"},
{(DWORD)WM_IME_SETCONTEXT, "WM_IME_SETCONTEXT"},
{(DWORD)WM_IME_NOTIFY, "WM_IME_NOTIFY"},
{(DWORD)WM_IME_CONTROL, "WM_IME_CONTROL"},
{(DWORD)WM_IME_COMPOSITIONFULL, "WM_IME_COMPOSITIONFULL"},
{(DWORD)WM_IME_SELECT, "WM_IME_SELECT"},
{(DWORD)WM_IME_CHAR, "WM_IME_CHAR"},
{(DWORD)WM_IME_KEYDOWN, "WM_IME_KEYDOWN"},
{(DWORD)WM_IME_KEYUP, "WM_IME_KEYUP"},
{(DWORD)WM_MDICREATE, "WM_MDICREATE"},
{(DWORD)WM_MDIDESTROY, "WM_MDIDESTROY"},
{(DWORD)WM_MDIACTIVATE, "WM_MDIACTIVATE"},
{(DWORD)WM_MDIRESTORE, "WM_MDIRESTORE"},
{(DWORD)WM_MDINEXT, "WM_MDINEXT"},
{(DWORD)WM_MDIMAXIMIZE, "WM_MDIMAXIMIZE"},
{(DWORD)WM_MDITILE, "WM_MDITILE"},
{(DWORD)WM_MDICASCADE, "WM_MDICASCADE"},
{(DWORD)WM_MDIICONARRANGE, "WM_MDIICONARRANGE"},
{(DWORD)WM_MDIGETACTIVE, "WM_MDIGETACTIVE"},
{(DWORD)WM_MDISETMENU, "WM_MDISETMENU"},
{(DWORD)WM_ENTERSIZEMOVE, "WM_ENTERSIZEMOVE"},
{(DWORD)WM_EXITSIZEMOVE, "WM_EXITSIZEMOVE"},
{(DWORD)WM_DROPFILES, "WM_DROPFILES"},
{(DWORD)WM_MDIREFRESHMENU, "WM_MDIREFRESHMENU"},
{(DWORD)WM_CUT, "WM_CUT"},
{(DWORD)WM_COPY, "WM_COPY"},
{(DWORD)WM_PASTE, "WM_PASTE"},
{(DWORD)WM_CLEAR, "WM_CLEAR"},
{(DWORD)WM_UNDO, "WM_UNDO"},
{(DWORD)WM_RENDERFORMAT, "WM_RENDERFORMAT"},
{(DWORD)WM_RENDERALLFORMATS, "WM_RENDERALLFORMATS"},
{(DWORD)WM_DESTROYCLIPBOARD, "WM_DESTROYCLIPBOARD"},
{(DWORD)WM_DRAWCLIPBOARD, "WM_DRAWCLIPBOARD"},
{(DWORD)WM_PAINTCLIPBOARD, "WM_PAINTCLIPBOARD"},
{(DWORD)WM_VSCROLLCLIPBOARD, "WM_VSCROLLCLIPBOARD"},
{(DWORD)WM_SIZECLIPBOARD, "WM_SIZECLIPBOARD"},
{(DWORD)WM_ASKCBFORMATNAME, "WM_ASKCBFORMATNAME"},
{(DWORD)WM_CHANGECBCHAIN, "WM_CHANGECBCHAIN"},
{(DWORD)WM_HSCROLLCLIPBOARD, "WM_HSCROLLCLIPBOARD"},
{(DWORD)WM_QUERYNEWPALETTE, "WM_QUERYNEWPALETTE"},
{(DWORD)WM_PALETTEISCHANGING, "WM_PALETTEISCHANGING"},
{(DWORD)WM_PALETTECHANGED, "WM_PALETTECHANGED"},
{(DWORD)WM_HOTKEY, "WM_HOTKEY"},
{(DWORD)WM_PRINT, "WM_PRINT"},
{(DWORD)WM_PRINTCLIENT, "WM_PRINTCLIENT"},
{(DWORD)WM_HANDHELDFIRST, "WM_HANDHELDFIRST"},
{(DWORD)WM_HANDHELDLAST, "WM_HANDHELDLAST"},
{(DWORD)WM_AFXFIRST, "WM_AFXFIRST"},
{(DWORD)WM_AFXLAST, "WM_AFXLAST"},
{(DWORD)WM_PENWINFIRST, "WM_PENWINFIRST"},
{(DWORD)WM_PENWINLAST, "WM_PENWINLAST"},
{(DWORD)WM_APP, "WM_APP"}
};
// release + asserts build has no memory checking
#ifndef _RELEASE_ASSERTS_
void DlgDisplayVrgmst(HWND hListMemory)
{
char szTemp[300];
int cbTotal = 0;
for(int imst = 0; vrgmst[imst].szFile != 0; imst++)
{
cbTotal += vrgmst[imst].cbAlloc;
wsprintfA(szTemp, "%6.d %s", vrgmst[imst].cbAlloc, vrgmst[imst].szFile);
SendMessage(hListMemory, LB_ADDSTRING, 0, (LPARAM) szTemp);
}
wsprintfA(szTemp, "%6.d %s", cbTotal, "--- Total ---");
SendMessage(hListMemory, LB_ADDSTRING, 0, (LPARAM) szTemp);
}
HFONT hf = 0;
INT_PTR CALLBACK FDlgRicheditDebugCentral(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam)
{
HWND hListMemory;
switch (message)
{
case WM_INITDIALOG:
hListMemory = GetDlgItem(hdlg, IDC_MEMORY_STATISTICS);
LOGFONTA lf;
ZeroMemory(&lf, sizeof(lf));
lf.lfHeight = 14;
memcpy(lf.lfFaceName, "Courier New", 12);
hf = CreateFontIndirectA(&lf);
SendMessage(hListMemory, WM_SETFONT, (WPARAM)hf, FALSE);
UpdateMst();
DlgDisplayVrgmst(hListMemory);
return FALSE;
case WM_COMMAND:
switch (wParam)
{
case IDOK:
EndDialog(hdlg, IDOK);
return TRUE;
case IDCANCEL:
EndDialog(hdlg, IDCANCEL);
return TRUE;
}
break;
}
return FALSE;
}
void RicheditDebugCentral(void)
{
DialogBoxA(hinstRE, MAKEINTRESOURCEA(IDD_DEBUG), NULL, FDlgRicheditDebugCentral);
DeleteObject(hf);
}
#endif //!_RELEASE_ASSERTS_
/*
* DebugMain
*
* @mfunc
* Dll entry point. See Win32 SDK documentation for details.
* hDLL - handle of DLL
* dwReason - indicates why DLL called
* lpReserved - reserved
*
* @rdesc
* TRUE (always)
*
*/
BOOL WINAPI DebugMain (HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
{
//
// DLL is attaching to the address space of the current process.
//
ghMod = hDLL;
TlsIndex = TlsAlloc();
TlsSetValue(TlsIndex, (LPVOID)-1);
InitializeCriticalSection(&csLog);
InitializeCriticalSection(&csAssert);
//Create a separate thread to handle asserts.
//We use events to halt the the asserting thread
//during an assert, and to halt the assert thread the rest of
//the time. Note that these are autoreset events.
hEventAssert1= CreateEvent(NULL, FALSE, FALSE, NULL);
hEventAssert2= CreateEvent(NULL, FALSE, FALSE, NULL);
INITDEBUGSERVICES(OPTUSEDEFAULTS, NULL, NULL);
break;
}
case DLL_THREAD_ATTACH:
{
//
// A new thread is being created in the current process.
//
TlsSetValue(TlsIndex, (LPVOID)-1);
break;
}
case DLL_THREAD_DETACH:
{
//
// A thread is exiting cleanly.
//
break;
}
case DLL_PROCESS_DETACH:
{
//
// The calling process is detaching the DLL from its address space.
//
fDllDetach = TRUE;
//Clean up after ourselves.
TlsFree(TlsIndex);
SETLOGGING(FALSE);
//Clean up the assert thread stuff.
if (NULL != hAssertThrd)
TerminateThread(hAssertThrd, 0);
if (NULL != hEventAssert1)
CloseHandle(hEventAssert1);
if (NULL != hEventAssert2)
CloseHandle(hEventAssert2);
DeleteCriticalSection(&csLog);
DeleteCriticalSection(&csAssert);
break;
}
}
return TRUE;
}
//This is not in release asserts build
#ifndef _RELEASE_ASSERTS_
/*
* SetLogging
*
* @mfunc
* This function starts and stops logging of output from
* the debug services. If logging is being started, it
* creates a new file for logging (path and name specified
* in win.ini). fStartLog is TRUE and logging is already
* on, or fStartLog is FALSE and logging is off, this
* nothing happens.
*
* fStartLog - TRUE to start logging, FALSE to stop logging.
*
*/
void WINAPI SetLogging(BOOL fStartLog)
{
//Don't start logging if it's already on.
if (fStartLog && !fLogging)
{
char szLogFile[MAX_PATH];
//Set option flag telling everyone we're on
dwDebugOptions |= OPTLOGGINGON;
//Get file name
GetProfileStringA("RICHEDIT DEBUG", "LOGFILE", "", szLogFile, MAX_PATH);
//Create new file
hLogFile = CreateFileA(szLogFile, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
//If we didn't succed creating the file, reset flags and tell user.
if (INVALID_HANDLE_VALUE == hLogFile)
{
dwDebugOptions &= ~OPTLOGGINGON;
MessageBoxA(NULL, "Unable to open log file.", "Richedit Debug", MB_OK);
}
}
//Don't stop logging if it's not on.
else if (!fStartLog && fLogging)
{
//Set option flag telling everyone we're off, and close file.
dwDebugOptions &= ~OPTLOGGINGON;
CloseHandle(hLogFile);
}
}
#endif //!_RELEASE_ASSERTS_
/*
* InitDebugServices
*
* @mfunc
* This function initializes the options for the debug
* services. If this function is not called, all optional
* debug services are left off by default.
* If OPTUSEDEFAULTS is specified for dwOpts, options are
* loaded from win.ini, otherwise the caller specified
* options are set. If the caller wishes to specify options
* they must specify all options they want turned on. Any
* options not explicitly specified will be turned off.
* The function also takes a pointer to an assert hook
* function and a trace hook function.
*
* dwOpts - Debug options to be set.
* pfnAssertHook - Pointer to assert hook function (NULL if none).
* pfnTraceHook - Pointer to trace hook function (NULL if none).
*
*/
DllExport void WINAPI InitDebugServices(DWORD dwOpts,
PFNASSERTHOOK pfnAssertHook, PFNTRACEHOOK pfnTraceHook)
{
// Check to see if OPTUSEDEFAULTS was specified. If so, get
// values from win.ini. Otherwise, set options to values
// specified by caller.
if (dwOpts & OPTUSEDEFAULTS)
{
SETLOGGING(GetProfileIntA("RICHEDIT DEBUG", "LOGGING", 0));
SETVERBOSE(GetProfileIntA("RICHEDIT DEBUG", "VERBOSE", 0));
SETINFO(GetProfileIntA("RICHEDIT DEBUG", "INFO", 0));
SETMEMORY(GetProfileIntA("RICHEDIT DEBUG", "MEMORY", 0));
SETTRACING(GetProfileIntA("RICHEDIT DEBUG", "TRACE", 0));
SETTRACEEXT(GetProfileIntA("RICHEDIT DEBUG", "TRACEEXT", 0));
SETOPT(OPTTRACEDISP, GetProfileIntA("RICHEDIT DEBUG", "TRACEDISP", 0));
SETOPT(OPTTRACEWRAP, GetProfileIntA("RICHEDIT DEBUG", "TRACEWRAP", 0));
SETOPT(OPTTRACEEDIT, GetProfileIntA("RICHEDIT DEBUG", "TRACEEDIT", 0));
SETOPT(OPTTRACETS, GetProfileIntA("RICHEDIT DEBUG", "TRACETS", 0));
SETOPT(OPTTRACETOM, GetProfileIntA("RICHEDIT DEBUG", "TRACETOM", 0));
SETOPT(OPTTRACEOLE, GetProfileIntA("RICHEDIT DEBUG", "TRACEOLE", 0));
SETOPT(OPTTRACEBACK, GetProfileIntA("RICHEDIT DEBUG", "TRACEBACK", 0));
SETOPT(OPTTRACESEL, GetProfileIntA("RICHEDIT DEBUG", "TRACESEL", 0));
SETOPT(OPTTRACEHOST, GetProfileIntA("RICHEDIT DEBUG", "TRACEHOST", 0));
SETOPT(OPTTRACEDTE, GetProfileIntA("RICHEDIT DEBUG", "TRACEDTE", 0));
SETOPT(OPTTRACEUNDO, GetProfileIntA("RICHEDIT DEBUG", "TRACEUNDO", 0));
SETOPT(OPTTRACERANG, GetProfileIntA("RICHEDIT DEBUG", "TRACERANG", 0));
SETOPT(OPTTRACEUTIL, GetProfileIntA("RICHEDIT DEBUG", "TRACEUTIL", 0));
SETOPT(OPTTRACENOTM, GetProfileIntA("RICHEDIT DEBUG", "TRACENOTM", 0));
SETOPT(OPTTRACERTFR, GetProfileIntA("RICHEDIT DEBUG", "TRACERTFR", 0));
SETOPT(OPTTRACERTFW, GetProfileIntA("RICHEDIT DEBUG", "TRACERTFW", 0));
SETOPT(OPTTRACEPRT, GetProfileIntA("RICHEDIT DEBUG", "TRACEPRT", 0));
SETOPT(OPTTRACEFE, GetProfileIntA("RICHEDIT DEBUG", "TRACEFE", 0));
SETOPT(OPTTRACEFONT, GetProfileIntA("RICHEDIT DEBUG", "TRACEFONT", 0));
}
else
{
//Set up logging before we set dwDebugOptions because
//SetLogging will not turn logging on if the flag
//indicates it is already on.
SETLOGGING(dwOpts & OPTLOGGINGON);
dwDebugOptions = dwOpts;
}
SETASSERTFN(pfnAssertHook);
SETTRACEFN(pfnTraceHook);
}
/*
* AssertProc
*
* @mfunc
* This is the dialog proc for the assert message.
/ *
* lParam - The string to display in the dialog.
*
*/
BOOL CALLBACK AssertProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
{
RECT rcDlg, rcDesk;
GetWindowRect(hwndDlg, &rcDlg);
GetWindowRect(GetDesktopWindow(), &rcDesk);
SetWindowPos(hwndDlg, HWND_TOP,
((rcDesk.right - rcDesk.left ) - (rcDlg.right - rcDlg.left))/2,
((rcDesk.bottom - rcDesk.top ) - (rcDlg.bottom - rcDlg.top))/2,
0, 0, SWP_NOSIZE);
if (NULL != lParam)
SetDlgItemTextA(hwndDlg, IDC_MSG, (LPSTR)lParam);
//Sometimes we don't always end up on top. I don't know why.
SetForegroundWindow(hwndDlg);
}
break;
case WM_COMMAND:
//Kill dialog and return button id that was pressed.
EndDialog(hwndDlg, LOWORD(wParam));
break;
default:
return FALSE;
}
return TRUE;
}
/*
* AssertThread
*
* @mfunc
* This is the entry point for the thread created for the
* assert dialog.
*
* lParam - Data passed to thread...not used.
*
* @rdesc
* Should not return. It will be explicitly terminated.
*
*/
DWORD WINAPI AssertThread(LPVOID lParam)
{
//This should run until it is explicitly terminated in
//process detach.
while(TRUE)
{
//We go into a wait state until the event is signaled,
//which means we are handling an assert.
WaitForSingleObject(hEventAssert1, INFINITE);
idAssert = DialogBoxParamA(ghMod, MAKEINTRESOURCEA(IDD_ASSERT),
NULL, (DLGPROC)AssertProc, (LPARAM)szAssert);
//The asserting thread will be waiting on this event so
//set it to allow the asserting thread continue.
SetEvent(hEventAssert2);
}
return 0;
}
char * __cdecl strrchr (
const char * string,
int ch
)
{
char *start = (char *)string;
while (*string++) /* find end of string */
;
/* search towards front */
while (--string != start && *string != (char)ch)
;
if (*string == (char)ch) /* char found ? */
return( (char *)string );
return(NULL);
}
/*
* AssertSzFn
*
* @mfunc
* Display a message for the user and give the
* option to abort, ignore, or ignore all.
* Selecting ignore all causes all asserts to be
* ignored from that time forward. It cannot be
* reset. If the assert dialog cannot be created
* A message box is used. The message box has one
* button (OK) which will cause an abort.
*
* szFile - the file the warning occured in.
* iLine - the line number the warning occured at.
* szUserMsg - User define message string
*
*/
void AssertSzFn(LPSTR szUserMsg, LPSTR szFile, int iLine)
{
char szModuleName[MAX_PATH];
char * pszModuleName;
DWORD pid;
DWORD tid;
DWORD dwAssertTID;
//Check to see if an assert hook has been set. If it has, call
//it with pointers to all our parameters (they can be modified
//this way if desired). If the hook returns false, return.
//Otherwise, continue with our assert with the potentially
//modified parameters.
if (NULL != pfnAssert)
if (!pfnAssert(szUserMsg, szFile, &iLine))
return;
if( NULL == hAssertThrd )
{
if( NULL != hEventAssert1 && NULL != hEventAssert2)
{
hAssertThrd = CreateThread(NULL, 0, AssertThread,
NULL, 0, &dwAssertTID);
}
}
//This critical section will prevent us from being entered simultaneously
//by multiple threads. This alone will not prevent reentrance by our own thread
//once the assert dialog is up. Under normal circumstances a special thread
//exists to run the assert dialog and Event objects are used to halt this
//thread while the assert dialog is up (see WaitForSingleObject
//further down). If the assert thread does not exist, a MessageBox is used
//and we can be reentered (this is a fallback position and there's
//not much we can do about it).
EnterCriticalSection(&csAssert);
pid = GetCurrentProcessId();
tid = GetCurrentThreadId();
//Get the module name to include in assert message.
if (GetModuleFileNameA(NULL, szModuleName, MAX_PATH))
{
pszModuleName = strrchr(szModuleName, '\\');
if (!pszModuleName)
{
pszModuleName = szModuleName;
}
else
{
pszModuleName++;
}
}
else
{
pszModuleName = "Unknown";
}
//Send a message to the debug output and build a string for the
//assert dialog. The string depends on whether the user provided
//a message.
if (NULL != szUserMsg)
{
TRACEASSERTSZ(szUserMsg, szFile, iLine);
sprintf(szAssert,
"PROCESS: %s, PID: %d, TID: %d\nFILE: %s (%d)\n%s\n",
pszModuleName, pid, tid, szFile, iLine, szUserMsg);
}
else
{
TRACEASSERT(szFile, iLine);
sprintf(szAssert,
"PROCESS: %s, PID: %d, TID: %d\nFILE: %s (%d)\n",
pszModuleName, pid, tid, szFile, iLine);
}
//If the user did not disable asserts on a previous assert,
//put up a dialog with the assert message.
if (!fIgnoreAsserts)
{
idAssert = -1;
//If we are in the middle of process detach, the assert thread
//will not execute so pop the dialog here ourselves. Presumably there
//is little change of reentrancy at this point. If we are not
//in process detach, let the assert thread handle the assert.
if (fDllDetach)
{
idAssert = DialogBoxParamA(ghMod, MAKEINTRESOURCEA(IDD_ASSERT),
NULL, (DLGPROC)AssertProc, (LPARAM)szAssert);
}
else
{
SetEvent(hEventAssert1);
WaitForSingleObject(hEventAssert2, INFINITE);
}
//The assert thread doesn't exist or the dialogbox create failed so
//use a message box instead. In this case, since we
//are obviously having problems, we are only going to
//give the user one choice...abort.
if (-1 == idAssert)
{
idAssert = MessageBoxA(NULL,
szAssert,
"Richedit Assert - (retry will be ignored)",
MB_SETFOREGROUND | MB_TASKMODAL |
MB_ICONEXCLAMATION | MB_ABORTRETRYIGNORE);
//
// If id == 0, then an error occurred. There are two possibilities
// that can cause the error: Access Denied, which means that this
// process does not have access to the default desktop, and everything
// else (usually out of memory).
//
if (!idAssert)
{
if (GetLastError() == ERROR_ACCESS_DENIED)
{
//
// Retry this one with the SERVICE_NOTIFICATION flag on. That
// should get us to the right desktop.
//
idAssert = MessageBoxA( NULL,
szAssert,
"Richedit Assert - (retry will be ignored)",
MB_SETFOREGROUND | MB_TASKMODAL | MB_ICONEXCLAMATION |
MB_ABORTRETRYIGNORE);
}
}
}
if (idAssert == ID_IGNOREALL)
{
fIgnoreAsserts = TRUE;
}
if (idAssert == IDABORT )
{
//This will cause a break when debugging, and
//an exception leading to termination otherwise.
DebugBreak();
return;
}
}
LeaveCriticalSection(&csAssert);
}
/*
* TabLookup
*
* @mfunc
* This function searches an array of TabElem
* structures looking for an entry whose key
* matches the one we were given. If found, it
* copies the string associated with the key into
* the supplied buffer.
*
* Table - TabElem pointer to start of array.
* TabSize - Size of array in bytes.
* dwKey - Key to match.
* szBuf - Buffer to hold string (assumed MAXDEBUGSTRLEN in size).
*
* @rdesc
* FALSE if key not found, TRUE if found.
*
*/
BOOL TabLookup(TabElem * Table, UINT TabSize, DWORD dwKey, LPSTR szBuf)
{
BOOL fRet = FALSE;
UINT cTab, index;
cTab = TabSize/sizeof(TabElem);
for (index = 0; index < cTab; index++)
{
if (Table[index].dwKey == dwKey)
break;
}
if (index < cTab)
{
lstrcpyA(szBuf, Table[index].sz);
fRet = TRUE;
}
return fRet;
}
/*
* GetHResultSz
*
* @mfunc
* This function fills a buffer with a string associated
* with a given HRESULT. This string can then be used
* in the output from TraceMsg.
*
* hr - HRESULT on which the string will be based.
* szBuf - Buffer to hold string (MAXDEBUGSTRLEN in size).
*
*/
void GetHResultSz(HRESULT hr, LPSTR szBuf)
{
// Build string based on FormatMessageA
if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, (DWORD)hr,
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
szBuf, MAXDEBUGSTRLEN, NULL))
{
// Build default string
sprintf(szBuf, "hr = %d: Unrecognized HRESULT.", hr);
}
else
{
int cch;
char * pch;
//Need to get rid of the CRLF from FormatMessageA.
pch = szBuf;
cch = strlen(szBuf);
pch += (cch - 2);
*pch = '\0';
}
}
/*
* GetParamSz
*
* @mfunc
* This function fills a buffer with a string associated
* with a param from the text message handler.
* This string can then be used in the output from
* TraceMsg.
*
* dwParam - param on which the string will be based.
* szBuf - Buffer to hold string (MAXDEBUGSTRLEN in size).
*/
void GetParamSz(DWORD dwParam, LPSTR szBuf)
{
char szTemp[MAXDEBUGSTRLEN];
if (!TabLookup(TrcParamTab, sizeof(TrcParamTab), (DWORD)dwParam, szTemp))
{
sprintf(szBuf, "PARAM = %d: Unrecognized PARAM.", dwParam);
}
else
{
sprintf(szBuf, "PARAM: %s", szTemp);
}
}
/*
* GetDefaultSz
*
* @mfunc
* This function fills a buffer with a string associated
* with either the value from GetLastError, or with a
* default string. This string can then be used in the
* output from TraceMsg.
*
* dwError - Value from GetLastError.
* szBuf - Buffer to hold string (MAXDEBUGSTRLEN in size).
*
*/
void GetDefaultSz(DWORD dwError, LPSTR szBuf)
{
//Check to see if we have an error value
if (dwError)
{
// Build string based on FormatMessageA
if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
szBuf, MAXDEBUGSTRLEN, NULL))
{
// Build default string
lstrcpyA(szBuf, "Reason unknown.");
}
else
{
int cch;
char * pch;
//Need to get rid of the CRLF from FormatMessageA.
pch = szBuf;
cch = strlen(szBuf);
pch += (cch - 2);
*pch = '\0';
}
}
else
{
// Build default string
lstrcpyA(szBuf, "Reason unknown.");
}
}
//The following are not used by the release with asserts build
#ifndef _RELEASE_ASSERTS_
/*
* GetDataSz
*
* @mfunc
* This function fills a buffer with a string representing
* data passed to TraceMsg in one of it's DWORDS data
* parameters. This string can then be used in the
* output from TraceMsg.
*
* uDataType - This is the type of data we are dealing with.
* dwData - This is the data itself.
* szBuf - Buffer to hold string (MAXDEBUGSTRLEN in size).
*
*/
void GetDataSz(UINT uDataType, DWORD dwData, LPSTR szBuf)
{
switch (uDataType)
{
// Data is an HRESULT
case TRCDATAHRESULT:
GetHResultSz((HRESULT)dwData, szBuf);
break;
// Data is a string (copy to szBuf and pass it through)
case TRCDATASTRING:
lstrcpyA(szBuf, (LPSTR)(DWORD_PTR)dwData);
break;
// Data is a parameter value
case TRCDATAPARAM:
GetParamSz(dwData, szBuf);
break;
// Get string based on GetLastError
case TRCDATADEFAULT:
default:
GetDefaultSz(dwData, szBuf);
break;
}
}
/*
* LogDebugString
*
* @mfunc
* This function writes a string to the log file. The file must
* be opened already and hLogFile must contain the handle.
*
* szDebugMsg - String to write to log file.
*
*/
void LogDebugString(LPSTR szDebugMsg)
{
if ((NULL != hLogFile) && (INVALID_HANDLE_VALUE != hLogFile))
{
DWORD dwMsgBytes, dwBytes;
dwMsgBytes = strlen(szDebugMsg)*sizeof(char);
//Prevent other threads from trying to write at same time.
EnterCriticalSection(&csLog);
SetFilePointer(hLogFile, 0, NULL, FILE_END);
WriteFile (hLogFile, szDebugMsg, dwMsgBytes, &dwBytes, NULL);
LeaveCriticalSection(&csLog);
}
}
/*
* TraceMsg
*
* @mfunc
* This is the central message generating facility for
* the debug tools. All messages to the debug output
* or log file are generated here. This function takes
* a DWORD (dwFlags) that consists of packed values that determine
* the kind of message to generated. It takes two DWORD
* data parameters that can contain several different
* types of data (string, HRESULT, etc.) These are interpreted
* using dwFlags. It also takes the file and line associated with
* the point in the source where it was called.
*
* dwFlags - Packed values tell us how to generate the message.
* dwData1 - The first of two data parameters.
* dwData2 - The second of two data parameters.
* szFile - File name we were called from.
* iLine - Line number we were called from.
*
*/
void TraceMsg(DWORD dwFlags, DWORD dwData1, DWORD dwData2,
LPSTR szFile, int iLine)
{
//The following three buffers are used to build our message.
char szTemp[MAXDEBUGSTRLEN];
char szTemp2[MAXDEBUGSTRLEN];
char szDebugMsg[MAXDEBUGSTRLEN];
char* pch;
int cch;
TrcFlags trcf; //Used to decode dwFlags
DWORD pid;
DWORD tid;
DWORD dwError;
int indent, tls;
//Check to see if a Trace hook has been set. If it has, call
//it with pointers to all our parameters (they can be modified
//this way if desired). If the hook returns false, return.
//Otherwise, continue with our message output with the potentially
//modified parameters.
if (NULL != pfnTrace)
if (!pfnTrace(&dwFlags, &dwData1, &dwData2, szFile, &iLine))
return;
trcf.dw = dwFlags;
//Return if this is an informational message and they are disabled.
if ((TRCSEVINFO == trcf.fields.uSeverity) && !fInfo)
return;
// Call GetLastError now in case we need it later.
// This way api calls downstream won't disturb the value
// we need.
dwError = GetLastError();
pid = GetCurrentProcessId();
tid = GetCurrentThreadId();
szTemp[0] = '\0';
szTemp2[0] = '\0';
szDebugMsg[0] = '\0';
// Handle indentation (TLSindent is set by CTrace)
tls = (int)(DWORD_PTR)TlsGetValue(TlsIndex);
indent = (tls < 0 ? 0 : tls);
memset(szDebugMsg, ' ', 2*indent*sizeof(char));
szDebugMsg[2*indent] = '\0';
// Handle severity (Warning, Error, etc.)
if (TRCSEVNONE != trcf.fields.uSeverity)
{
sprintf(szTemp, "%s: ", TrcSeverity[trcf.fields.uSeverity]);
strcat(szDebugMsg, szTemp);
}
// Interpret the first data value
if (TRCDATANONE != trcf.fields.uData1)
{
if (TRCDATADEFAULT == trcf.fields.uData1)
dwData1 = dwError;
GetDataSz(trcf.fields.uData1, dwData1, szTemp2);
lstrcpyA(szTemp, szDebugMsg);
wsprintfA(szDebugMsg, "%s%s ", szTemp, szTemp2);
}
// Interpret the second data value.
if (TRCDATANONE != trcf.fields.uData2)
{
if (TRCDATADEFAULT == trcf.fields.uData2)
dwData2 = dwError;
GetDataSz(trcf.fields.uData2, dwData2, szTemp2);
lstrcpyA(szTemp, szDebugMsg);
wsprintfA(szDebugMsg, "%s%s", szTemp, szTemp2);
}
if (fVerbose)
{
// Handle scope (Internal/External call)
if (TRCSCOPENONE != trcf.fields.uScope)
{
sprintf(szTemp, "SCOPE: %s ", TrcScope[trcf.fields.uScope]);
strcat(szDebugMsg, szTemp);
}
// Handle subsytem (TOM, ITextServices, etc.)
if (TRCSUBSYSNONE != trcf.fields.uSubSystem)
{
sprintf(szTemp, "SUBSYSTEM: %s ", TrcSubsys[trcf.fields.uSubSystem]);
strcat(szDebugMsg, szTemp);
}
// Handle process ID, thread ID, file and line.
sprintf(szTemp, "PID: %u TID: %u ", pid, tid);
strcat(szDebugMsg, szTemp);
}
// Up to now there is no real danger of overflowing our buffer since
// we were dealing with strings of small size. Now we will be running
// in to paths and user strings. We will use _snprintf to concatonate
// new stuff to our message. This is not the most effecient way since
// it involves alot of copying, but it is a fairly simple way to keep
// adding to our string without having to worry about how much room is
// left in the buffer. It will truncate if we go past the end.
if (NULL != szFile)
{
lstrcpyA(szTemp, szDebugMsg);
if (0 != iLine)
{
wsprintfA(szDebugMsg, "%sFILE: %s (%u) ",
szTemp, szFile, iLine);
}
else
{
wsprintfA(szDebugMsg, "%sFILE: %s ",
szTemp, szFile);
}
}
// Append a CRLF to the end of the string (make sure we don't overflow)
cch = strlen(szDebugMsg);
pch = szDebugMsg;
if (cch < (MAXDEBUGSTRLEN - 3))
pch += cch;
else
pch += (MAXDEBUGSTRLEN - 3);
lstrcpyA(pch, "\r\n");
if (fLogging)
LogDebugString(szDebugMsg);
// Write to debug output.
OutputDebugStringA(szDebugMsg);
}
/*
* Tracef
*
* @mfunc:
* The given format string and parameters are used to render a
* string into a buffer. This string is passed to TraceMsg.
* The severity parameter determines the type of message. The
* following values are valid: TRCSEVWARN, TRCSEVERR, TRCSEVINFO.
*
* Arguments:
* dwSev Severity of message.
* szFmt Format string for wvsprintf (qqv)
*/
void Tracef(DWORD dwSev, LPSTR szFmt, ...)
{
va_list valMarker;
char rgchTraceTagBuffer[MAXDEBUGSTRLEN];
// format out a string
va_start(valMarker, szFmt);
wvsprintfA(rgchTraceTagBuffer, szFmt, valMarker);
va_end(valMarker);
if (dwSev == TRCSEVERR)
TraceMsg(MAKEFLAGS(TRCSUBSYSNONE, TRCSEVERR, TRCSCOPENONE,
TRCDATASTRING, TRCDATANONE), (DWORD)(DWORD_PTR)(rgchTraceTagBuffer),
(DWORD)0, NULL, 0);
else if (dwSev == TRCSEVWARN)
TraceMsg(MAKEFLAGS(TRCSUBSYSNONE, TRCSEVWARN, TRCSCOPENONE,
TRCDATASTRING, TRCDATANONE), (DWORD)(DWORD_PTR)(rgchTraceTagBuffer),
(DWORD)0, NULL, 0);
else if (dwSev == TRCSEVINFO)
TraceMsg(MAKEFLAGS(TRCSUBSYSNONE, TRCSEVINFO, TRCSCOPENONE,
TRCDATASTRING, TRCDATANONE), (DWORD)(DWORD_PTR)(rgchTraceTagBuffer),
(DWORD)0, NULL, 0);
else if (dwSev == TRCSEVMEM)
TraceMsg(MAKEFLAGS(TRCSUBSYSNONE, TRCSEVMEM, TRCSCOPENONE,
TRCDATASTRING, TRCDATANONE), (DWORD)(DWORD_PTR)(rgchTraceTagBuffer),
(DWORD)0, NULL, 0);
else
TraceMsg(MAKEFLAGS(TRCSUBSYSNONE, TRCSEVNONE, TRCSCOPENONE,
TRCDATASTRING, TRCDATANONE), (DWORD)(DWORD_PTR)(rgchTraceTagBuffer),
(DWORD)0, NULL, 0);
}
/*
* TraceError
*
* @mfunc:
* This function is for compatibility with old debug functionality.
* An error message is generated and sent to TraceMsg.
*
*/
void TraceError(LPSTR sz, LONG sc)
{
if (FAILED(sc))
{
char rgchTraceTagBuffer[MAXDEBUGSTRLEN];
wsprintfA(rgchTraceTagBuffer,
"%s, error=%ld (%#08lx).", sz, sc, sc);
TraceMsg(MAKEFLAGS(TRCSUBSYSNONE, TRCSEVERR, TRCSCOPENONE,
TRCDATASTRING, TRCDATANONE), (DWORD)(DWORD_PTR)(rgchTraceTagBuffer),
(DWORD)0, NULL, 0);
}
}
/*
* CheckTrace
*
* @mfunc
* This function checks to see if tracing should be performed
* in a function given the debug options set and the subsystem
* the function is in.
* ptrcf - Pointer to TrcFlags structure passed to CTrace.
*
* @rdesc
* True if tracing should be performed, false otherwise.
*
*/
static BOOL CheckTrace(TrcFlags * ptrcf)
{
DWORD dwOpt;
//Set dwOpt to the correct value for the subsytem we are
//in.
switch (ptrcf->fields.uSubSystem)
{
case TRCSUBSYSDISP: dwOpt = OPTTRACEDISP; break;
case TRCSUBSYSWRAP: dwOpt = OPTTRACEWRAP; break;
case TRCSUBSYSEDIT: dwOpt = OPTTRACEEDIT; break;
case TRCSUBSYSTS: dwOpt = OPTTRACETS; break;
case TRCSUBSYSTOM: dwOpt = OPTTRACETOM; break;
case TRCSUBSYSOLE: dwOpt = OPTTRACEOLE; break;
case TRCSUBSYSBACK: dwOpt = OPTTRACEBACK; break;
case TRCSUBSYSSEL: dwOpt = OPTTRACESEL; break;
case TRCSUBSYSHOST: dwOpt = OPTTRACEHOST; break;
case TRCSUBSYSDTE: dwOpt = OPTTRACEDTE; break;
case TRCSUBSYSUNDO: dwOpt = OPTTRACEUNDO; break;
case TRCSUBSYSRANG: dwOpt = OPTTRACERANG; break;
case TRCSUBSYSUTIL: dwOpt = OPTTRACEUTIL; break;
case TRCSUBSYSNOTM: dwOpt = OPTTRACENOTM; break;
case TRCSUBSYSRTFR: dwOpt = OPTTRACERTFR; break;
case TRCSUBSYSRTFW: dwOpt = OPTTRACERTFW; break;
case TRCSUBSYSPRT: dwOpt = OPTTRACEPRT; break;
case TRCSUBSYSFE: dwOpt = OPTTRACEFE; break;
case TRCSUBSYSFONT: dwOpt = OPTTRACEFONT; break;
default:
return FALSE;
}
//If there is no tracing at any level enabled, return false.
if (!ISOPTSET(dwOpt) && !fTrace
&& !(fTraceExt && (ptrcf->fields.uScope == TRCSCOPEEXTERN)))
return FALSE;
return TRUE;
}
/*
* CTrace::CTrace
*
* @mfunc
* This constructor is used to generate output about the function
* it is called from. Creating an instance of this class on the
* stack at the beginning of a function, will cause a trace message
* to be sent to the debug output. When the function returns, the
* destructor will be called automatically and another message
* will be sent to the debug output.
* This constructor takes several parameters to pass on to
* TraceMsg and it also stores certain data for use by the destructor.
*
* dwFlags - Packed values tell us how to generate the message.
* dw1 - The first of two data parameters. This must be
* the name of the function we were called from.
* dw2 - The second of two data parameters. This will be either
* unused or it will be a parameter to be interpreted by
* TraceMsg.
* szFile - File name we were called from.
*
*/
CTrace::CTrace(DWORD dwFlags, DWORD dw1, DWORD dw2, LPSTR szFile)
{
char szFunc[80];
int tls;
trcf.dw = dwFlags;
//Return if tracing is not enabled.
if (!CheckTrace(&trcf))
return;
//Increment indentation level on entrance to function
tls = (int)(DWORD_PTR)TlsGetValue(TlsIndex);
tls++;
TlsSetValue(TlsIndex, (LPVOID)(DWORD_PTR)tls);
szFunc[0] = '\0';
lstrcpyA(szFileName, szFile);
lstrcpyA(szFuncName, (LPSTR)(DWORD_PTR)dw1);
sprintf(szFunc, "IN : %s.", szFuncName);
TraceMsg (trcf.dw, (DWORD)(DWORD_PTR)szFunc, dw2, szFileName, 0);
}
/*
* CTrace::~CTrace
*
* @mfunc
* This destructor is used to generate output about the function
* it is called from. Creating an instance of this class on the
* stack at the beginning of a function, will cause a trace message
* to be sent to the debug output. When the function returns, the
* destructor will be called automatically and another message
* will be sent to the debug output.
*
*
*/
CTrace::~CTrace()
{
char szFunc[80];
int tls;
//Return if tracing is not enabled.
if (!CheckTrace(&trcf))
return;
szFunc[0] = '\0';
sprintf(szFunc, "OUT: %s.", szFuncName);
trcf.fields.uData2 = TRCDATANONE;
TraceMsg (trcf.dw, (DWORD)(DWORD_PTR)szFunc, 0, szFileName, 0);
//Decrement indentation level on exit from function
tls = (int)(DWORD_PTR)TlsGetValue(TlsIndex);
tls--;
TlsSetValue(TlsIndex, (LPVOID)(DWORD_PTR)tls);
}
#endif //!_RELEASE_ASSERTS_
#endif // !!(DEBUG) && !! _RELEASE_ASSERTS_