//+------------------------------------------------------------------- // 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 #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); } }