WindowsXP-SP1/windows/oleacc/oleacc/debug.h
2020-09-30 16:53:49 +02:00

362 lines
14 KiB
C++

// Copyright (c) 2000 Microsoft Corporation
// --------------------------------------------------------------------------
//
// debug
//
// Assert, OutputDebugString-like replacements
//
//
// On NT, these use OutputDebugString; on 9x, the DBWIN32 mutex is used.
//
// These all compile away to nothing in release builds.
// (In future releases, some of the parameter errors may remain on release
// builds.)
//
// On release builds, ouput is only produces if the mutex
// "oleacc-msaa-use-dbwin" exists. (A small applet can be used to create
// this mutex.) This prevents our debug code from annoying the NT test and
// stress people who only want to see critical messages.
//
// --------------------------------------------------------------------------
//
// Trace functionality - these output debug strings.
//
//
// To log an error, use:
//
// TraceError( format string, optional-args... );
//
// uses printf-like format string with variable number of args.
//
// If a HRESULT is known, use:
// TraceErrorHR( hr, format string, args... );
//
// If the error is the result of a failed Win32 API call, use...
// TraceErrorW32( format string, args... );
//
// This will call GetLastError internally.
//
// Flavors available: (eg. TraceXXXX)
//
// Debug - temporary printf debugging. Should be removed before checkin.
// Info - for displaying useful information during normal operation.
// Warning - when an unexpected recoverable error happens.
// Error - when system API or method calls fail unexpectedly
// Param - when bad parameters are passed in which result in an error
// ParamWarn - when bad parameters are passed in which we accept for compat
// reasons; or when soon-to-be-deprecated values are used.
// Interop - when API or method of some other component which we rely on
// fails unexpectedly
//
// --------------------------------------------------------------------------
//
// Call/Return tracking
//
// To track when a particular method is called and returns, use:
//
// void Class::Method( args )
// {
// IMETHOD( methodname, optional-fmt-string, optional-args... );
//
// Use SMETHOD for static methods and functions. (IMETHOD also reports the
// value of the 'this' pointer.)
//
// --------------------------------------------------------------------------
//
// Asserts
//
// Assert( cond )
// - Traditional assert.
//
// AssertMsg( cond, fmt-string, args... )
// - Assert which reports message. Uses printf-style format.
//
// AssertStr( str )
// - This exists for compat reasons - it was already used in oleacc code.
// This is an unconditional assert, equivalent to
// AssertMsg( FALSE, str )
//
// --------------------------------------------------------------------------
//
// Note that all strings - format strings and method names - need TEXT()
// to compile as Unicode.
//
// --------------------------------------------------------------------------
#ifndef _DEBUG_H_
#define _DEBUG_H_
#include <stdarg.h>
#define _TRACE_DEBUG 0
#define _TRACE_INFO 1
#define _TRACE_WARNING 2
#define _TRACE_ERROR 3
#define _TRACE_PARAM 4
#define _TRACE_PARAWARN 5
#define _TRACE_INTEROP 6
#define _TRACE_ASSERT_D 7 // Debug-build assert - really does assert
#define _TRACE_ASSERT_R 8 // Release-build assert - only logs error, doesn't halt program
#define _TRACE_CALL 9
#define _TRACE_RET 10
// These are implemented in debug.cpp, and do the real work of outputting the
// debug message, and calling DebugBreak, if appropriate.
//
// HR, W32 versions add messages corresponding to HRESULT or GetLastError().
void _Trace ( LPCTSTR pFile, ULONG uLineNo, DWORD dwLevel, const void * pThis, LPCTSTR pszWhere, LPCTSTR pszStr, va_list alist );
void _TraceHR ( LPCTSTR pFile, ULONG uLineNo, DWORD dwLevel, const void * pThis, LPCTSTR pszWhere, HRESULT hr, LPCTSTR pszStr, va_list alist );
void _TraceW32 ( LPCTSTR pFile, ULONG uLineNo, DWORD dwLevel, const void * pThis, LPCTSTR pszWhere, LPCTSTR pszStr, va_list alist );
void _Trace ( LPCTSTR pFile, ULONG uLineNo, DWORD dwLevel, const void * pThis, LPCTSTR pszWhere, LPCTSTR pszStr );
void _TraceHR ( LPCTSTR pFile, ULONG uLineNo, DWORD dwLevel, const void * pThis, LPCTSTR pszWhere, HRESULT hr, LPCTSTR pszStr );
void _TraceW32 ( LPCTSTR pFile, ULONG uLineNo, DWORD dwLevel, const void * pThis, LPCTSTR pszWhere, LPCTSTR pszStr );
// Prototypes for the macros defined here.
//
// These are not actually used - they are only here to give VC's autocomplete some
// prototypes to work with for autocomplete.
//
// The real work is done by the #defines below.
//
// Note that these must appear *before* their #defines in this file.
//
void IMETHOD( LPCTSTR pszMethodName, LPCTSTR pszStr = TEXT(""), ... );
void Assert( bool cond );
void AssertMsg( bool cond, LPCTSTR str, ... );
void AssertStr( LPCTSTR str );
void TraceDebug( LPCTSTR str, ... );
void TraceInfo( LPCTSTR str, ... );
void TraceWarning( LPCTSTR str, ... );
void TraceError( LPCTSTR str, ... );
void TraceParam( LPCTSTR str, ... );
void TraceParamWarn( LPCTSTR str, ... );
void TraceInterop( LPCTSTR str, ... );
void TraceDebugHR( HRESULT hr, LPCTSTR str, ... );
void TraceInfoHR( HRESULT hr, LPCTSTR str, ... );
void TraceWarningHR( HRESULT hr, LPCTSTR str, ... );
void TraceErrorHR( HRESULT hr, LPCTSTR str, ... );
void TraceParamHR( HRESULT hr, LPCTSTR str, ... );
void TraceParamWarnHR( HRESULT hr, LPCTSTR str, ... );
void TraceInteropHR( HRESULT hr, LPCTSTR str, ... );
void TraceDebugW32( LPCTSTR str, ... );
void TraceInfoW32( LPCTSTR str, ... );
void TraceWarningW32( LPCTSTR str, ... );
void TraceErrorW32( LPCTSTR str, ... );
void TraceParamW32( LPCTSTR str, ... );
void TraceParamWarnW32( LPCTSTR str, ... );
void TraceInteropW32( LPCTSTR str, ... );
#ifdef _DEBUG
// Problem - #define's can't handle variable number of arguments - so you can't do:
//
// #define TraceError( str, ... ) RealTrace( __FILE__, __LINE__, str, ... )
//
// Instead, we use a helper class. Its ctor takes as arguments __FILE__,
// __LINE__, and any other 'out of band' data. This class also has a
// method that takes a variable number of params. So we get something like:
//
// #define TraceError TraceClass( __FILE__, __LINE__ ).Method
//
//
// This method ends up being called with the variable list of params:
//
// TraceError( "count is %d", count )
//
// ...gets expanded to...
//
// TraceClass( __FILE__, __LINE__ ).Method( "count is %d", count )
//
// The basic idea is the we use ctor params to capture any 'out-of-band'
// data that's not specified in the macro parameters; and then use the
// method call to add in the variable-length macro params.
//
// The method can use the <stdarg.h> ,acros to get a va_list for these params,
// and then pass that to the RealTrace function, along with the __FILE__ and
// __LINE__ which were collected in the ctor.
class _TraceHelper
{
LPCTSTR m_pszFile;
ULONG m_uLineNo;
DWORD m_dwLevel;
const void * m_pThis;
public:
_TraceHelper( LPCTSTR pszFile, ULONG uLineNo, DWORD dwLevel, const void * pThis )
: m_pszFile( pszFile ),
m_uLineNo( uLineNo ),
m_dwLevel( dwLevel ),
m_pThis( pThis )
{
// Done.
}
// Can't use plain "BOOL cond" here, since ptr types don't convert to BOOL
// (which is an int), even though you can use them in an if statement.
template < typename T >
void TraceIfCondFails ( T cond, LPCTSTR pszStr, ... )
{
if( ! cond )
{
va_list alist;
va_start( alist, pszStr );
_Trace( m_pszFile, m_uLineNo, m_dwLevel, m_pThis, NULL, pszStr, alist );
va_end( alist );
}
}
void Trace ( LPCTSTR pszStr, ... )
{
va_list alist;
va_start( alist, pszStr );
_Trace( m_pszFile, m_uLineNo, m_dwLevel, m_pThis, NULL, pszStr, alist );
va_end( alist );
}
void TraceHR ( HRESULT hr, LPCTSTR pszStr, ... )
{
va_list alist;
va_start( alist, pszStr );
_TraceHR( m_pszFile, m_uLineNo, m_dwLevel, m_pThis, NULL, hr, pszStr, alist );
va_end( alist );
}
void TraceW32 ( LPCTSTR pszStr, ... )
{
va_list alist;
va_start( alist, pszStr );
_TraceW32( m_pszFile, m_uLineNo, m_dwLevel, m_pThis, NULL, pszStr, alist );
va_end( alist );
}
};
class _DebugCallRetTracker
{
const void * m_pThis;
LPCTSTR m_pszMethodName;
LPCTSTR m_pszFile;
ULONG m_uLineNo;
public:
_DebugCallRetTracker( const void * pThis, LPCTSTR pszFile, ULONG uLineNo )
: m_pThis( pThis ),
m_pszMethodName( NULL ),
m_pszFile( pszFile ),
m_uLineNo( uLineNo )
{
// Done.
}
void Trace( LPCTSTR pszMethodName, LPCTSTR pszStr = NULL, ... )
{
m_pszMethodName = pszMethodName;
va_list alist;
va_start( alist, pszStr );
_Trace( m_pszFile, m_uLineNo, _TRACE_CALL, m_pThis, m_pszMethodName, pszStr, alist );
va_end( alist );
}
~_DebugCallRetTracker( )
{
_Trace( m_pszFile, m_uLineNo, _TRACE_RET, m_pThis, m_pszMethodName, NULL );
}
};
#define IMETHOD _DebugCallRetTracker _CallTrack_temp_var( this, TEXT( __FILE__ ), __LINE__ ); _CallTrack_temp_var.Trace
#define SMETHOD _DebugCallRetTracker _CallTrack_temp_var( NULL, TEXT( __FILE__ ), __LINE__ ); _CallTrack_temp_var.Trace
#define _TraceM( file, line, level, fn ) _TraceHelper( TEXT( file ), line, level, NULL ).fn
#define _TRACE_ASSERT _TRACE_ASSERT_D
#else // _DEBUG
// This inline allows us to swallow a variable number of args (including 0).
// The "while(0)" in front of it stops those args from even being evaluated.
// Using _ReurnZero() avoids "conditional expression is constant" warning.
inline void _DoNothingWithArgs( ... ) { }
inline int _ReturnZero() { return 0; }
#define IMETHOD while( _ReturnZero() ) _DoNothingWithArgs
#define SMETHOD while( _ReturnZero() ) _DoNothingWithArgs
#define _TraceM( file, line, level, fn ) while( _ReturnZero() ) _DoNothingWithArgs
#define _TRACE_ASSERT _TRACE_ASSERT_R
#endif // _DEBUG
// These expand as follows:
//
// Sample usage:
//
// TraceInfo( TEXT("count = %d"), count );
//
// In debug mode, this gets expanded to:
//
// _TraceHelper( TEXT( "filename.cpp" ), 234, _TRACE_INFO, NULL ).Trace ( TEXT("count = %d"), count );
//
// In release mode, this gets expanded to:
//
// while( 0 ) _DoNothing ( TEXT("count = %d"), count );
#define TraceDebug _TraceM( __FILE__, __LINE__, _TRACE_DEBUG, Trace )
#define TraceInfo _TraceM( __FILE__, __LINE__, _TRACE_INFO, Trace )
#define TraceWarning _TraceM( __FILE__, __LINE__, _TRACE_WARNING, Trace )
#define TraceError _TraceM( __FILE__, __LINE__, _TRACE_ERROR, Trace )
#define TraceParam _TraceM( __FILE__, __LINE__, _TRACE_PARAM, Trace )
#define TraceParamWarn _TraceM( __FILE__, __LINE__, _TRACE_PARAMWARN, Trace )
#define TraceInterop _TraceM( __FILE__, __LINE__, _TRACE_INTEROP, Trace )
#define TraceDebugHR _TraceM( __FILE__, __LINE__, _TRACE_DEBUG, TraceHR )
#define TraceInfoHR _TraceM( __FILE__, __LINE__, _TRACE_INFO, TraceHR )
#define TraceWarningHR _TraceM( __FILE__, __LINE__, _TRACE_WARNING, TraceHR )
#define TraceErrorHR _TraceM( __FILE__, __LINE__, _TRACE_ERROR, TraceHR )
#define TraceParamHR _TraceM( __FILE__, __LINE__, _TRACE_PARAM, TraceHR )
#define TraceParamWarnHR _TraceM( __FILE__, __LINE__, _TRACE_PARAMWARN, TraceHR )
#define TraceInteropHR _TraceM( __FILE__, __LINE__, _TRACE_INTEROP, TraceHR )
#define TraceDebugW32 _TraceM( __FILE__, __LINE__, _TRACE_DEBUG, TraceW32 )
#define TraceInfoW32 _TraceM( __FILE__, __LINE__, _TRACE_INFO, TraceW32 )
#define TraceWarningW32 _TraceM( __FILE__, __LINE__, _TRACE_WARNING, TraceW32 )
#define TraceErrorW32 _TraceM( __FILE__, __LINE__, _TRACE_ERROR, TraceW32 )
#define TraceParamW32 _TraceM( __FILE__, __LINE__, _TRACE_PARAM, TraceW32 )
#define TraceParamWarnW32 _TraceM( __FILE__, __LINE__, _TRACE_PARAMWARN, TraceW32 )
#define TraceInteropW32 _TraceM( __FILE__, __LINE__, _TRACE_INTEROP, TraceW32 )
#define Assert( cond ) _TraceM( __FILE__, __LINE__, _TRACE_ASSERT, TraceIfCondFails ) ( cond, TEXT( # cond ) )
#define AssertMsg _TraceM( __FILE__, __LINE__, _TRACE_ASSERT, TraceIfCondFails )
// Unconditional Assert with message...
#define AssertStr( str ) AssertMsg( FALSE, str )
#endif // _DEBUG_H_