|
|
/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
vs_debug.hxx
Abstract:
Various defines for general usage
Author:
Adi Oltean [aoltean] 07/09/1999
Revision History:
Name Date Comments aoltean 07/09/1999 Created aoltean 08/11/1999 Adding throw specification aoltean 09/03/1999 Adding DuplicateXXX functions aoltean 09/09/1999 dss -> vss aoltean 09/20/1999 Adding ThrowIf, Err, Msg, MsgNoCR, etc.
--*/
#ifndef __VSS_DEBUG_HXX__
#define __VSS_DEBUG_HXX__
#if _MSC_VER > 1000
#pragma once
#endif
////////////////////////////////////////////////////////////////////////
// Standard foo for file name aliasing. This code block must be after
// all includes of VSS header files.
//
#ifdef VSS_FILE_ALIAS
#undef VSS_FILE_ALIAS
#endif
#define VSS_FILE_ALIAS "INCDEBGH"
//
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// Global constants
//
// @const x_nVssMsgBufferSize | Maximum buffer size in Tracer operations
const x_nVssMsgBufferSize = 512; const x_nVssNumericBufferSize = 30; const x_nVssGuidBufferSize = 60; const x_nVssMaxDebugArgs = 10; const WCHAR x_wszEventLogVssSourceName[] = L"VSS";
/////////////////////////////////////////////////////////////////////////////
// Declared classes
//
//
// @class CVssFunctionTracer | This structure is used for tracing, debugging, treating HRESULTS
// in a C++ function, especially a COM server method.
//
struct CVssDebugInfo {
// Constructors& destructors
private: CVssDebugInfo();
public: CVssDebugInfo( LPCWSTR wszFile, LPCSTR szFileAlias, // Five character alias, see file drivers\volsnap\filealias.xls for mappings
ULONG ulLine, DWORD dwLevel, DWORD dwIndent = 0 );
CVssDebugInfo( const CVssDebugInfo& original );
~CVssDebugInfo() ;
// Operations
public:
// This is used to add an numeric-type argument
CVssDebugInfo operator << ( IN INT nArgument );
// This is used to add an numeric-type argument.
// It will be represented in hexadecimal format.
CVssDebugInfo operator << ( IN HRESULT hrArgument );
// This is used to add an numeric-type argument.
// It will be represented in hexadecimal format.
CVssDebugInfo operator << ( IN LONGLONG llArgument );
// This is used to add an numeric-type argument.
CVssDebugInfo operator << ( IN GUID hrArgument );
// This is used to add an string-type argument
CVssDebugInfo operator << ( IN LPCWSTR wszArgument );
public: LPCWSTR m_wszFile; LPCSTR m_szFileAlias; ULONG m_ulLine; DWORD m_dwLevel; DWORD m_dwIndent;
// Optional argument list
LPWSTR m_ppwszStrings[x_nVssMaxDebugArgs]; WORD m_wNumStrings; bool m_bOutOfMemoryOccured; mutable bool m_bStringsOwnership; };
#define VSSDBG_COORD CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_COORD, 0)
#define VSSDBG_SWPRV CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_SWPRV, 0)
#define VSSDBG_TESTPRV CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_TESTPRV, 0)
#define VSSDBG_VSSTEST CVssDebugInfo(__WFILE__, "TST--", __LINE__, DEBUG_TRACE_VSS_TEST, 0)
#define VSSDBG_VSSDEMO CVssDebugInfo(__WFILE__, "TSD--", __LINE__, DEBUG_TRACE_VSS_DEMO, 0)
#define VSSDBG_EXCEPT CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_CATCH_EXCEPTIONS, 0)
#define VSSDBG_GEN CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_GEN, 0)
#define VSSDBG_XML CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_XML, 0)
#define VSSDBG_WRITER CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_WRITER, 0)
#define VSSDBG_IOCTL CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_IOCTL, 0)
#define VSSDBG_SHIM CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_SHIM, 0)
#define VSSDBG_SQLLIB CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_SQLLIB, 0)
#define VSSDBG_VSSADMIN CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_VSS_ADMIN, 0)
#define VSSDBG_STSWRITER CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_STSWRITER, 0)
#define VSSDBG_SQLWRITER CVssDebugInfo(__WFILE__, VSS_FILE_ALIAS, __LINE__, DEBUG_TRACE_SQLWRITER, 0)
#define VSS_STANDARD_CATCH(FT) \
catch( HRESULT CaughtHr ) { \ FT.hr = CaughtHr; \ FT.Trace( VSSDBG_EXCEPT, L"HRESULT EXCEPTION CAUGHT: hr: 0x%x", FT.hr ); \ } \ catch( ... ) { \ FT.hr = E_UNEXPECTED; \ FT.Trace( VSSDBG_EXCEPT, L"UNKNOWN EXCEPTION CAUGHT, returning hr: 0x%x", FT.hr ); \ }
//
// @class CVssFunctionTracer | This class is used for tracing, debugging, treating HRESULTS
// in a C++ function, especially a COM server method.
//
class CVssFunctionTracer { class CVssOutputBuffer { private: // Must be under 512 in order to make
// the lookaside allocation algortihm work efficiently!
enum { nVssMsgBufferSize = 400 }; WCHAR* m_pwszBuffer;
public: CVssOutputBuffer() { m_pwszBuffer = new WCHAR[nVssMsgBufferSize + 1]; } ~CVssOutputBuffer() { delete m_pwszBuffer; }
INT GetBufferSize() { return nVssMsgBufferSize; }; WCHAR * GetBuffer() { return m_pwszBuffer; }; bool IsBufferValid() { return (m_pwszBuffer != NULL); }; };
// Constructors and destructors
private: CVssFunctionTracer(); CVssFunctionTracer(const CVssFunctionTracer&);
public: CVssFunctionTracer( IN CVssDebugInfo dbgInfo, IN const WCHAR* pwszFunctionName );
~CVssFunctionTracer();
// Attributes
public: _declspec(property(get=GetHr,put=SetHr)) HRESULT hr;
// Implementation
inline HRESULT GetHr() { return m_hr; }; inline void SetHr( HRESULT hr ) { m_hr = hr; };
inline bool HrFailed() { return FAILED(m_hr); }; inline bool HrSucceeded() { return SUCCEEDED(m_hr); };
// Operations
public:
//
// Traces.
//
void inline __cdecl Trace( CVssDebugInfo dbgInfo, const WCHAR* pwszMsgFormat, ...);
void inline TraceBuffer( CVssDebugInfo dbgInfo, DWORD dwBufferSize, PBYTE pbBuffer );
void inline __cdecl Throw( CVssDebugInfo dbgInfo, // Caller debugging info
HRESULT hrToBeThrown, // The new HR to be thrown
const WCHAR* pwszMsgFormat, // Message that will be displayed if throw needed
... // Additional arguments
) throw(HRESULT);
void inline __cdecl ThrowIf( BOOL bThrowNeeded, // Throw an HR if and only if bThrowNeeded is TRUE.
CVssDebugInfo dbgInfo, // Caller debugging info
HRESULT hrToBeThrown, // The new HR to be thrown
const WCHAR* pwszMsgFormat, // Message that will be displayed if throw needed
... // Additional arguments
) throw(HRESULT);
//
// Messages displayed at the console (only for test and demo purpose).
//
void __cdecl Msg( const WCHAR* pwszMsgFormat, // Message that will be displayed
... );
void __cdecl MsgNoCR( const WCHAR* pwszMsgFormat, // Message that will be displayed
... );
void __cdecl Err( CVssDebugInfo dbgInfo, // Caller debugging info
HRESULT hrToBeThrown, // The new HR to be thrown
const WCHAR* pwszMsgFormat, // Error message that will be displayed
... ); //
// Informative message boxes (only for test and demo purpose).
//
void __cdecl MsgBox( const WCHAR* pwszMsgTitle, // Title of the Message box
const WCHAR* pwszMsgFormat, // Message that will be displayed
... );
void __cdecl ErrBox( CVssDebugInfo dbgInfo, // Caller debugging info
HRESULT hrToBeThrown, // The new HR to be thrown
const WCHAR* pwszMsgFormat, // Error message that will be displayed
... );
// Trace the corresponding COM error
void TraceComError();
// Log the attempt of starting VSS
void LogVssStartupAttempt();
// Put a new entry in the Error Log.
void __cdecl LogError( IN DWORD dwEventID, // The ID of the event
IN CVssDebugInfo dbgInfo, // Caller debugging info
IN WORD wType = EVENTLOG_ERROR_TYPE // Entry type
);
void __cdecl TranslateError( IN CVssDebugInfo dbgInfo, IN HRESULT hr, IN LPCWSTR wszRoutine );
void inline __cdecl CheckForError( IN CVssDebugInfo dbgInfo, IN LPCWSTR wszRoutine ) { if (HrFailed()) TranslateError(dbgInfo, m_hr, wszRoutine); }
// check for an error on an internal call. Do not log E_UNEXPECTED
// errors
void inline __cdecl CheckForErrorInternal( IN CVssDebugInfo dbgInfo, IN LPCWSTR wszRoutine ) { if (HrFailed()) { if (m_hr == E_UNEXPECTED) throw E_UNEXPECTED; else TranslateError(dbgInfo, m_hr, wszRoutine); } }
void __cdecl TranslateGenericError ( IN CVssDebugInfo dbgInfo, // Caller debugging info
IN HRESULT hr, IN LPCWSTR wszErrorTextFormat, IN ... );
void __cdecl LogGenericWarning ( IN CVssDebugInfo dbgInfo, // Caller debugging info
IN LPCWSTR wszErrorTextFormat, IN ... );
BOOL IsDuringSetup() { return g_cDbgTrace.IsDuringSetup(); };
BOOL IsInSoftwareProvider() { return m_dwLevel == DEBUG_TRACE_VSS_SWPRV; };
//
// Calls CoCreate in a cycle and performs special logging
//
void CoCreateInstanceWithLog( IN CVssDebugInfo dbgInfo, // Caller debugging info
IN CLSID ServerClassID, IN LPCWSTR ServerName, IN DWORD dwContext, IN IID InterfaceID, OUT IUnknown ** ppUnknown );
// Attributes
public: HRESULT m_hr;
// Internal Data
private: const WCHAR* m_pwszFunctionName; LPCSTR m_szFileAlias; ULONG m_ulLine; DWORD m_dwLevel; // At entry time
DWORD m_dwIndent; // At entry time
};
///////////////////////////////////////////////////////////////////////////////////////
// Class implementations
//
///////////////////////////////////////////////////////////////////////////////////////
// CVssDebugInfo
inline CVssDebugInfo::CVssDebugInfo( LPCWSTR wszFile, LPCSTR szFileAlias, ULONG ulLine, DWORD dwLevel, DWORD dwIndent ): m_wszFile(wszFile), m_szFileAlias(szFileAlias), m_ulLine(ulLine), m_dwIndent(dwIndent), m_dwLevel(dwLevel), m_wNumStrings(0), m_bOutOfMemoryOccured(false), m_bStringsOwnership(true) { for (WORD wIndex = 0; wIndex < x_nVssMaxDebugArgs; wIndex++) m_ppwszStrings[wIndex] = NULL; }
inline CVssDebugInfo::CVssDebugInfo( const CVssDebugInfo& original ) { m_wszFile = original.m_wszFile; // We suppose that this is a constant string.
m_szFileAlias = original.m_szFileAlias; // We suppose that this is a constant string.
m_ulLine = original.m_ulLine; m_dwIndent = original.m_dwIndent; m_dwLevel = original.m_dwLevel; m_wNumStrings = original.m_wNumStrings; m_bOutOfMemoryOccured = original.m_bOutOfMemoryOccured;
// Transfer the strings ownership.
// This will work even if the ownership is already transferred
m_bStringsOwnership = original.m_bStringsOwnership; original.m_bStringsOwnership = false;
// Transfer the strings
for (WORD wIndex = 0; wIndex < x_nVssMaxDebugArgs; wIndex++) m_ppwszStrings[wIndex] = original.m_ppwszStrings[wIndex]; }
inline CVssDebugInfo::~CVssDebugInfo() { if (m_bStringsOwnership) { for (WORD wIndex = 0; wIndex < x_nVssMaxDebugArgs; wIndex++) { if ( m_ppwszStrings[wIndex] != NULL ) { ::CoTaskMemFree(m_ppwszStrings[wIndex]); m_ppwszStrings[wIndex] = NULL; } } } }
// This is used to add an numeric-type argument
inline CVssDebugInfo CVssDebugInfo::operator << ( IN INT nArgument ) { // Converting the number into a string
WCHAR wszBuffer[x_nVssNumericBufferSize + 1]; ::_snwprintf(wszBuffer, x_nVssNumericBufferSize, L"%d", nArgument);
return (*this) << wszBuffer; }
// This is used to add an HRESULT-type argument
inline CVssDebugInfo CVssDebugInfo::operator << ( IN HRESULT hrArgument ) { // Converting the number into a string
WCHAR wszBuffer[x_nVssNumericBufferSize + 1]; ::_snwprintf(wszBuffer, x_nVssNumericBufferSize, L"0x%08lx", hrArgument);
return (*this) << wszBuffer; }
// This is used to add an LONGLONG-type argument
inline CVssDebugInfo CVssDebugInfo::operator << ( IN LONGLONG llArgument ) { // Converting the number into a string
WCHAR wszBuffer[x_nVssNumericBufferSize + 1]; ::_snwprintf(wszBuffer, x_nVssNumericBufferSize, WSTR_LONGLONG_FMT, LONGLONG_PRINTF_ARG(llArgument) );
return (*this) << wszBuffer; }
// This is used to add an GUID-type argument
inline CVssDebugInfo CVssDebugInfo::operator << ( IN GUID guidArgument ) { // Converting the number into a string
WCHAR wszBuffer[x_nVssGuidBufferSize + 1]; ::_snwprintf(wszBuffer, x_nVssGuidBufferSize, WSTR_GUID_FMT, GUID_PRINTF_ARG(guidArgument));
return (*this) << wszBuffer; }
// This is used to add an string-type argument
inline CVssDebugInfo CVssDebugInfo::operator << ( IN LPCWSTR wszArgument ) { if (wszArgument == NULL) { BS_ASSERT(false); return (*this); }
if (m_bOutOfMemoryOccured) return (*this);
// We cannot add more strings if we do not have the ownership...
if (!m_bStringsOwnership) { BS_ASSERT(false); return (*this); }
if (m_wNumStrings >= x_nVssMaxDebugArgs) { BS_ASSERT(false); // Improper usage (putting too many arguments)
return (*this); }
// Storing into the actual list of arguments. We might have an allocation error here.
LPWSTR wszFormattedValue = (LPWSTR)::CoTaskMemAlloc(sizeof(WCHAR)*(1 + ::wcslen(wszArgument))); if (wszFormattedValue == NULL) { m_bOutOfMemoryOccured = true; return (*this); }
::wcscpy(wszFormattedValue, wszArgument); m_ppwszStrings[m_wNumStrings++] = wszFormattedValue;
return (*this); }
///////////////////////////////////////////////////////////////////////////////////////
// CVssFunctionTracer
inline CVssFunctionTracer::CVssFunctionTracer( IN CVssDebugInfo dbgInfo, IN const WCHAR* pwszFunctionName ) { m_hr = S_OK; m_pwszFunctionName = pwszFunctionName; m_szFileAlias = dbgInfo.m_szFileAlias; m_ulLine = dbgInfo.m_ulLine; m_dwLevel = dbgInfo.m_dwLevel; m_dwIndent = dbgInfo.m_dwIndent;
if ( g_cDbgTrace.IsTracingEnabled() && g_cDbgTrace.GetTraceEnterExit() ) { g_cDbgTrace.PrePrint( dbgInfo.m_wszFile, dbgInfo.m_ulLine, m_dwIndent, m_dwLevel, m_pwszFunctionName, TRUE ); // The reason that I not allow putting here custom-defined arguments is that
// if the caller put wrong references it can easily generate an AV.
// And, at this point, there is no NT exceptions treatment at the caller side.
g_cDbgTrace.PrintEnterExit(L""); g_cDbgTrace.PostPrint( m_dwIndent ); } }
inline CVssFunctionTracer::~CVssFunctionTracer() { if ( g_cDbgTrace.IsTracingEnabled() && g_cDbgTrace.GetTraceEnterExit() ) { g_cDbgTrace.PrePrint( L"", 0UL, m_dwIndent, m_dwLevel, m_pwszFunctionName, FALSE ); g_cDbgTrace.PrintEnterExit(L"hr: 0x%08x", m_hr); g_cDbgTrace.PostPrint( m_dwIndent ); } }
void inline __cdecl CVssFunctionTracer::Trace( CVssDebugInfo dbgInfo, const WCHAR* pwszMsgFormat, ...)
// WARNING: This function do NOT clear the ft.hr field!
{ if ( !g_cDbgTrace.IsTracingEnabled() ) return;
CVssOutputBuffer buffer; if (buffer.IsBufferValid()) { va_list marker; va_start( marker, pwszMsgFormat ); _vsnwprintf( buffer.GetBuffer(), buffer.GetBufferSize(), pwszMsgFormat, marker ); va_end( marker );
g_cDbgTrace.PrePrint( dbgInfo.m_wszFile, dbgInfo.m_ulLine, dbgInfo.m_dwIndent, dbgInfo.m_dwLevel ); g_cDbgTrace.Print( L"%s: %s", m_pwszFunctionName, buffer.GetBuffer() ); g_cDbgTrace.PostPrint( dbgInfo.m_dwIndent ); } };
void inline CVssFunctionTracer::TraceBuffer( CVssDebugInfo dbgInfo, DWORD dwBufferSize, PBYTE pbBuffer ) { // WARNING: This function do NOT clear the ft.hr field!
if ( !g_cDbgTrace.IsTracingEnabled() ) return;
const nBytesPerSubgroup = 4; const nSubgroupsPerGroup = 2; const nGroupsCount = 2; const nSubgroupSize = 3*nBytesPerSubgroup + 1; // Add a space between subgroups
const nGroupSize = nSubgroupSize*nSubgroupsPerGroup + 1; // Add a space between groups
const nLineSize = nGroupSize*nGroupsCount + 1; // Add the zero character.
WCHAR wszPrintedBufferLine[nLineSize]; WCHAR wszPrintedBufferLineInChr[nLineSize]; WCHAR wszDigits[] = L"0123456789ABCDEF";
// Print each line
for (DWORD dwBufferOffset = 0; dwBufferOffset < dwBufferSize; ) { int nLineOffset = 0; int nLineOffsetChr = 0;
// Print each group in the line
for (int nGroupIndex = 0; nGroupIndex < nGroupsCount; nGroupIndex++) { // Print each subgroup in the group
for (int nSubgroupIndex = 0; nSubgroupIndex < nSubgroupsPerGroup; nSubgroupIndex++) { // Print each byte in the subgroup
for (int nByteIndex = 0; nByteIndex < nBytesPerSubgroup; nByteIndex++) { if (dwBufferOffset < dwBufferSize) { BYTE bChar = pbBuffer[dwBufferOffset]; wszPrintedBufferLineInChr[nLineOffsetChr++] = ( bChar >= 0x20 && bChar < 0x7F )? (WCHAR)bChar: L'.'; wszPrintedBufferLine[nLineOffset++] = wszDigits[pbBuffer[dwBufferOffset] / 0x10]; wszPrintedBufferLine[nLineOffset++] = wszDigits[pbBuffer[dwBufferOffset++] % 0x10]; wszPrintedBufferLine[nLineOffset++] = L' '; // Print an additional space after each group
} else { wszPrintedBufferLineInChr[nLineOffsetChr++] = L'#'; wszPrintedBufferLine[nLineOffset++] = L'#'; wszPrintedBufferLine[nLineOffset++] = L'#'; wszPrintedBufferLine[nLineOffset++] = L' '; // Print an additional space after each group
} } wszPrintedBufferLine[nLineOffset++] = L' '; // Print a space after each subgroup
} wszPrintedBufferLine[nLineOffset++] = L' '; // Print an additional space after each group
}
// Put hte termination characters
wszPrintedBufferLineInChr[nLineOffsetChr++] = L'\0'; wszPrintedBufferLine[nLineOffset++] = L'\0'; BS_ASSERT( nLineOffset == nLineSize );
g_cDbgTrace.PrePrint( dbgInfo.m_wszFile, dbgInfo.m_ulLine, dbgInfo.m_dwIndent, dbgInfo.m_dwLevel ); g_cDbgTrace.Print( L"%s %s", wszPrintedBufferLine, wszPrintedBufferLineInChr ); g_cDbgTrace.PostPrint( dbgInfo.m_dwIndent ); } };
void inline __cdecl CVssFunctionTracer::Throw( CVssDebugInfo dbgInfo, // Caller debugging info
HRESULT hrToBeThrown, // The new HR to be thrown
const WCHAR* pwszMsgFormat, // Message that will be displayed if throw needed
... // Additional arguments
) throw(HRESULT) { if ( g_cDbgTrace.IsTracingEnabled() ) { if (pwszMsgFormat != NULL) { CVssOutputBuffer buffer; if (buffer.IsBufferValid()) { va_list marker; va_start( marker, pwszMsgFormat ); _vsnwprintf( buffer.GetBuffer(), buffer.GetBufferSize(), pwszMsgFormat, marker ); va_end( marker );
g_cDbgTrace.PrePrint( dbgInfo.m_wszFile, dbgInfo.m_ulLine, dbgInfo.m_dwIndent, dbgInfo.m_dwLevel ); g_cDbgTrace.Print( L"%s: %s", m_pwszFunctionName, buffer.GetBuffer() ); g_cDbgTrace.PostPrint( dbgInfo.m_dwIndent ); } }
g_cDbgTrace.PrePrint( dbgInfo.m_wszFile, dbgInfo.m_ulLine, dbgInfo.m_dwIndent, DEBUG_TRACE_CATCH_EXCEPTIONS ); g_cDbgTrace.Print( L"%s: Throwing HRESULT code 0x%08lx. " L"Previous HRESULT code = 0x%08lx", m_pwszFunctionName, hrToBeThrown, m_hr ); g_cDbgTrace.PostPrint( DEBUG_TRACE_CATCH_EXCEPTIONS ); } m_hr = hrToBeThrown; throw( ( HRESULT )m_hr ); };
void inline __cdecl CVssFunctionTracer::ThrowIf( BOOL bThrowNeeded, // Throw an HR if and only if bThrowNeeded is TRUE.
CVssDebugInfo dbgInfo, // Caller debugging info
HRESULT hrToBeThrown, // The new HR to be thrown
const WCHAR* pwszMsgFormat, // Message that will be displayed if throw needed
... // Additional arguments
) throw(HRESULT)
// WARNING: This function clears the ft.hr field if no errors !
// Also if bThrowNeeded == false then the m_hr is reset to S_OK !
{ if (!bThrowNeeded) { m_hr = S_OK; return; }
if ( g_cDbgTrace.IsTracingEnabled() ) { if (pwszMsgFormat != NULL) { CVssOutputBuffer buffer; if (buffer.IsBufferValid()) { va_list marker; va_start( marker, pwszMsgFormat ); _vsnwprintf( buffer.GetBuffer(), buffer.GetBufferSize(), pwszMsgFormat, marker ); va_end( marker );
g_cDbgTrace.PrePrint( dbgInfo.m_wszFile, dbgInfo.m_ulLine, dbgInfo.m_dwIndent, dbgInfo.m_dwLevel ); g_cDbgTrace.Print( L"%s: %s", m_pwszFunctionName, buffer.GetBuffer() ); g_cDbgTrace.PostPrint( dbgInfo.m_dwIndent ); } }
g_cDbgTrace.PrePrint( dbgInfo.m_wszFile, dbgInfo.m_ulLine, dbgInfo.m_dwIndent, DEBUG_TRACE_CATCH_EXCEPTIONS ); g_cDbgTrace.Print( L"%s: %s HRESULT code 0x%08lx. " L"Previous HRESULT code = 0x%08lx", bThrowNeeded? L"Throwing": L"Tracing", m_pwszFunctionName, hrToBeThrown, m_hr ); g_cDbgTrace.PostPrint( DEBUG_TRACE_CATCH_EXCEPTIONS ); }
m_hr = hrToBeThrown; throw( ( HRESULT )m_hr ); };
//
// Messages displayed at the console (only for test and demo purpose).
//
void inline __cdecl CVssFunctionTracer::Msg( const WCHAR* pwszMsgFormat, // Message that will be displayed
... ) { USES_CONVERSION;
_ASSERTE(pwszMsgFormat);
CVssOutputBuffer buffer; if (buffer.IsBufferValid()) { va_list marker; va_start( marker, pwszMsgFormat ); _vsnwprintf( buffer.GetBuffer(), buffer.GetBufferSize(), pwszMsgFormat, marker ); va_end( marker );
wprintf( L"%s\n", W2CT(buffer.GetBuffer()) ); } }
void inline __cdecl CVssFunctionTracer::MsgNoCR( const WCHAR* pwszMsgFormat, // Message that will be displayed
... ) { USES_CONVERSION;
_ASSERTE(pwszMsgFormat);
CVssOutputBuffer buffer; if (buffer.IsBufferValid()) { va_list marker; va_start( marker, pwszMsgFormat ); _vsnwprintf( buffer.GetBuffer(), buffer.GetBufferSize(), pwszMsgFormat, marker ); va_end( marker );
wprintf( L"%s", W2CT(buffer.GetBuffer()) ); } }
void inline __cdecl CVssFunctionTracer::Err( CVssDebugInfo dbgInfo, // Caller debugging info
HRESULT hrToBeThrown, // The new HR to be thrown
const WCHAR* pwszMsgFormat, // Error message that will be displayed
... ) { USES_CONVERSION;
_ASSERTE(pwszMsgFormat);
CVssOutputBuffer buffer; if (buffer.IsBufferValid()) { va_list marker; va_start( marker, pwszMsgFormat ); _vsnwprintf( buffer.GetBuffer(), buffer.GetBufferSize(), pwszMsgFormat, marker ); va_end( marker );
// Message box
CVssOutputBuffer buffer2; if (!buffer2.IsBufferValid()) throw(E_OUTOFMEMORY);
_snwprintf(buffer2.GetBuffer(), buffer2.GetBufferSize(), L"%s(%ld)\n%s @ [%08lx,%08lx], PID=%ld, TID=%ld\n%s", dbgInfo.m_wszFile, dbgInfo.m_ulLine, m_pwszFunctionName, dbgInfo.m_dwIndent, dbgInfo.m_dwLevel, GetCurrentProcessId(), GetCurrentThreadId(), buffer.GetBuffer() );
::MessageBoxW( NULL, buffer2.GetBuffer(), L"Error", MB_OK);
if ( g_cDbgTrace.IsTracingEnabled() ) { g_cDbgTrace.PrePrint( dbgInfo.m_wszFile, dbgInfo.m_ulLine, dbgInfo.m_dwIndent, dbgInfo.m_dwLevel ); g_cDbgTrace.Print( L"%s: %s", m_pwszFunctionName, buffer2.GetBuffer() ); g_cDbgTrace.PostPrint( dbgInfo.m_dwIndent ); }
wprintf( L"Error: %s\n", W2CT(buffer2.GetBuffer()) );
}
if (hrToBeThrown) { m_hr = hrToBeThrown; throw( ( HRESULT )m_hr ); } }
//
// Informative message boxes (only for test and demo purpose).
//
void inline __cdecl CVssFunctionTracer::MsgBox( const WCHAR* pwszMsgTitle, // Title of the Message box
const WCHAR* pwszMsgFormat, // Message that will be displayed
... ) { USES_CONVERSION;
_ASSERTE(pwszMsgTitle); _ASSERTE(pwszMsgFormat);
CVssOutputBuffer buffer; if (buffer.IsBufferValid()) { va_list marker; va_start( marker, pwszMsgFormat ); _vsnwprintf( buffer.GetBuffer(), buffer.GetBufferSize(), pwszMsgFormat, marker ); va_end( marker );
::MessageBox(NULL, W2CT(buffer.GetBuffer()), W2CT(pwszMsgTitle), MB_OK); } }
void inline __cdecl CVssFunctionTracer::ErrBox( CVssDebugInfo dbgInfo, // Caller debugging info
HRESULT hrToBeThrown, // The new HR to be thrown
const WCHAR* pwszMsgFormat, // Error message that will be displayed
... ) { USES_CONVERSION;
_ASSERTE(pwszMsgFormat);
CVssOutputBuffer buffer; if (buffer.IsBufferValid()) { va_list marker; va_start( marker, pwszMsgFormat ); _vsnwprintf( buffer.GetBuffer(), buffer.GetBufferSize(), pwszMsgFormat, marker ); va_end( marker );
if ( g_cDbgTrace.IsTracingEnabled() ) { g_cDbgTrace.PrePrint( dbgInfo.m_wszFile, dbgInfo.m_ulLine, dbgInfo.m_dwIndent, dbgInfo.m_dwLevel ); g_cDbgTrace.Print( L"%s: %s", m_pwszFunctionName, buffer.GetBuffer() ); g_cDbgTrace.PostPrint( dbgInfo.m_dwIndent ); }
::MessageBox(NULL, W2CT(buffer.GetBuffer()), L"Error", MB_OK); }
if (hrToBeThrown) { m_hr = hrToBeThrown; throw( ( HRESULT )m_hr ); } }
/*++
Routine Description:
Traces the COM error description. Can be called after automation COM calls (for example XML or COM+ related)
--*/ void inline CVssFunctionTracer::TraceComError() { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssFunctionTracer::TraceComError");
CComPtr<IErrorInfo> pErrorInfo; HRESULT hr2 = ::GetErrorInfo(0, &pErrorInfo); if (SUCCEEDED(hr2)) { if (pErrorInfo != NULL) { BSTR bstrDescription; HRESULT hr3 = pErrorInfo->GetDescription(&bstrDescription); if (SUCCEEDED(hr3)) { ft.Trace(VSSDBG_GEN, L"Error info description: %s", bstrDescription); ::SysFreeString(bstrDescription); } else ft.Trace(VSSDBG_GEN, L"Warning: Error getting error description = 0x%08lx", hr3); } } else ft.Trace(VSSDBG_GEN, L"Warning: Error getting error info = 0x%08lx", hr2); }
void inline __cdecl CVssFunctionTracer::LogError( IN DWORD dwEventID, // The ID of the event
IN CVssDebugInfo dbgInfo, // Caller debugging info
IN WORD wType // By default it is EVENTLOG_ERROR_TYPE
) { CVssFunctionTracer ft(VSSDBG_GEN, L"CVssFunctionTracer::LogError");
try { LPCWSTR ppwszStrings[x_nVssMaxDebugArgs]; CHAR szFileLine[32]; CHAR szTemp[34]; // Max length of string from _ultoa()
// Create the four lines of binary data output in the data section of the event log message.
// First the Caller debugging info:
::strncpy( szFileLine, dbgInfo.m_szFileAlias, 8 ); ::_ultoa( dbgInfo.m_ulLine, szTemp, 10 ); ::strncpy( szFileLine + 8, szTemp, 8 ); // strncpy has the nice property of zeroing out unuse chars.
// Now info on the ft at point of construction:
::strncpy( szFileLine + 16, m_szFileAlias, 8 ); ::_ultoa( m_ulLine, szTemp, 10 ); ::strncpy( szFileLine + 24, szTemp, 8 ); // strncpy has the nice property of zeroing out unuse chars.
// Fill out the strings that are given as arguments
WORD wNumStrings = dbgInfo.m_wNumStrings; for( WORD wIndex = 0; wIndex < dbgInfo.m_wNumStrings; wIndex++ ) ppwszStrings[wIndex] = const_cast<LPCWSTR>(dbgInfo.m_ppwszStrings[wIndex]);
// Get a handle to use with ReportEvent()
HANDLE hEventSource = ::RegisterEventSourceW( NULL, // IN LPCWSTR lpUNCServerName,
x_wszEventLogVssSourceName // IN LPCWSTR lpSourceName
); if (hEventSource == NULL) ft.Throw( VSSDBG_SHIM, E_UNEXPECTED, L"Error on RegisterEventSourceW 0x%08lx", GetLastError());
// Write to event log.
BOOL bRet = ::ReportEventW( hEventSource, // IN HANDLE hEventLog,
wType, // IN WORD wType,
0, // IN WORD wCategory,
dwEventID, // IN DWORD dwEventID,
NULL, // IN PSID lpUserSid,
wNumStrings, // IN WORD wNumStrings,
sizeof( szFileLine ), // IN DWORD dwDataSize,
ppwszStrings, // IN LPCWSTR *lpStrings,
szFileLine // IN LPVOID lpRawData
); if ( !bRet ) ft.Trace( VSSDBG_SHIM, L"Error on ReportEventW 0x%08lx", GetLastError());
// Close the handle to the event log
bRet = ::DeregisterEventSource( hEventSource ); if ( !bRet ) ft.Throw( VSSDBG_SHIM, E_UNEXPECTED, L"Error on DeregisterEventSource 0x%08lx", GetLastError()); } VSS_STANDARD_CATCH(ft) }
//
// Set the file alias to unknown in case a module doesn't set it's alias.
//
#undef VSS_FILE_ALIAS
#define VSS_FILE_ALIAS "UNKNOWN"
#endif // __VSS_DEBUG_HXX__
|