mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1029 lines
30 KiB
1029 lines
30 KiB
/////////////////////////////////////////////////////////////////////////////
|
|
// File: DEBUG.CPP
|
|
// Owner: t-danmo
|
|
//
|
|
// Debugging procedures
|
|
//
|
|
|
|
#include "common.h"
|
|
|
|
#ifdef DEBUG
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Public Variables
|
|
//
|
|
|
|
// To enable/disable Trace() at run-time
|
|
DWORD dwTraceFlags = (DWORD)(0xFFFF & ~mskTracePaintUI);
|
|
BOOL fShowAssertDialog = TRUE;
|
|
BOOL fShowReportDialog = TRUE;
|
|
BOOL fAssertDialogShown = FALSE;
|
|
BOOL fBeepOnFailure = FALSE;
|
|
BOOL fCreateLogFile = FALSE;
|
|
BOOL fShowErrorsOnExit = FALSE;
|
|
|
|
int cAssertGood = 0; // Number of times an assertion has been successful
|
|
int cAssertFail = 0; // Number of times an assertion has failed
|
|
int cReportGood = 0; // Number of times an unsual situation did not occur
|
|
int cReportFail = 0; // Number of times an unsual situation did occur
|
|
|
|
int cMemAllocSkip = 0; // Number of times before memory failure
|
|
int cMemAllocFail = 0; // Number of failures
|
|
int cMemAllocTotal = 0; // Number of call FSimulateMemoryFailure()
|
|
|
|
int cIOSkip = 0; // Number of times before IO failure
|
|
int cIOFail = 0; // Number of failures
|
|
int cIOTotal = 0; // Number of call FSimulateIOFailure()
|
|
|
|
int cResourceLoadSkip=0; // Number of times before resource load failure
|
|
int cResourceLoadFail=0; // Number of failures
|
|
int cResourceLoadTotal=0; // Number of call FSimulateResourceLoadFailure()
|
|
|
|
|
|
BOOL fEnableSourceTracking = FALSE;
|
|
BOOL fExpandPathName = FALSE;
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Private Variables
|
|
//
|
|
const TCHAR szUnusualSit[] = _T(szAPPNAME " - Unusual situation (not an error)");
|
|
const TCHAR szAssertFailed[] = _T(szAPPNAME " - Assertion failed!");
|
|
|
|
|
|
#define mskMBP_AssertFail 0x01
|
|
#define mskMBP_ReportFail 0x02
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void DbgMsgBoxPrintf(
|
|
DWORD dwFlags,
|
|
const TCHAR szTitle[],
|
|
const TCHAR szFile[],
|
|
int nLine,
|
|
const TCHAR szExpr[],
|
|
const TCHAR szFormat[], // May be NULL
|
|
va_list arglist)
|
|
{
|
|
TCHAR szTrace[1024];
|
|
TCHAR szMsgBox[1024];
|
|
TCHAR szT[1024];
|
|
BOOL fShowDialog = FALSE;
|
|
int iRet;
|
|
|
|
if (szTitle == NULL || szFile == NULL)
|
|
{
|
|
Trace2(mskTraceAlways, "\nAssert(szTitle != NULL && szFile != NULL): Invalid Parameters. { %s@%d }", __FILE__, __LINE__);
|
|
return;
|
|
}
|
|
szT[0] = 0;
|
|
szT[1] = 0;
|
|
if (szFormat)
|
|
{
|
|
lstrcpy(szT, _W"\n");
|
|
wvsprintf(&szT[1], szFormat, arglist);
|
|
}
|
|
if (dwFlags & mskMBP_AssertFail)
|
|
{
|
|
cAssertFail++;
|
|
fShowDialog = fShowAssertDialog;
|
|
Assert(szExpr);
|
|
if (szExpr == NULL)
|
|
{
|
|
Trace2(mskTraceAlways, "\nAssert(szExpr != NULL): Inconsistent Parameter. { %s@%d }", __FILE__, __LINE__);
|
|
return;
|
|
}
|
|
wsprintf(szTrace, "\nAssert(%s), { %s@%d } %s", szExpr, szFile, nLine, &szT[1]);
|
|
wsprintf(szMsgBox, "Assert(%s);%s\n\nFile %s, line %d, revision %s.", szExpr, szT, szFile, nLine, __DATE__);
|
|
}
|
|
else if (dwFlags & mskMBP_ReportFail)
|
|
{
|
|
cReportFail++;
|
|
fShowDialog = fShowReportDialog;
|
|
if (szExpr)
|
|
{
|
|
wsprintf(szTrace, "\nReport(%s), { %s@%d} %s", szExpr, szFile, nLine, &szT[1]);
|
|
wsprintf(szMsgBox, "Report(%s);%s\n\nFile %s, line %d, revision %s.", szExpr, szT, szFile, nLine, __DATE__);
|
|
}
|
|
else
|
|
{
|
|
wsprintf(szTrace, "\nUnsualSituation: { %s@%d } %s", szFile, nLine, &szT[1]);
|
|
wsprintf(szMsgBox, "UnsualSituation:%s\n\nFile %s, line %d, revision %s.", szT, szFile, nLine, __DATE__);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Trace2(mskTraceAlways, "\nAssert(FALSE): Unknown Flag. { %s@%d }", __FILE__, __LINE__);
|
|
return;
|
|
}
|
|
|
|
if (lstrlen(szTrace) >= LENGTH(szTrace) ||
|
|
lstrlen(szMsgBox) >= LENGTH(szMsgBox))
|
|
{
|
|
Trace2(mskTraceAlways, "\nAssert(FALSE): Buffer Overflow. { %s@%d }", __FILE__, __LINE__);
|
|
return;
|
|
}
|
|
|
|
szTrace[200] = 0; // Prevent a too long line
|
|
#ifdef DBWIN
|
|
if (fSendSzToDbWinEdit)
|
|
OutputDbWinString(szTrace); // Send the string to hwndDbWinEdit
|
|
if (fSendSzToDebugger)
|
|
#endif // DBWIN
|
|
OutputDebugString(szTrace); // Send the string to the debug terminal
|
|
if (fAssertDialogShown || !fShowDialog)
|
|
return;
|
|
if (fBeepOnFailure)
|
|
MessageBeep(0);
|
|
fAssertDialogShown = TRUE;
|
|
iRet = MessageBox(
|
|
hwndMain,
|
|
szMsgBox,
|
|
szTitle,
|
|
MB_ABORTRETRYIGNORE | MB_ICONSTOP | MB_DEFBUTTON2 | MB_TASKMODAL);
|
|
fAssertDialogShown = FALSE;
|
|
#ifdef DBWIN
|
|
if (GetAsyncKeyState(VK_CONTROL)<0)
|
|
dbwinreginfo.fSaveToClipboard = TRUE;
|
|
#endif // DBWIN
|
|
switch (iRet)
|
|
{
|
|
case IDABORT:
|
|
{
|
|
if (GetAsyncKeyState(VK_SHIFT)<0)
|
|
{
|
|
int * p = NULL;
|
|
iRet = *p; // Force a GPF to allow debugger to kick-in
|
|
}
|
|
abort();
|
|
}
|
|
break;
|
|
|
|
case IDIGNORE:
|
|
if (GetAsyncKeyState(VK_SHIFT)<0)
|
|
{
|
|
if (dwFlags & mskMBP_AssertFail)
|
|
fShowAssertDialog = FALSE;
|
|
else
|
|
fShowReportDialog = FALSE;
|
|
}
|
|
break;
|
|
case IDRETRY:
|
|
DebugBreak();
|
|
break;
|
|
} // switch
|
|
} // DbgMsgBoxPrintf
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// AssertMsgPrintf()
|
|
//
|
|
// Report an assertion failure
|
|
//
|
|
void AssertMsgPrintf(int nLine, const TCHAR szFile[], const TCHAR szExpr[], const TCHAR szFormat[], ...)
|
|
{
|
|
va_list arglist;
|
|
|
|
va_start(arglist, szFormat);
|
|
DbgMsgBoxPrintf(mskMBP_AssertFail, szAssertFailed, szFile, nLine, szExpr, szFormat, arglist);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ReportMsgPrintf()
|
|
//
|
|
// Report an unusual situation
|
|
//
|
|
void ReportMsgPrintf(int nLine, const TCHAR szFile[], const TCHAR szExpr[], const TCHAR szFormat[], ...)
|
|
{
|
|
va_list arglist;
|
|
|
|
va_start(arglist, szFormat);
|
|
DbgMsgBoxPrintf(mskMBP_ReportFail, szUnusualSit, szFile, nLine, szExpr, szFormat, arglist);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// AssertClassName()
|
|
//
|
|
// Assert hwnd is a valid window of class szClassName
|
|
// This is useful to prevent a given operation to be done
|
|
// on a wrong type of window
|
|
//
|
|
void AssertClassName(HWND hwnd, const TCHAR szClassName[])
|
|
{
|
|
TCHAR szT[64];
|
|
|
|
AssertSz1(IsWindow(hwnd), "Invalid window handle hwnd=0x%08X", hwnd);
|
|
Assert(szClassName != NULL);
|
|
GetClassName(hwnd, szT, LENGTH(szT)-1);
|
|
AssertSz2(
|
|
lstrcmpi(szT, szClassName) == sgnEqual,
|
|
"Window hwnd=0x%08X is expected to be of class '%s'",
|
|
hwnd, szClassName);
|
|
} // AssertClassName
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
LRESULT SendMessageFor(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, const TCHAR szClassName[])
|
|
{
|
|
AssertSz1(IsWindow(hwnd), "Invalid window handle hwnd=0x%08X", hwnd);
|
|
AssertClassName(hwnd, szClassName);
|
|
return SendMessage(hwnd, uMsg, wParam, lParam);
|
|
} // SendMessageFor
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
LONG SetWindowLongFor(HWND hwnd, int iIndex, LONG lParam, const TCHAR szClassName[])
|
|
{
|
|
AssertSz1(IsWindow(hwnd), "Invalid window handle hwnd=0x%08X", hwnd);
|
|
AssertClassName(hwnd, szClassName);
|
|
return SetWindowLong(hwnd, iIndex, lParam);
|
|
} // SetWindowLongFor
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
LONG GetWindowLongFrom(HWND hwnd , int iIndex, const TCHAR szClassName[])
|
|
{
|
|
AssertSz1(IsWindow(hwnd), "Invalid window handle hwnd=0x%08X", hwnd);
|
|
AssertClassName(hwnd, szClassName);
|
|
return GetWindowLong(hwnd, iIndex);
|
|
} // GetWindowLongFrom
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
LRESULT LSendMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
AssertSz1(IsWindow(hwnd), "Invalid window handle hwnd=0x%08X", hwnd);
|
|
return SendMessage(hwnd, uMsg, wParam, lParam);
|
|
} // LSendMessage
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
LRESULT LSendDlgItemMessage(HWND hdlg, int wIdDlgItem, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
AssertSz1(IsWindow(hdlg), "Invalid dialog handle hdlg=0x%08X", hdlg);
|
|
AssertSz1(IsWindow(GetDlgItem(hdlg, wIdDlgItem)), "Control Id=%d does not exist", wIdDlgItem);
|
|
return SendDlgItemMessage(hdlg, wIdDlgItem, uMsg, wParam, lParam);
|
|
} // LSendDlgItemMessage
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
int CchGetWindowText(HWND hwnd, OUT LPTSTR lpszString, int cchMaxString)
|
|
{
|
|
int cchResult;
|
|
|
|
AssertSz1(IsWindow(hwnd), "Invalid window handle hwnd=0x%08X", hwnd);
|
|
Assert(lpszString != NULL);
|
|
Assert(cchMaxString > 1);
|
|
cchResult = GetWindowText(hwnd, lpszString, cchMaxString);
|
|
Assert(cchResult >= 0);
|
|
if (GetWindowTextLength(hwnd) >= cchMaxString)
|
|
{
|
|
Trace1(mskTraceWarnings, "\nINFO: Buffer too small for GetWindowText(\"%s\").", lpszString);
|
|
}
|
|
return cchResult;
|
|
} // CchGetWindowText
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL FSetWindowText(HWND hwnd, IN LPCTSTR lpszString)
|
|
{
|
|
BOOL fResult;
|
|
|
|
AssertSz1(IsWindow(hwnd), "Invalid window handle hwnd=0x%08X", hwnd);
|
|
fResult = SetWindowText(hwnd, lpszString);
|
|
Assert(fResult);
|
|
return fResult;
|
|
} // FSetWindowText
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HWND HGetDlgItem(HWND hdlg, int wIdDlgItem)
|
|
{
|
|
HWND hwndItem;
|
|
|
|
AssertSz1(IsWindow(hdlg), "Invalid dialog handle hdlg=0x%08X", hdlg);
|
|
AssertSz1(IsWindow(GetDlgItem(hdlg, wIdDlgItem)), "Control Id=%d does not exist", wIdDlgItem);
|
|
hwndItem = GetDlgItem(hdlg, wIdDlgItem);
|
|
Assert(IsWindow(hwndItem));
|
|
return hwndItem;
|
|
} // HGetDlgItem
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
UINT CchGetDlgItemText(HWND hdlg, int wIdDlgItem, OUT LPTSTR lpszString, int cchMaxString)
|
|
{
|
|
UINT uResult;
|
|
|
|
AssertSz1(IsWindow(hdlg), "Invalid dialog handle hdlg=0x%08X", hdlg);
|
|
AssertSz1(IsWindow(GetDlgItem(hdlg, wIdDlgItem)), "Control Id=%d does not exist", wIdDlgItem);
|
|
Assert(lpszString);
|
|
Assert(cchMaxString > 1);
|
|
uResult = GetDlgItemText(hdlg, wIdDlgItem, lpszString, cchMaxString);
|
|
Assert((int)uResult >= 0);
|
|
if (GetWindowTextLength(HGetDlgItem(hdlg, wIdDlgItem)) >= cchMaxString)
|
|
{
|
|
Trace1(mskTraceWarnings, "\nINFO: Buffer too small for GetDlgItemText(Id=%d).", wIdDlgItem);
|
|
}
|
|
return uResult;
|
|
} // CchGetDlgItemText
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL FSetDlgItemText(HWND hdlg, int wIdDlgItem, IN LPCTSTR lpszString)
|
|
{
|
|
BOOL fResult;
|
|
|
|
AssertSz1(IsWindow(hdlg), "Invalid dialog handle hdlg=0x%08X", hdlg);
|
|
AssertSz1(IsWindow(GetDlgItem(hdlg, wIdDlgItem)), "Control Id=%d does not exist", wIdDlgItem);
|
|
fResult = SetDlgItemText(hdlg, wIdDlgItem, lpszString);
|
|
Assert(fResult);
|
|
return fResult;
|
|
} // FSetDlgItemText
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
UINT FIsDlgButtonChecked(HWND hdlg, int wIdButton)
|
|
{
|
|
AssertSz1(IsWindow(hdlg), "Invalid dialog handle hdlg=0x%08X", hdlg);
|
|
AssertSz1(IsWindow(GetDlgItem(hdlg, wIdButton)), "Control Id=%d does not exist", wIdButton);
|
|
return IsDlgButtonChecked(hdlg, wIdButton);
|
|
} // FIsDlgButtonChecked
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void DbgTrace(
|
|
int nLine,
|
|
const TCHAR szFile[],
|
|
DWORD dwFlags,
|
|
const TCHAR * szFormat,
|
|
...)
|
|
{
|
|
va_list arglist;
|
|
TCHAR sz[1024];
|
|
int cch;
|
|
|
|
Assert(szFile);
|
|
Assert(szFormat);
|
|
va_start(arglist, szFormat);
|
|
if ((dwFlags == mskTraceAlways) || (dwFlags & dwTraceFlags))
|
|
{
|
|
#ifdef DBWIN
|
|
if (fSendSzToDbWinEdit == FALSE && fSendSzToDebugger == FALSE)
|
|
return;
|
|
#endif // DBWIN
|
|
cch = 0;
|
|
if (fEnableSourceTracking)
|
|
{
|
|
const TCHAR * pch = szFile;
|
|
|
|
if (!fExpandPathName)
|
|
{
|
|
// Strip out the path name
|
|
pch = strrchr(szFile, _W'\\');
|
|
if (pch == NULL)
|
|
pch = szFile;
|
|
else
|
|
pch++;
|
|
}
|
|
// Copy the CR to the buffer
|
|
while (*szFormat == _W'\n')
|
|
{
|
|
sz[cch] = _W'\n';
|
|
cch++;
|
|
szFormat++;
|
|
}
|
|
cch += wsprintf(&sz[cch], _W"{%s@%d} ", pch, nLine);
|
|
} // if
|
|
wvsprintf(&sz[cch], szFormat, arglist);
|
|
Assert(lstrlen(sz) < LENGTH(sz));
|
|
sz[LENGTH(sz) - 1] = 0; // Just in case we overflowed into sz
|
|
#ifdef DBWIN
|
|
if (fSendSzToDbWinEdit)
|
|
OutputDbWinString(sz);
|
|
if (fSendSzToDebugger)
|
|
#endif // DBWIN
|
|
OutputDebugString(sz);
|
|
} // if
|
|
} // DbgTrace
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// FIsZeroInit()
|
|
//
|
|
// Return TRUE if a block of memory is filled with zeroes
|
|
// otherwise return FALSE
|
|
//
|
|
BOOL FIsZeroInit(void * pvData, UINT cbData)
|
|
{
|
|
Assert(pvData != NULL);
|
|
for (BYTE * pbData = (BYTE *)pvData; cbData; cbData--)
|
|
{
|
|
if (*pbData++)
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
} // FIsZeroInit
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CchLoadString()
|
|
//
|
|
// Same as ::LoadString() but with extra error checking.
|
|
// CchLoadString is #defined to ::LoadString in the retail build
|
|
//
|
|
int CchLoadString(
|
|
UINT wIdString, // IN: String Id
|
|
TCHAR szBuffer[], // OUT: Buffer to receive the string
|
|
int cchBuffer) // IN: Length of the buffer (in characters; not in bytes)
|
|
{
|
|
int cch;
|
|
|
|
Assert(HIWORD(wIdString) == 0);
|
|
Assert(szBuffer);
|
|
cch = ::LoadString(hInstanceSave, wIdString, szBuffer, cchBuffer);
|
|
if (cch == 0)
|
|
{
|
|
// String Id not found
|
|
Trace1(mskTraceWarnings, "\nINFO: CchLoadString(Id=%d) has a string of zero length (StringId not found).", wIdString);
|
|
}
|
|
if (cch >= cchBuffer - 1)
|
|
ReportSz1("INFO: CchLoadString(Id=%d)\nNot enough buffer space to hold the entire string.", wIdString);
|
|
return cch;
|
|
} // CchLoadString
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// FSimulateResourceLoadFailure()
|
|
//
|
|
// Return TRUE if a resource failure should fail due to simulation; update
|
|
// simulation variables as necessary.
|
|
// cResourceLoadSkip: Number of times before failure
|
|
// cResourceLoadFail: Number of consecutive failures to simulate
|
|
// cResourceLoadTotal: Number of calls to FSimulateResourceLoadFailure()
|
|
//
|
|
BOOL FSimulateResourceLoadFailure()
|
|
{
|
|
cResourceLoadTotal++;
|
|
|
|
if (cResourceLoadSkip > 0)
|
|
{
|
|
cResourceLoadSkip--;
|
|
return FALSE;
|
|
}
|
|
if (cResourceLoadFail > 0)
|
|
{
|
|
cResourceLoadFail--;
|
|
Trace1(mskTraceAlways,
|
|
"\nINFO: FSimulateResourceLoadFailure() returned TRUE, Count=%d.",
|
|
cResourceLoadTotal);
|
|
if (fBeepOnFailure)
|
|
MessageBeep(MB_ICONEXCLAMATION);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
} // FSimulateResourceLoadFailure
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// HLoadIcon()
|
|
//
|
|
// Loads an icon from the resource module.
|
|
// Return NULL if a resource failure should fail due to simulation,
|
|
// otherwise return a handle to the icon by calling the LoadIcon()
|
|
// function.
|
|
//
|
|
HICON HLoadIcon(UINT wIdIcon)
|
|
{
|
|
static int cTotal=0;
|
|
HICON hicon;
|
|
|
|
cTotal++;
|
|
|
|
Assert(hInstanceSave!=NULL);
|
|
Assert(HIWORD(wIdIcon) == 0);
|
|
if (FSimulateResourceLoadFailure())
|
|
{
|
|
Trace2(mskTraceAlways,
|
|
"\nINFO: HLoadIcon(Id=%d) returned NULL, Count=%d.",
|
|
wIdIcon, cTotal);
|
|
return NULL;
|
|
}
|
|
hicon = LoadIcon(hInstanceSave, MAKEINTRESOURCE(wIdIcon));
|
|
ReportFSz1(hicon, "Unable to load icon Id=%d", wIdIcon);
|
|
return hicon;
|
|
} // HLoadIcon
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// HLoadBitmap()
|
|
//
|
|
// Loads an icon from the resource module.
|
|
// Return NULL if a resource failure should fail due to simulation,
|
|
// otherwise return a handle to the icon by calling the LoadBitmap()
|
|
// function.
|
|
//
|
|
HBITMAP HLoadBitmap(UINT wIdBitmap)
|
|
{
|
|
static int cTotal=0;
|
|
HBITMAP hbitmap;
|
|
|
|
cTotal++;
|
|
|
|
Assert(hInstanceSave!=NULL);
|
|
Assert(HIWORD(wIdBitmap) == 0);
|
|
if (FSimulateResourceLoadFailure())
|
|
{
|
|
Trace2(mskTraceAlways,
|
|
"\nINFO: HLoadBitmap(Id=%d) returned NULL, Count=%d.",
|
|
wIdBitmap, cTotal);
|
|
return NULL;
|
|
}
|
|
hbitmap = LoadBitmap(hInstanceSave, MAKEINTRESOURCE(wIdBitmap));
|
|
ReportFSz1(hbitmap, "Unable to load bitmap Id=%d", wIdBitmap);
|
|
return hbitmap;
|
|
} // HLoadBitmap
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// HLoadMenu()
|
|
//
|
|
// Loads a menu from the resource module.
|
|
// Return NULL if a resource failure should fail due to simulation,
|
|
// otherwise return a handle to the Menu by calling the LoadMenu()
|
|
// function.
|
|
//
|
|
HMENU HLoadMenu(UINT wIdMenu)
|
|
{
|
|
static int cTotal=0;
|
|
HMENU hmenu;
|
|
|
|
cTotal++;
|
|
|
|
Assert(hInstanceSave!=NULL);
|
|
Assert(HIWORD(wIdMenu) == 0);
|
|
if (FSimulateResourceLoadFailure())
|
|
{
|
|
Trace2(mskTraceAlways,
|
|
"\nINFO: HLoadMenu(Id=%d) returned NULL, Count=%d.",
|
|
wIdMenu, cTotal);
|
|
return NULL;
|
|
}
|
|
hmenu = LoadMenu(hInstanceSave, MAKEINTRESOURCE(wIdMenu));
|
|
ReportFSz1(hmenu, "Unable to load menu Id=%d", wIdMenu);
|
|
return hmenu;
|
|
} // HLoadMenu
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// HLoadCursor()
|
|
//
|
|
// Loads a cursor from the resource module.
|
|
// Return NULL if a resource failure should fail due to simulation,
|
|
// otherwise return a handle to the Cursor by calling the LoadCursor()
|
|
// function.
|
|
//
|
|
HCURSOR HLoadCursor(UINT wIdCursor)
|
|
{
|
|
static int cTotal=0;
|
|
HCURSOR hcursor;
|
|
|
|
cTotal++;
|
|
|
|
Assert(hInstanceSave!=NULL);
|
|
Assert(HIWORD(wIdCursor) == 0);
|
|
if (FSimulateResourceLoadFailure())
|
|
{
|
|
Trace2(mskTraceAlways,
|
|
"\nINFO: HLoadCursor(Id=%d) returned NULL, Count=%d.",
|
|
wIdCursor, cTotal);
|
|
return NULL;
|
|
}
|
|
hcursor = LoadCursor(hInstanceSave, MAKEINTRESOURCE(wIdCursor));
|
|
ReportFSz1(hcursor, "Unable to load cursor Id=%d", wIdCursor);
|
|
return hcursor;
|
|
} // HLoadCursor
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// SetDlgTraceFlags()
|
|
//
|
|
// Set the checkboxes according to the trace flags
|
|
//
|
|
void SetDlgTraceFlags(HWND hdlg, DWORD dwTraceFlagsNew, BOOL fGrayed = FALSE)
|
|
{
|
|
BOOL fTrue = fGrayed ? 2 : TRUE;
|
|
BOOL fFalse = fGrayed ? 2 : FALSE;
|
|
|
|
CheckDlgButton(hdlg, IDC_CHECK_0001,
|
|
(dwTraceFlagsNew & 0x0001) ? fTrue : fFalse);
|
|
CheckDlgButton(hdlg, IDC_CHECK_0002,
|
|
(dwTraceFlagsNew & 0x0002) ? fTrue : fFalse);
|
|
CheckDlgButton(hdlg, IDC_CHECK_0004,
|
|
(dwTraceFlagsNew & 0x0004) ? fTrue : fFalse);
|
|
CheckDlgButton(hdlg, IDC_CHECK_0008,
|
|
(dwTraceFlagsNew & 0x0008) ? fTrue : fFalse);
|
|
CheckDlgButton(hdlg, IDC_CHECK_0010,
|
|
(dwTraceFlagsNew & 0x0010) ? fTrue : fFalse);
|
|
CheckDlgButton(hdlg, IDC_CHECK_0020,
|
|
(dwTraceFlagsNew & 0x0020) ? fTrue : fFalse);
|
|
CheckDlgButton(hdlg, IDC_CHECK_0040,
|
|
(dwTraceFlagsNew & 0x0040) ? fTrue : fFalse);
|
|
CheckDlgButton(hdlg, IDC_CHECK_TraceUnused1,
|
|
(dwTraceFlagsNew & mskTraceUnused1) ? fTrue : fFalse);
|
|
CheckDlgButton(hdlg, IDC_CHECK_TraceUnused2,
|
|
(dwTraceFlagsNew & mskTraceUnused2) ? fTrue : fFalse);
|
|
CheckDlgButton(hdlg, IDC_CHECK_TraceUnused3,
|
|
(dwTraceFlagsNew & mskTraceUnused3) ? fTrue : fFalse);
|
|
} // SetDlgTraceFlags
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// SetDlgEditTraceFlags()
|
|
//
|
|
// Set the edit control to the value of the trace flags
|
|
//
|
|
void SetDlgEditTraceFlags(HWND hdlg, DWORD dwTraceFlagsNew)
|
|
{
|
|
char szT[32];
|
|
|
|
wsprintf(szT, "0x%08X", dwTraceFlagsNew);
|
|
SideAssert(SetDlgItemText(hdlg, IDC_EDIT_TRACEFLAGS, szT));
|
|
} // SetDlgEditTraceFlags
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// DwGetDlgTraceFlags()
|
|
//
|
|
// Get the trace flags from the checkboxes of the dialog
|
|
//
|
|
DWORD DwGetDlgTraceFlags(HWND hdlg)
|
|
{
|
|
DWORD dwTraceFlagsT = 0;
|
|
|
|
Assert(IsWindow(hdlg));
|
|
if (IsDlgButtonChecked(hdlg, IDC_CHECK_0001) == 1)
|
|
dwTraceFlagsT |= 0x0001;
|
|
if (IsDlgButtonChecked(hdlg, IDC_CHECK_0002) == 1)
|
|
dwTraceFlagsT |= 0x0002;
|
|
if (IsDlgButtonChecked(hdlg, IDC_CHECK_0004) == 1)
|
|
dwTraceFlagsT |= 0x0004;
|
|
if (IsDlgButtonChecked(hdlg, IDC_CHECK_0008) == 1)
|
|
dwTraceFlagsT |= 0x0008;
|
|
if (IsDlgButtonChecked(hdlg, IDC_CHECK_0010) == 1)
|
|
dwTraceFlagsT |= 0x0010;
|
|
if (IsDlgButtonChecked(hdlg, IDC_CHECK_0020) == 1)
|
|
dwTraceFlagsT |= 0x0020;
|
|
if (IsDlgButtonChecked(hdlg, IDC_CHECK_0040) == 1)
|
|
dwTraceFlagsT |= 0x0040;
|
|
if (IsDlgButtonChecked(hdlg, IDC_CHECK_TraceUnused1) == 1)
|
|
dwTraceFlagsT |= mskTraceUnused1;
|
|
if (IsDlgButtonChecked(hdlg, IDC_CHECK_TraceUnused2) == 1)
|
|
dwTraceFlagsT |= mskTraceUnused2;
|
|
if (IsDlgButtonChecked(hdlg, IDC_CHECK_TraceUnused3) == 1)
|
|
dwTraceFlagsT |= mskTraceUnused3;
|
|
return dwTraceFlagsT;
|
|
} // DwGetDlgTraceFlags
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// DlgProcSetTraceFlags()
|
|
//
|
|
// Dialog proc to set the trace flags
|
|
//
|
|
BOOL CALLBACK DlgProcSetTraceFlags(HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
DWORD dwTraceFlagsT;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
UNREF(lParam);
|
|
SetDlgTraceFlags(hdlg, dwTraceFlags);
|
|
if (fEnableSourceTracking)
|
|
CheckDlgButton(hdlg, IDC_CHECK_EnableSourceTracking, TRUE);
|
|
else
|
|
EnableWindow(GetDlgItem(hdlg, IDC_CHECK_ExpandPathName), FALSE);
|
|
CheckDlgButton(hdlg, IDC_CHECK_ExpandPathName, fExpandPathName);
|
|
SetDlgEditTraceFlags(hdlg, dwTraceFlags);
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDOK:
|
|
if (!FGetCtrlDWordValue(
|
|
GetDlgItem(hdlg, IDC_EDIT_TRACEFLAGS),
|
|
&dwTraceFlags, 0, 0))
|
|
{
|
|
break;
|
|
}
|
|
fEnableSourceTracking = IsDlgButtonChecked(hdlg, IDC_CHECK_EnableSourceTracking);
|
|
fExpandPathName = IsDlgButtonChecked(hdlg, IDC_CHECK_ExpandPathName);
|
|
/* Fall through */
|
|
|
|
case IDCANCEL:
|
|
EndDialog(hdlg, 0);
|
|
break;
|
|
case IDC_EDIT_TRACEFLAGS:
|
|
if (HIWORD(wParam) == EN_CHANGE)
|
|
{
|
|
DWORD dwResult;
|
|
if (FGetCtrlDWordValue((HWND)lParam, OUT &dwResult, 0, 0))
|
|
SetDlgTraceFlags(hdlg, dwResult);
|
|
else
|
|
SetDlgTraceFlags(hdlg, 0, TRUE);
|
|
}
|
|
break;
|
|
case IDC_CHECK_EnableSourceTracking:
|
|
EnableWindow(GetDlgItem(hdlg, IDC_CHECK_ExpandPathName),
|
|
IsDlgButtonChecked(hdlg, IDC_CHECK_EnableSourceTracking));
|
|
break;
|
|
|
|
default:
|
|
dwTraceFlagsT = DwGetDlgTraceFlags(hdlg);
|
|
SetDlgEditTraceFlags(hdlg, dwTraceFlagsT);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
} // DlgProcSetTraceFlags
|
|
|
|
|
|
#ifndef NO_DEBUG_ALLOC
|
|
|
|
BOOL fAllocRefValid = TRUE;
|
|
PALLOCHEADER * rgAllocHeaderPtr = NULL;
|
|
int cAllocRef = 0; // Number of non-NULL pointers in rgAllocHeaderPtr
|
|
int cAllocRefAlloc = 0; // Number of elements allocated in rgAllocHeaderPtr
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Check the consistency of a ALLOCHEADER structure
|
|
// Return TRUE if the header is valid, otherwise FALSE
|
|
//
|
|
BOOL FAllocHeaderValid_(PALLOCHEADER pAllocHeader)
|
|
{
|
|
if (pAllocHeader == NULL)
|
|
return FALSE;
|
|
if (pAllocHeader->iAllocRef < 0 || pAllocHeader->iAllocRef >= cAllocRefAlloc)
|
|
return FALSE;
|
|
if (pAllocHeader->szFile == NULL)
|
|
return FALSE;
|
|
if (lstrcmp(pAllocHeader->szSignature, szAllocSignature) != sgnEqual)
|
|
return FALSE;
|
|
if (lstrcmp((TCHAR *)(pAllocHeader->rgbData + pAllocHeader->dwAllocSize), szAllocSignature) != sgnEqual)
|
|
return FALSE;
|
|
if (fAllocRefValid)
|
|
{
|
|
Assert(rgAllocHeaderPtr);
|
|
if (rgAllocHeaderPtr[pAllocHeader->iAllocRef] != pAllocHeader)
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void * AllocMem_(DWORD dwAllocSize, int nLine, const TCHAR szFile[])
|
|
{
|
|
PALLOCHEADER pAllocHeader;
|
|
PALLOCHEADER * ppAllocHeader;
|
|
int i;
|
|
|
|
#ifdef DBWIN
|
|
ReportFSz(hwndDbWin != NULL, "DbWin Window was destroyed");
|
|
#endif DBWIN
|
|
Trace2(dwAllocSize ? mskTraceNone : (mskTraceMemFailures | mskTraceWarnings),
|
|
"\nINFO: Malloc() with size of zero [%s@%d]", szFile, nLine);
|
|
// LATER: Simulate a memory failure
|
|
pAllocHeader = (PALLOCHEADER)malloc(sizeof(ALLOCHEADER) + dwAllocSize + cbAllocSignature);
|
|
if (pAllocHeader == NULL)
|
|
{
|
|
Trace2(mskTraceAlways, "\nMalloc() Failed [%s@%d]", szFile, nLine);
|
|
return NULL;
|
|
}
|
|
AssertSz(lstrlen(szAllocSignature) < cchAllocSignature, "Not enough room for the signature");
|
|
// Initialize the block
|
|
pAllocHeader->dwAllocSize = dwAllocSize; // Size of the block
|
|
pAllocHeader->nLine = nLine; // Line where the block has been allocated
|
|
pAllocHeader->szFile = szFile; // File where the block has been allocated
|
|
lstrcpy(pAllocHeader->szSignature, szAllocSignature); // Signature at beginning of block
|
|
lstrcpy((TCHAR *)(pAllocHeader->rgbData + dwAllocSize), szAllocSignature); // Signature at end of block
|
|
GarbageInit(pAllocHeader->rgbData, dwAllocSize);
|
|
|
|
if ((cAllocRef >= cAllocRefAlloc-1) && fAllocRefValid)
|
|
{
|
|
// Redundant assertions, but valuable comments
|
|
Assert(sizeof(PALLOCHEADER) == sizeof(rgAllocHeaderPtr[0]));
|
|
Assert(sizeof(PALLOCHEADER) == sizeof(*ppAllocHeader));
|
|
ppAllocHeader = (PALLOCHEADER *)realloc(
|
|
rgAllocHeaderPtr,
|
|
(cAllocRefAlloc + cAllocRefGranularity) * sizeof(PALLOCHEADER));
|
|
if (ppAllocHeader)
|
|
{
|
|
rgAllocHeaderPtr = ppAllocHeader;
|
|
// Initialize the rest of the array to NULL
|
|
ppAllocHeader = &rgAllocHeaderPtr[cAllocRefAlloc];
|
|
for (i = 0; i < cAllocRefGranularity; i++)
|
|
*ppAllocHeader++ = NULL;
|
|
cAllocRefAlloc += cAllocRefGranularity;
|
|
}
|
|
else
|
|
{
|
|
Trace0(mskTraceAlways, "\nUnable to allocate 'Allocation Reference Table'.");
|
|
fAllocRefValid = FALSE;
|
|
}
|
|
}
|
|
if (fAllocRefValid)
|
|
{
|
|
Assert(rgAllocHeaderPtr != NULL);
|
|
// The first pointer is a sentinel (ie, should be always NULL)
|
|
Assert(rgAllocHeaderPtr[0] == NULL);
|
|
ppAllocHeader = &rgAllocHeaderPtr[cAllocRefAlloc - 1];
|
|
while (*ppAllocHeader)
|
|
ppAllocHeader--;
|
|
// There must be an empty spot in the array
|
|
Assert(ppAllocHeader > &rgAllocHeaderPtr[0]);
|
|
*ppAllocHeader = pAllocHeader;
|
|
pAllocHeader->iAllocRef = ppAllocHeader - &rgAllocHeaderPtr[0];
|
|
Assert(pAllocHeader->iAllocRef < cAllocRefAlloc);
|
|
cAllocRef++;
|
|
}
|
|
Assert(FAllocHeaderValid_(pAllocHeader));
|
|
return pAllocHeader->rgbData;
|
|
} // AllocMem_
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void * ReAllocMem_(void * pvDataOld, DWORD dwAllocSize, int nLine, const TCHAR szFile[])
|
|
{
|
|
void * pvDataNew;
|
|
|
|
// It is simpler to simply call AllocMem_ and free the old block
|
|
pvDataNew = AllocMem_(dwAllocSize, nLine, szFile);
|
|
if (pvDataNew == NULL)
|
|
{
|
|
Trace2(mskTraceAlways, "\nReAlloc() returns NULL [%s@%d]", szFile, nLine);
|
|
return NULL;
|
|
}
|
|
if (pvDataOld)
|
|
{
|
|
PALLOCHEADER pAllocHeader;
|
|
DWORD dwAllocMin;
|
|
|
|
pAllocHeader = (PALLOCHEADER)pvDataOld - 1;
|
|
// Check if memory header has not been corrupted
|
|
AssertSz1(FAllocHeaderValid_(pAllocHeader), "Memory block 0x%08X is corrupted", pvDataOld);
|
|
dwAllocMin = pAllocHeader->dwAllocSize;
|
|
pAllocHeader = (PALLOCHEADER)pvDataNew - 1;
|
|
if (pAllocHeader->dwAllocSize < dwAllocMin)
|
|
dwAllocMin = pAllocHeader->dwAllocSize;
|
|
// Copy the old content of the block into the new one
|
|
memcpy(pvDataNew, pvDataOld, dwAllocMin);
|
|
FreeMem_(pvDataOld);
|
|
}
|
|
return pvDataNew;
|
|
} // ReAllocMem_
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void FreeMem_(void * pvData)
|
|
{
|
|
PALLOCHEADER pAllocHeader;
|
|
|
|
if (pvData == NULL)
|
|
return;
|
|
pAllocHeader = (PALLOCHEADER)pvData - 1;
|
|
// Check if memory header has not been corrupted
|
|
AssertSz1(
|
|
FAllocHeaderValid_(pAllocHeader),
|
|
"Memory block 0x%08X is corrupted."
|
|
"\n - You have corrupted the header or tail of memory block."
|
|
"\n - You are attempting to delete twice the same memory block."
|
|
"\n - You are attempting to delete a non-dynamic variable.",
|
|
pvData);
|
|
if (fAllocRefValid)
|
|
{
|
|
Assert(rgAllocHeaderPtr);
|
|
rgAllocHeaderPtr[pAllocHeader->iAllocRef] = NULL;
|
|
cAllocRef--;
|
|
}
|
|
Assert(cAllocRef >= 0);
|
|
GarbageInit(pAllocHeader, sizeof(ALLOCHEADER) + pAllocHeader->dwAllocSize + cbAllocSignature);
|
|
free(pAllocHeader);
|
|
} // FreeMem_
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
#undef new
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void * operator new(size_t nSize, int nLine, const char szFileName[])
|
|
{
|
|
return AllocMem_(nSize, nLine, szFileName);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void operator delete(void * pvData)
|
|
{
|
|
Free(pvData);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void CheckMemoryLeaks()
|
|
{
|
|
int i;
|
|
int cAllocRefT = 0;
|
|
int cAllocCorrupted = 0;
|
|
|
|
Trace0(mskTraceMemFailures, "\n[Local Heap Check]");
|
|
if (!fAllocRefValid)
|
|
{
|
|
Trace0(mskTraceAlways, "\nOut of memory for Allocation Reference Table.");
|
|
return;
|
|
}
|
|
if (rgAllocHeaderPtr == NULL)
|
|
{
|
|
Trace0(mskTraceMemFailures, "\nDebug Heap Not Enabled");
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < cAllocRefAlloc; i++)
|
|
{
|
|
PALLOCHEADER pAllocHeader = rgAllocHeaderPtr[i];
|
|
if (pAllocHeader == NULL)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
cAllocRefT++;
|
|
if (!FAllocHeaderValid_(pAllocHeader))
|
|
{
|
|
Trace2(mskTraceMemFailures, "\n[%d] : 0x%08lX - Corrupted.", i, pAllocHeader->rgbData);
|
|
cAllocCorrupted++;
|
|
}
|
|
else
|
|
{
|
|
BYTE szT[64];
|
|
|
|
const BYTE * pch = pAllocHeader->rgbData;
|
|
for (UINT j = 0; j < 60 && j < pAllocHeader->dwAllocSize; j++, pch++)
|
|
{
|
|
if (*pch >= ' ' && *pch <= '~')
|
|
szT[j] = *pch;
|
|
else
|
|
szT[j] = '.';
|
|
}
|
|
szT[j] = 0;
|
|
Trace6(
|
|
mskTraceMemFailures,
|
|
"\n[%d] : 0x%08lX - %ld bytes { \"%"_aS_"\" } [%s@%d]",
|
|
i, pAllocHeader->rgbData,
|
|
pAllocHeader->dwAllocSize, szT,
|
|
pAllocHeader->szFile, pAllocHeader->nLine);
|
|
}
|
|
}
|
|
} // for
|
|
if (cAllocRef)
|
|
{
|
|
Trace2(mskTraceMemFailures,
|
|
"\n %d memory blocks found, %d corrupted.",
|
|
cAllocRefT, cAllocCorrupted);
|
|
}
|
|
else
|
|
{
|
|
Trace0(mskTraceMemFailures, "\nNo memory leaks found...");
|
|
}
|
|
Assert(cAllocRefT == cAllocRef);
|
|
}
|
|
#endif // ~NO_DEBUG_ALLOC
|
|
|
|
|
|
class CDbgPostExitCheck
|
|
{
|
|
public:
|
|
~CDbgPostExitCheck()
|
|
{
|
|
#ifdef NO_DEBUG_ALLOC
|
|
Trace0(mskTraceMemFailures,
|
|
"\n[Local Heap Check]..."
|
|
"\nDebug Heap Not Enabled");
|
|
#else
|
|
// Dump any memory leaks to the debug window
|
|
CheckMemoryLeaks();
|
|
#endif // ~NO_DEBUG_ALLOC
|
|
Trace6(0x80000000, "\n[Integrety Check Report]"
|
|
"\n\tAssert() - %d total (%d failed, %d succeeded)."
|
|
"\n\tReport() - %d total (%d failed, %d succeeded).",
|
|
cAssertGood + cAssertFail, cAssertFail, cAssertGood,
|
|
cReportGood + cReportFail, cReportFail, cReportGood);
|
|
|
|
#ifdef DBWIN
|
|
// Destroy the DbWin window
|
|
Report(IsWindow(hwndDbWin));
|
|
DestroyWindow(hwndDbWin);
|
|
// hwndDbWin is set to NULL during the WM_DESTROY
|
|
Assert(hwndDbWin == NULL);
|
|
#endif // DBWIN
|
|
OutputDebugString("\n");
|
|
}
|
|
};
|
|
|
|
// Disable warning C4073: initializers put in library initialization area
|
|
#pragma warning (disable : 4073)
|
|
#pragma init_seg(lib)
|
|
static const CDbgPostExitCheck DbgPostExitCheck;
|
|
#pragma warning (default : 4073)
|
|
|
|
#endif // DEBUG
|