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.
984 lines
33 KiB
984 lines
33 KiB
/*++
|
|
|
|
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__
|