Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1520 lines
44 KiB

//+-------------------------------------------------------------------
// Microsoft OLE
// Copyright (C) Microsoft Corporation, 1994-1995.
//
// File: cdbghelp.cxx
//
// Contents: OLE Debug Helper Object
//
// Classes: CDebugHelper
//
// History: 19-Nov-94 DeanE Created
//---------------------------------------------------------------------
#include <dfheader.hxx>
#pragma hdrstop
// Global library character constants - note alphabetical order for
// easy reference
//
CONST TCHAR chBackSlash = TEXT('\\');
CONST TCHAR chEqual = TEXT('=');
CONST TCHAR chNewLine = TEXT('\n');
CONST TCHAR chNull = TEXT('\0');
CONST TCHAR chPeriod = TEXT('.');
CONST TCHAR chSpace = TEXT(' ');
CONST TCHAR chTrace = TEXT(' ');
CONST TCHAR chTraceErr = TEXT('e');
// Global library string contants - note alphabetical order for
// easy reference
//
CONST TCHAR szCRLF[] = TEXT("\r\n");
CONST TCHAR szError[] = TEXT("ERROR "); // Used TraceMsg for ERRORs
CONST TCHAR szNewLine[] = TEXT("\n");
CONST TCHAR szNull[] = TEXT("");
CONST TCHAR szPeriod[] = TEXT(".");
// Test Result Description strings
//
LPCTSTR szPass = TEXT("VAR_PASS");
LPCTSTR szFail = TEXT("VAR_FAIL");
LPCTSTR szAbort = TEXT("VAR_ABORT");
LPCTSTR szWarn = TEXT("WARNING");
LPCTSTR szInfo = TEXT("INFO");
LPCTSTR szInvalid = TEXT("INVALID!!");
// Debug Helper Usage String
//
LPTSTR gptszDebugHelperUsageString = {
TEXT("Debug Object Command line options:\r\n")
TEXT(" /logloc - where log output goes (bitfield)\r\n")
TEXT(" /traceloc - where trace output goes (bitfield)\r\n")
TEXT(" /tracelvl - trace levels (bitfield)\r\n")
TEXT(" /spyclass - spy window\r\n")
TEXT(" /labmode - do not use PopUp for errors\r\n")
TEXT(" /breakmode - break on error\r\n")
TEXT(" /verbose - trace hrchecks that are ok\r\n")
};
int giAlwaysNegativeOne = -1;
// Global variable, the THREAD_VALIDATE_FLAG_ON bit of which at present is
// used to do or skip thread validation DH_VDATETHREAD macro. Other bits
// might be used in future. Initialize the variable to set its bit
// THREAD_VALIDATE_FLAG_ON.
ULONG g_fThreadValidate = THREAD_VALIDATE_FLAG_ON ;
//+-------------------------------------------------------------------
// Member: CDebugHelp::CDebugHelp
//
// Synopsis: Initializes CDebugHelp object. Makes object usable
// in it's default state.
//
// Arguments: None.
//
// Returns: Nothing. Constructor cannot fail.
//
// History: 21-Nov-94 DeanE Created
//--------------------------------------------------------------------
CDebugHelp::CDebugHelp() :
_fLogLoc(DH_LOC_TERM),
_fTraceLoc(DH_LOC_TERM),
_fTraceLvl(DH_LVL_ALWAYS|DH_LVL_ERROR),
_fMode(DH_LABMODE),
_hrExpectedError(S_OK),
_fCreatedLog(FALSE),
_plog(NULL),
_hwndAssert(NULL),
_cPass(0),
_cAbort(0),
_cFail(0),
_cIndentLevel(0),
_fSpyWarning(0),
_pszSpyWindowClass((LPTSTR) SZ_DEFAULT_SPY_WINDOW_CLASS)
{
DWORD cchModule;
TCHAR szModule[CCH_MAX_MODULE];
TCHAR szModule1[CCH_MAX_MODULE];
short ret=0;
lstrcpy(_szDbgPrefix, TEXT("NoName"));
// Initialize the debug prefix string - it is the first
// CCH_MAX_DBGPREFIX characters in the name of this
// .exe, without the extension
//
cchModule = GetModuleFileName(NULL, szModule1, CCH_MAX_MODULE);
if ((0 != cchModule) && (cchModule < CCH_MAX_MODULE))
{
ret = GetFileTitle(szModule1, szModule, sizeof(szModule));
if (0 == ret)
{
//
// Strip the .exe extension if it exists
//
cchModule = _tcslen(szModule);
if (cchModule >= 4) // if the name has at least 4 chars
{
if (0 == _tcsicmp(szModule + cchModule - 4, TEXT(".exe")))
{
szModule[cchModule - 4] = TEXT('\0');
}
}
//
// Save the module name as the debug prefix
//
_tcscpy(_szDbgPrefix, szModule);
}
}
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::~CDebugHelp
//
// Synopsis: Releases resources associated with the CDebugHelp class.
// Sets member variables so the basic functions can work.
//
// Arguments: None
//
// Returns: Nothing.
//
// History: 21-Nov-94 DeanE Created
//--------------------------------------------------------------------
CDebugHelp::~CDebugHelp()
{
// Set all member variables to valid default values
_fLogLoc = DH_LOC_TERM;
_fTraceLoc = DH_LOC_TERM;
_fTraceLvl = DH_LVL_ALWAYS|DH_LVL_ERROR;
_fMode = DH_LABMODE;
// Close the log by deleting the log object, if we created it
if (_fCreatedLog)
{
delete _plog;
}
_plog = NULL;
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::GetRegDbgInfo
//
// Synopsis: Initializes CDebugHelp object from the registry. Even
// if errors occur, the object is left in the usable
// default state.
//
// Arguments: [pszRegKey] - Registy key holding necessary values.
//
// Returns: S_OK if values read and settings are valid, an error
// code if not.
//
// History: 21-Nov-94 DeanE Created
//--------------------------------------------------------------------
HRESULT CDebugHelp::GetRegDbgInfo(LPTSTR pszRegKey)
{
CRegistryHelp *prhRegKey = NULL;
HRESULT hr = E_FAIL;
DWORD fLabMode = TRUE;
DWORD fBreakMode= FALSE;
DWORD fVerbose = FALSE;
// Open the registry key
prhRegKey = new(NullOnFail) CRegistryHelp(
#ifndef _MAC
HKEY_CURRENT_USER,
#else // _MAC
HKEY_CLASSES_ROOT,
#endif // _MAC
pszRegKey,
REG_OPTION_NON_VOLATILE,
KEY_READ,
&hr);
if (prhRegKey == NULL)
{
hr = MAKE_TH_ERROR_CODE(E_OUTOFMEMORY);
}
if (FAILED(hr))
{
delete prhRegKey;
return(hr);
}
// Note: From this point, error returns don't mean return an
// error, but set the default and return
//
// Get Trace Location value
hr = prhRegKey->GetValueDword(
NULL,
SZ_REG_TRACE_LOC,
&_fTraceLoc,
REG_DWORD);
if (SUCCEEDED(hr))
{
_fTraceLoc = ValidateLoc(_fTraceLoc);
}
// Get Log Location value
hr = prhRegKey->GetValueDword(
NULL,
SZ_REG_LOG_LOC,
&_fLogLoc,
REG_DWORD);
if (SUCCEEDED(hr))
{
_fLogLoc = ValidateLoc(_fLogLoc);
}
// Get Trace Level
hr = prhRegKey->GetValueDword(
NULL,
SZ_REG_TRACE_LVL,
&_fTraceLvl,
REG_DWORD);
if (SUCCEEDED(hr))
{
_fTraceLvl = ValidateLvl(_fTraceLvl) | DH_LVL_ALWAYS | DH_LVL_ERROR;
}
// Get Mode
hr = prhRegKey->GetValueDword(
NULL,
SZ_REG_LABMODE,
&fLabMode,
REG_DWORD);
if (SUCCEEDED(hr) && fLabMode)
{
_fMode = DH_LABMODE;
}
hr = prhRegKey->GetValueDword(
NULL,
SZ_REG_BREAKMODE,
&fBreakMode,
REG_DWORD);
if (SUCCEEDED(hr) && fBreakMode)
{
_fMode |= DH_BREAKMODE;
}
hr = prhRegKey->GetValueDword(
NULL,
SZ_REG_VERBOSE,
&fVerbose,
REG_DWORD);
if (SUCCEEDED(hr) && fVerbose)
{
_fMode |= DH_VERBOSE;
}
_fMode = ValidateMode(_fMode);
// Clean up and exit
delete prhRegKey;
hr = S_OK;
return(hr);
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::WriteRegDbgInfo
//
// Synopsis: Write the current state of the CDebugHelp object to
// the registry.
//
// Arguments: [pszRegKey] - Registy key to write to.
//
// Returns: S_OK if values written, an error code if not.
//
// History: 21-Apr-96 Kennethm Created
//--------------------------------------------------------------------
HRESULT CDebugHelp::WriteRegDbgInfo(LPTSTR pszRegKey)
{
CRegistryHelp *prhRegKey = NULL;
HRESULT hr = E_FAIL;
// Open the registry key
prhRegKey = new(NullOnFail) CRegistryHelp(
#ifndef _MAC
HKEY_CURRENT_USER,
#else // _MAC
HKEY_CLASSES_ROOT,
#endif // _MAC
pszRegKey,
REG_OPTION_NON_VOLATILE,
KEY_WRITE,
&hr);
if (prhRegKey == NULL)
{
hr = MAKE_TH_ERROR_CODE(E_OUTOFMEMORY);
}
if (FAILED(hr))
{
delete prhRegKey;
return(hr);
}
// Write Trace Location value
hr = prhRegKey->SetValueDword(
NULL,
SZ_REG_TRACE_LOC,
_fTraceLoc,
REG_DWORD);
if (SUCCEEDED(hr))
{
// Write Log Location value
hr = prhRegKey->SetValueDword(
NULL,
SZ_REG_LOG_LOC,
_fLogLoc,
REG_DWORD);
}
if (SUCCEEDED(hr))
{
// Write Trace Level
hr = prhRegKey->SetValueDword(
NULL,
SZ_REG_TRACE_LVL,
_fTraceLvl,
REG_DWORD);
}
if (SUCCEEDED(hr))
{
// Write Lab Mode
hr = prhRegKey->SetValueDword(
NULL,
SZ_REG_LABMODE,
_fMode&DH_LABMODE ? TRUE : FALSE,
REG_DWORD);
}
if (SUCCEEDED(hr))
{
// Write Break Mode
hr = prhRegKey->SetValueDword(
NULL,
SZ_REG_BREAKMODE,
_fMode&DH_BREAKMODE ? TRUE : FALSE,
REG_DWORD);
}
if (SUCCEEDED(hr))
{
// Write Verbose
hr = prhRegKey->SetValueDword(
NULL,
SZ_REG_VERBOSE,
_fMode&DH_VERBOSE ? TRUE : FALSE,
REG_DWORD);
}
// Clean up and exit
delete prhRegKey;
return(hr);
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::CreateLog, public
//
// Synopsis: Creates a new log based on the parameters passed.
//
// Arguments: [argc] - Number of command line args
// [argv] - Command line args
//
// Returns: S_OK if log created successfully or none is specified,
// E_FAIL if not.
//
// History: 21-Nov-94 DeanE Created
//--------------------------------------------------------------------
HRESULT CDebugHelp::CreateLog(int argc, char **argv)
{
HRESULT hr = S_OK;
// Check for existing log
if ((_plog != NULL) && (_fCreatedLog == TRUE))
{
delete _plog;
}
// Create the new log
_plog = new(NullOnFail) Log(argc, argv, LOG_ANSI);
if (NULL == _plog)
{
hr = E_OUTOFMEMORY;
}
else
if (NO_ERROR != _plog->ConfirmCreation())
{
delete _plog;
hr = E_FAIL;
}
// Set _fCreatedLog flag to true so the log will get deleted during
// cleanup (otherwise the calling process must delete it).
//
if (SUCCEEDED(hr))
{
_fCreatedLog = TRUE;
}
return(hr);
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::CreateLog, public
//
// Synopsis: Creates a new log based on the parameters passed.
//
// Arguments: [paszCmdline] - Windows-style ANSI command line.
//
// Returns: S_OK if log created successfully or none is specified,
// E_FAIL if not.
//
// History: 21-Nov-94 DeanE Created
//--------------------------------------------------------------------
HRESULT CDebugHelp::CreateLog(LPSTR paszCmdline)
{
HRESULT hr = S_OK;
int argc = 0;
CHAR **argv = NULL;
// Convert pszCmdline to argc/argv parameters
hr = CmdlineToArgs(paszCmdline, &argc, &argv);
if (FAILED(hr))
{
return(hr);
}
// Check for existing log
if ((_plog != NULL) && (_fCreatedLog == TRUE))
{
delete _plog;
}
// Create the new log
_plog = new(NullOnFail) Log(argc, argv, LOG_ANSI);
if (NULL == _plog)
{
hr = E_OUTOFMEMORY;
}
else
if (NO_ERROR != _plog->ConfirmCreation())
{
delete _plog;
hr = E_FAIL;
}
// Set _fCreatedLog flag to true so the log will get deleted during
// cleanup (otherwise the calling process must delete it).
//
if (SUCCEEDED(hr))
{
_fCreatedLog = TRUE;
}
//
// Delete the argc/argv command line created by CmdlineToArgs
//
while (argc > 0)
{
--argc;
delete argv[argc];
}
delete argv;
return(hr);
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::SetLog, public
//
// Synopsis: Sets the log pointer to the one passed. This one should
// not be deleted. Deletes existing log is appropriate. If
// NULL is passed, the old log is deleted and the new log
// is set to NULL (none).
//
// Arguments: [plog] - Pointer to new log.
//
// Returns: S_OK if log set successfully, E_FAIL if not.
//
// History: 21-Nov-94 DeanE Created
//--------------------------------------------------------------------
HRESULT CDebugHelp::SetLog(Log *plog)
{
HRESULT hr = E_FAIL;
// Make sure new log pointer is valid
if ((NULL == plog) || (FALSE == IsBadReadPtr(plog, sizeof(Log *))))
{
// Free old log if we have one
if ((_plog != NULL) && (_fCreatedLog == TRUE))
{
delete _plog;
}
// Set new log; we should not delete the pointer
_plog = plog;
_fCreatedLog = FALSE;
hr = S_OK;
}
else
{
OutputDebugString(TEXT("Invalid log pointer"));
}
return(hr);
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::SetDebugInfo, public
//
// Synopsis: Sets debug information.
//
// Arguments: [fLogLoc] - New Log Location setting.
// [fTraceLoc] - New Trace Location setting.
// [fTraceLvl] - New Trace Level setting.
// [fMode] - New Mode setting.
//
// Returns: S_OK
//
// History: 21-Nov-94 DeanE Created
// 10-Apr-97 SCousens revamp fMode
//--------------------------------------------------------------------
HRESULT CDebugHelp::SetDebugInfo(
DWORD fLogLoc,
DWORD fTraceLoc,
DWORD fTraceLvl,
DWORD fMode)
{
// Validate New settings
fLogLoc = ValidateLoc(fLogLoc);
fTraceLoc = ValidateLoc(fTraceLoc);
fTraceLvl = ValidateLvl(fTraceLvl);
fMode = ValidateMode(fMode);
// Assign new values
if (fLogLoc != DH_LOC_SAME)
{
_fLogLoc = fLogLoc;
}
if (fTraceLoc != DH_LOC_SAME)
{
_fTraceLoc = fTraceLoc;
}
if (fTraceLvl != DH_LVL_SAME)
{
_fTraceLvl = DH_LVL_ALWAYS|DH_LVL_ERROR|fTraceLvl;
}
// Set mode bits, one by one
if ((fMode & DH_LABMODE_SET) ||
(fMode & DH_BREAKMODE_SET) ||
(fMode & DH_VERBOSE_SET))
{
DWORD fNewMode;
fNewMode = fMode & DH_LABMODE_SET ?
fMode & DH_LABMODE :
_fMode & DH_LABMODE;
fNewMode |= fMode & DH_BREAKMODE_SET ?
fMode & DH_BREAKMODE :
_fMode & DH_BREAKMODE;
fNewMode |= fMode & DH_VERBOSE_SET ?
fMode & DH_VERBOSE :
_fMode & DH_VERBOSE;
// mask off the SET bits
_fMode = fNewMode &
~(DH_LABMODE_SET |
DH_BREAKMODE_SET |
DH_VERBOSE_SET) ;
}
// Reset the warning flag (in OutputMsg)
_fSpyWarning = FALSE;
return(S_OK);
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::SetPopupWindow, public
//
// Synopsis: Associates the window handle passed with the Assert
// popups that can occur if Lab Mode is set FALSE. Simply
// replaces any existing window handle - does not close
// it, etc.
//
// Arguments: [hwnd] - New window handle
//
// Returns: S_OK if set successfully, E_FAIL if not.
//
// History: 1-Dec-94 DeanE Created
//--------------------------------------------------------------------
HRESULT CDebugHelp::SetPopupWindow(HWND hwnd)
{
_hwndAssert = hwnd;
return(S_OK);
}
//+-------------------------------------------------------------------
// Member: CDebughelp::SetSpyWindowClass, public
//
//
// Synopsis: Set the window class that all spy window output will
// go to.
//
// Arguments: [pszSpyWindowClass] -- pointer to class name
//
// Returns: S_OK
//
// Algorithm: If the old spy class is not equal to the default one,
// free up the buffer we allocated. Then create a new
// buffer and copy the new class string into it.
//
// History: 09-Aug-95 MikeW Created
//
// Notes: If an error is returned the old class is preserved.
//--------------------------------------------------------------------
HRESULT CDebugHelp::SetSpyWindowClass(const LPTSTR pszSpyWindowClass)
{
HRESULT hr = S_OK;
LPTSTR pszTemp;
if (_pszSpyWindowClass != SZ_DEFAULT_SPY_WINDOW_CLASS)
{
delete [] _pszSpyWindowClass;
}
pszTemp = new TCHAR[_tcslen(pszSpyWindowClass) + 1];
if (NULL == pszTemp)
{
hr = E_OUTOFMEMORY;
}
else
{
_pszSpyWindowClass = pszTemp;
_tcscpy(_pszSpyWindowClass, pszSpyWindowClass);
}
return S_OK;
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::TraceMsg, public
//
// Synopsis: Outputs the debug string to the current location setting
// if any set bit in the level passed match set bits in the
// global level.
//
// Arguments: [fLvl] - Trace level.
// [pszFmt] - Trace message format string.
// [...] - Arguments for format string.
//
// Returns: Nothing.
//
// History: 20-Oct-93 DeanE Created
// 10-Apr-97 SCousens Spiff up output string on error
//--------------------------------------------------------------------
void CDebugHelp::TraceMsg(DWORD fLvl, LPTSTR pszFmt, ...)
{
TCHAR szBuffer[CCH_MAX_DBG_CHARS];
TCHAR szDebug[CCH_MAX_DBG_CHARS +
CCH_MAX_DBGPREFIX +
CCH_MAX_INDENTPRINT + 6 ];
TCHAR szSpaces[CCH_MAX_INDENTPRINT];
va_list varArgs;
// If the level has DH_LVL_ENTRY in it indent by one
//
if (fLvl & DH_LVL_ENTRY)
{
_cIndentLevel++;
}
// If all of the bits match, then we will output the string to the
// current location(s)
//
if ((fLvl & _fTraceLvl) == fLvl)
{
// Print the caller's string to a buffer
va_start(varArgs, pszFmt);
_vsntprintf(szBuffer, CCH_MAX_DBG_CHARS, pszFmt, varArgs);
szBuffer[CCH_MAX_DBG_CHARS-1] = chNull;
va_end(varArgs);
// Add correct number of space for indentation
lstrcpy(szSpaces, TEXT(" "));
if (_cIndentLevel < CCH_MAX_INDENTPRINT)
{
szSpaces[_cIndentLevel]=TEXT('\0');
}
// Now prepend it with the debug prefix
_sntprintf(szDebug,
CCH_MAX_DBG_CHARS,
TEXT("%s: %c %s%s%s"),
_szDbgPrefix,
DH_LVL_ERROR & fLvl ? chTraceErr : chTrace,
szSpaces,
DH_LVL_ERROR & fLvl ? szError : szNull,
szBuffer);
szDebug[CCH_MAX_DBG_CHARS-1] = chNull;
// Now, spit the thing out to the proper places
OutputMsg(_fTraceLoc, szDebug);
}
// If the level has DH_LVL_EXIT in it unindent by one
//
if (fLvl & DH_LVL_EXIT)
{
_cIndentLevel--;
}
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::ReportResult, public
//
// Synopsis: Outputs the test variation and result to the location(s)
// currently specified.
//
// Arguments: [usResult] - Result of the test
// [pszFmt] - Format of the log message
// [...] - Parameters for message
//
// Returns: Nothing.
//
// History: 21-Nov-94 DeanE Created
//--------------------------------------------------------------------
void CDebugHelp::ReportResult(USHORT usResult, LPTSTR pszFmt, ...)
{
HRESULT hr = E_FAIL;
TCHAR szFmtBuffer[CCH_MAX_LOG_CHARS];
TCHAR szLogBuffer[CCH_MAX_LOG_CHARS];
va_list varArgs;
// format variable arg list into a buffer.
va_start(varArgs, pszFmt);
_vsntprintf(szFmtBuffer, CCH_MAX_LOG_CHARS, pszFmt, varArgs);
szFmtBuffer[CCH_MAX_LOG_CHARS-1] = chNull;
va_end(varArgs);
// Set up log buffer. Truncate any extra chars.
_sntprintf(szLogBuffer,
CCH_MAX_LOG_CHARS,
TEXT("%s: %s"),
GetResultText(usResult),
szFmtBuffer);
szLogBuffer[CCH_MAX_LOG_CHARS-1] = chNull;
SetStats(usResult);
// Send it out
OutputMsg(_fLogLoc, szLogBuffer);
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::ReportStats, public
//
// Synopsis: Outputs statistics about test variations run so far,
// such as #tests run, #passed, #failed, etc to the Log
// Location (_fLogLoc).
//
// Arguments: None.
//
// Returns: Nothing.
//
// History: 21-Nov-94 DeanE Created
//--------------------------------------------------------------------
void CDebugHelp::ReportStats()
{
TCHAR szBuffer[CCH_MAX_LOG_CHARS];
_sntprintf(szBuffer, CCH_MAX_LOG_CHARS,
TEXT("Summary--> Passed: %lu ; Failed: %lu ; Aborted: %lu"),
_cPass,
_cFail,
_cAbort);
szBuffer[CCH_MAX_LOG_CHARS-1] = chNull;
OutputMsg(_fLogLoc, szBuffer);
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::LabAssertEx, public
//
// Synopsis: Produces an assert message to the current debug
// location(s) or to a dialog box, if running in non-Lab
// mode.
//
// Arguments: [szFile] - File assert occurred in.
// [nLine] - Line assert occurred.
// [nszMsg] - Assert message.
//
// Returns: Nothing.
//
// History: 20-Oct-93 DeanE Created
//--------------------------------------------------------------------
void CDebugHelp::LabAssertEx(LPCTSTR szFile, int nLine, LPCTSTR szMsg)
{
TCHAR szBuffer[CCH_MAX_ASSERT_CHARS];
int nAnswer;
_sntprintf(szBuffer,
CCH_MAX_ASSERT_CHARS,
TEXT("Assert!!! File: %s, Line: %d, %s\n"),
szFile,
nLine,
szMsg);
szBuffer[CCH_MAX_ASSERT_CHARS-1] = chNull;
// always spew
OutputMsg(_fTraceLoc, szBuffer);
// if labmode, popup
if (FALSE == (_fMode & DH_LABMODE))
{
nAnswer = MessageBox(
_hwndAssert,
szBuffer,
TEXT("CT OLE Assert"),
MB_ICONEXCLAMATION | MB_OKCANCEL);
if (IDCANCEL==nAnswer)
{
DebugBreak();
}
}
// if break, break
else if (FALSE != (_fMode & DH_BREAKMODE))
{
DebugBreak();
}
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::CheckResult, public
//
// Synopsis: Compares the hr passed in with expected hr passed in
//
// Arguments: [hrCheck] - Result to check.
// [hrExpected] - Result expected.
// [pszFuncName] - Name of the current function
// [pszMsg] - Debug message if result not in list passed.
// [nLine] - __LINE__ macro
// [pszFile] - __FILE__ macro
//
// Returns: Nothing.
//
// History: 12-Aug-94 KennethM Created
// 1-Dec-94 DeanE Incorporated into CDebugHelp class
// 12-Apr-95 KennethM Only checks against S_OK
// 10-Apr-97 SCousens Check against errors also
//--------------------------------------------------------------------
HRESULT CDebugHelp::CheckResult (HRESULT hrCheck,
HRESULT hrExpected,
LPTSTR pszFuncName,
LPTSTR pszMsg,
int nLine,
LPTSTR pszFile)
{
TCHAR szAssertBuf[CCH_MAX_ASSERT_CHARS];
TCHAR szAssertTitle[CCH_MAX_ASSERT_CHARS];
TCHAR szMsgBuffer[CCH_MAX_ASSERT_CHARS];
DWORD cchMsgBuffer = 0;
int nAnswer;
HRESULT hr = S_OK;
// If _dwExpectedError is set, then someone up the call chain
// wants us to ignore that error code, even if our direct caller
// does not. If the incoming error code matches _dwExpectedError,
// then ignore it and return.
if ( ( _hrExpectedError != S_OK ) && ( hrCheck == _hrExpectedError ) )
{
return S_OK;
}
// figure out if we have a problem
if (hrCheck != hrExpected)
{
if (FAILED(hrCheck))
{
hr = hrCheck;
}
else
{
hr = E_FAIL;
}
}
// No problem, prepare to bail
if (S_OK == hr)
{
// if we are verbose, call tracemsg
if (FALSE != (DH_VERBOSE & _fMode))
{
TraceMsg(DH_LVL_ALWAYS,
S_OK == hrExpected ? // different output if HRCHECK
TEXT("%s; %s; ok") :
TEXT("%s; %s; hr=%#lx; ok"),
pszFuncName,
pszMsg,
hrCheck);
}
return hr;
}
// Get the text for the HRESULT from the system
cchMsgBuffer = FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
hrCheck,
GetSystemDefaultLangID(),
szMsgBuffer,
CCH_MAX_ASSERT_CHARS,
NULL);
szMsgBuffer[CCH_MAX_ASSERT_CHARS-1] = chNull;
if (0 == cchMsgBuffer)
{
_sntprintf(
szMsgBuffer,
CCH_MAX_ASSERT_CHARS,
TEXT("Error 0x%08x"),
hrCheck);
}
else // zap any \r\n from the FormatMessage
{
while ('\r' == szMsgBuffer[cchMsgBuffer-1] ||
'\n' == szMsgBuffer[cchMsgBuffer-1])
{
szMsgBuffer[--cchMsgBuffer] = chNull;
}
}
// Output to Trace Location
TraceMsg(DH_LVL_ERROR,
S_OK == hrExpected ? // different output if HRCHECK
TEXT("%s; %s; hr=%lx; %s") :
TEXT("%s; %s; hr=%lx;"),
pszFuncName,
pszMsg,
hr,
szMsgBuffer);
// If we are comparing against failure, show what we expected and got.
if (S_OK != hrExpected)
{
TraceMsg(DH_LVL_ALWAYS,
TEXT("+ hr Expected:%#lx; Got:%#lx; %s"),
hrExpected,
hrCheck,
szMsgBuffer);
}
TraceMsg(DH_LVL_ALWAYS,
TEXT("+ File:%s; Line:%d"),
pszFile,
nLine);
// labmode - display an error popup
if (FALSE == (_fMode & DH_LABMODE))
{
_sntprintf(szAssertBuf,
CCH_MAX_ASSERT_CHARS,
TEXT("%s : hr=%#lx : Expected %#lx\n%s\n"),
pszMsg,
hrCheck,
hrExpected,
szMsgBuffer);
szAssertBuf[CCH_MAX_ASSERT_CHARS-1] = chNull;
_sntprintf(szAssertTitle,
CCH_MAX_ASSERT_CHARS,
TEXT("CT OLE - %s Error"),
_szDbgPrefix);
szAssertTitle[CCH_MAX_ASSERT_CHARS-1] = chNull;
// Do we want to debug this?
nAnswer = MessageBox(
_hwndAssert,
szAssertBuf,
szAssertTitle,
MB_ICONSTOP | MB_OKCANCEL);
// yes we do?
if (IDCANCEL==nAnswer)
{
DebugBreak();
}
}
// break mode, break into the debugger
else if (FALSE != (_fMode & DH_BREAKMODE))
{
DebugBreak();
}
return hr;
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::SetExpectedError, public
//
// Synopsis: Disables error logging for the specified error code.
//
// Arguments: [hrExpectedError] - Error code to disable. Pass S_OK
// for no expected errors.
//
// Returns: Nothing.
//
// History: 16-Sep-97 BWill Created
//
// Notes: -- Use this call to temporarily disable error logging
// in client code.
// -- Call this function with S_OK to enable all checks.
// -- See also DH_EXPECTEDERROR/DH_NOEXPECTEDERROR in
// cdbghelp.hxx.
//--------------------------------------------------------------------
void CDebugHelp::SetExpectedError( HRESULT hrExpectedError )
{
_hrExpectedError = hrExpectedError;
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::ValidateLoc, private
//
// Synopsis: Checks the location flag passed to insure it is a legal
// value.
//
// Arguments: [fLoc] - Location flag to check.
//
// Returns: Legal version of what we were to check.
//
// History: 21-Nov-94 DeanE Created
// 10-Apr-97 SCousens Return legal value
//--------------------------------------------------------------------
DWORD CDebugHelp::ValidateLoc(DWORD fLoc)
{
// Get what we can out of supplied location
return (DH_LOC_VALID & fLoc);
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::ValidateLvl, private
//
// Synopsis: Checks the Trace Level flag passed to insure it is a
// legal value.
//
// Arguments: [fLvl] - Trace Level to check.
//
// Returns: Legal version of what we were to check.
//
// History: 21-Nov-94 DeanE Created
// 10-Apr-97 SCousens Return legal value
//--------------------------------------------------------------------
DWORD CDebugHelp::ValidateLvl(DWORD fLvl)
{
// Make sure a valid setting is passed
return (~DH_LVL_INVMASK & fLvl);
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::ValidateMode, private
//
// Synopsis: Checks the Lab Mode flag passed to insure it is a
// legal value.
//
// Arguments: [fMode] - Flag to check.
//
// Returns: Legal version of what we were to check.
//
// History: 21-Nov-94 DeanE Created
// 10-Apr-97 SCousens Return legal value
//--------------------------------------------------------------------
DWORD CDebugHelp::ValidateMode(DWORD fMode)
{
return (fMode & (~DH_INVMODE));
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::SetStats, private
//
// Synopsis: Sets stats based on result
//
// Arguments: [usResult] - Result to add.
//
// Returns: nothing.
//
// History: 20-Oct-93 DeanE Created
//--------------------------------------------------------------------
VOID CDebugHelp::SetStats(USHORT usResult)
{
switch (usResult)
{
case LOG_PASS:
_cPass++;
break;
case LOG_FAIL:
_cFail++;
break;
case LOG_ABORT:
_cAbort++;
break;
default:
// do nothing.
break;
}
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::GetResultText, private
//
// Synopsis: Determines the correct text to printf for the result code
// passed. Result code corresponds to LogServer result codes.
//
// Arguments: [usResult] - Result to look up.
//
// Returns: Pointer to output string corresponding to the result
// code passed (ie "PASSED" for LOG_PASS).
//
// History: 21-Nov-94 DeanE Created
//--------------------------------------------------------------------
LPCTSTR CDebugHelp::GetResultText(USHORT usResult)
{
LPCTSTR szResult = NULL;
TCHAR szAssert[CCH_MAX_DBG_CHARS];
switch (usResult)
{
case LOG_PASS:
szResult = szPass;
break;
case LOG_FAIL:
szResult = szFail;
break;
case LOG_ABORT:
szResult = szAbort;
break;
case LOG_WARN:
szResult = szWarn;
break;
case LOG_INFO:
szResult = szInfo;
break;
default:
szResult = szInvalid;
_sntprintf(szAssert,
CCH_MAX_DBG_CHARS,
TEXT("Invalid Test Result=%ld"),
usResult);
szAssert[CCH_MAX_DBG_CHARS-1] = chNull;
LabAssertEx(TEXT(__FILE__), __LINE__, szAssert);
break;
}
return(szResult);
}
//+-------------------------------------------------------------------
// Member: CDebugHelp::OutputMsg, private
//
// Synopsis: Outputs the buffer to the locations specified.
// Location, log, and buffer are all assumed to be valid,
// so no error checking is done.
//
// Arguments: [fLoc] - Location(s) to output buffer to.
// [pszBuffer] - Buffer to output.
//
// Returns: Nothing.
//
// History: 21-Nov-94 DeanE Created
// 08-Mar-95 MikeW Added DH_LOC_SPYWIN stuff
//--------------------------------------------------------------------
void CDebugHelp::OutputMsg(DWORD fLoc, LPTSTR pszBuffer)
{
CHAR szLogBuf[CCH_MAX_LOG_CHARS];
if (fLoc & DH_LOC_TERM)
{
OutputDebugString(pszBuffer);
OutputDebugString(szNewLine);
}
if (fLoc & DH_LOC_STDOUT)
{
_tprintf(TEXT("%s\n"), pszBuffer);
}
if (fLoc & DH_LOC_LOG)
{
if (FALSE == IsBadReadPtr(_plog, sizeof(Log *)))
{
// Buffer must be ANSI regardless of platform
#ifdef UNICODE
_snprintf(szLogBuf, CCH_MAX_LOG_CHARS, "%ls", pszBuffer);
#else
_snprintf(szLogBuf, CCH_MAX_LOG_CHARS, "%s", pszBuffer);
#endif
szLogBuf[CCH_MAX_LOG_CHARS-1] = chNull;
_plog->WriteData(szLogBuf);
}
else
{
// Trying to write to log that doesn't exist!
OutputDebugString(TEXT("CDebugHelp: Unable to write to Log File!\n"));
}
}
if (fLoc & DH_LOC_SPYWIN)
{
HWND hWndSpy;
hWndSpy = FindWindow(_pszSpyWindowClass, NULL);
if (NULL != hWndSpy)
{
SendMessage(hWndSpy, LB_ADDSTRING, 0, (LPARAM) pszBuffer);
SendMessage(hWndSpy, LB_ADDSTRING, 0, (LPARAM) szCRLF);
}
else if (FALSE == _fSpyWarning)
{
//only spew this once, till someone changes the settings.
_fSpyWarning = TRUE;
// Unable to find SpyWindow
OutputDebugString(TEXT("CDebugHelp: Spy Window not found!\n"));
}
}
}
//+-------------------------------------------------------------------------
//
// Function: InitializeDebugObject
//
// Synopsis: Initialize the debug helper (trace levels, etc.)
//
// Arguments: (none)
//
// Returns: S_OK if all went well
// S_FALSE if we encountered /? and spewed and bailed.
//
// History: 29-Apr-05 kennethm Created
// 09-Aug-95 MikeW Override defaults w/ command line
// 10-Apr-97 SCousens move into CDebugHelp
//--------------------------------------------------------------------------
HRESULT CDebugHelp::Initialize()
{
HRESULT hr = S_OK;
int nRet;
LPTSTR pszSpyClass = NULL;
CUlongCmdlineObj cmdTraceLvl (OLESTR("tracelvl"), OLESTR("Trace levels"));
CUlongCmdlineObj cmdTraceLoc (OLESTR("traceloc"), OLESTR("Trace output"));
CUlongCmdlineObj cmdLogLoc (OLESTR("logloc"), OLESTR("Log output"));
CBoolCmdlineObj cmdDebugUI (OLESTR("DebugUI"), OLESTR("Popup debug dialog"), OLESTR("FALSE"));
CBoolCmdlineObj cmdLabMode (OLESTR("labmode"), OLESTR("Popup on error"), OLESTR("FALSE"));
CBoolCmdlineObj cmdBreak (OLESTR("breakmode"), OLESTR("Break on error"), OLESTR("FALSE"));
CBoolCmdlineObj cmdVerbose (OLESTR("verbose"), OLESTR("Trace HRCHECK for a noisy log"), OLESTR("FALSE"));
CBaseCmdlineObj cmdSpyClass (OLESTR("spyclass"), OLESTR("Classname for Spy Window"));
CCmdline cmdlineArgs;
CBaseCmdlineObj *aPossCmdline[] = {
&cmdTraceLvl,
&cmdTraceLoc,
&cmdLogLoc,
&cmdDebugUI,
&cmdLabMode,
&cmdVerbose,
&cmdBreak,
&cmdSpyClass };
//
// Read the debug options from the registry
//
hr = GetRegDbgInfo (DEFAULT_REG_LOC);
//
// Now that we have the defaults from the registry read the command
// line to over-ride them.
//
if (hr == S_OK)
{
//
// Make sure there were no errors starting up the cmd line objects
//
nRet = cmdlineArgs.QueryError();
if (nRet != CMDLINE_NO_ERROR)
{
hr = E_FAIL;
TraceMsg (DH_LVL_ERROR, TEXT("cmdlineArgs.QueryError"));
}
}
if (hr == S_OK)
{
//
// Now parse the command line
//
nRet = cmdlineArgs.Parse(aPossCmdline,
sizeof(aPossCmdline)/sizeof(CBaseCmdlineObj *),
FALSE);
if (nRet != CMDLINE_NO_ERROR)
{
hr = E_FAIL;
TraceMsg (DH_LVL_ERROR, TEXT("cmdlineArgs.Parse"));
}
}
if (hr == S_OK)
{
DWORD dwLogLoc = DH_LOC_SAME;
DWORD dwTraceLoc = DH_LOC_SAME;
DWORD dwTraceLvl = DH_LVL_SAME;
DWORD dwMode = 0;
if (cmdLabMode.IsFound())
{
dwMode = *cmdLabMode.GetValue () ? DH_LABMODE_ON : DH_LABMODE_OFF;
}
if (cmdVerbose.IsFound())
{
dwMode |= *cmdVerbose.GetValue () ? DH_VERBOSE_ON : DH_VERBOSE_OFF;
}
if (cmdBreak.IsFound())
{
dwMode |= *cmdBreak.GetValue () ? DH_BREAKMODE_ON : DH_BREAKMODE_OFF;
}
if (cmdTraceLvl.IsFound())
{
dwTraceLvl = *cmdTraceLvl.GetValue();
}
if (cmdTraceLoc.IsFound())
{
dwTraceLoc = *cmdTraceLoc.GetValue();
}
if (cmdLogLoc.IsFound())
{
dwLogLoc = *cmdLogLoc.GetValue();
}
SetDebugInfo( \
dwLogLoc, \
dwTraceLoc, \
dwTraceLvl, \
dwMode);
if (cmdSpyClass.IsFound())
{
OleStringToTString(cmdSpyClass.GetValue(), &pszSpyClass);
if (NULL != pszSpyClass)
{
SetSpyWindowClass (pszSpyClass);
delete [] pszSpyClass;
}
}
if (cmdDebugUI.IsFound())
{
HRESULT hr2 = OptionsDialog (GetModuleHandle (NULL), GetActiveWindow ());
if (FAILED(hr2))
{
TraceMsg (DH_LVL_ERROR,
TEXT("DialogBoxParam failed; hr=%#x. (Is dlg in res?)"),
hr2);
}
}
}
return hr;
}
//+-------------------------------------------------------------------------
//
// Member: CEntryExitTrace::CEntryExitTrace
//
// Synopsis: Displays a debug line saying the current function is being
// entered. Saves the information so it can be displayed
// when the destructor is called.
//
// Arguments: [pDebugObject] -- The parent debug log object
// [plExitOutput] -- The 32 value to display on exit (can be
// NULL)
// [fLvl] -- The trace level of this function
// [pszFuncName] -- The name of this function
//
// Returns:
//
// History: 4-10-95 kennethm Created
//
// Notes:
//
//--------------------------------------------------------------------------
CEntryExitTrace::CEntryExitTrace(
CDebugHelp *pDebugObject,
PLONG plExitOutput,
DWORD fLvl,
LPTSTR pszFuncName)
{
// Save the paramters
_pDebugObject = pDebugObject;
_plExitOutput = plExitOutput;
_pszFuncName = pszFuncName;
_fLvl = fLvl;
// Display the trace information
_pDebugObject->TraceMsg(
(_fLvl | DH_LVL_ENTRY),
TEXT("%s _IN"),
_pszFuncName);
}
//+-------------------------------------------------------------------------
//
// Member: CEntryExitTrace::~CEntryExitTrace
//
// Synopsis: Destructor. Display a trace output line
//
// Arguments: (none)
//
// Returns:
//
// History: 4-17-95 kennethm Created
//
// Notes:
//
//--------------------------------------------------------------------------
CEntryExitTrace::~CEntryExitTrace(void)
{
// Display the trace information
if (_plExitOutput != NULL)
{
_pDebugObject->TraceMsg(
(_fLvl | DH_LVL_EXIT),
TEXT("%s _OUT:%#08lx"),
_pszFuncName,
*_plExitOutput);
}
else
{
_pDebugObject->TraceMsg(
(_fLvl | DH_LVL_EXIT),
TEXT("%s _OUT"),
_pszFuncName);
}
}