|
|
/****************************************************************************
Copyright (c) Microsoft Corporation 1997 All rights reserved
File: DEBUG.H
Debugging utilities header ***************************************************************************/
#ifndef _DEBUG_H_
#define _DEBUG_H_
// Trace Flags
#define TF_ALWAYS 0xFFFFFFFF
#define TF_NEVER 0x00000000
#define TF_QUERYINTERFACE 0x00000001 // Query Interface details
#define TF_FUNC 0x00000002 // Functions entrances w/parameters
#define TF_CALLS 0x00000004 // Function calls
#define TF_MEMORYALLOCS 0x00000008 // Memory Allocations
#define TF_DLL 0x00000010 // DLL specific
#define TF_WM 0x00000020 // Window Messages
#define TF_SCP 0x00000030 // SCP objects
#ifdef DEBUG
#pragma message("BUILD: DEBUG macros being built")
// Globals
extern DWORD g_TraceMemoryIndex; extern DWORD g_dwCounter; extern DWORD g_dwTraceFlags;
extern const TCHAR g_szTrue[]; extern const TCHAR g_szFalse[];
extern CRITICAL_SECTION g_DebugCS; extern BOOL g_fDebugInitialized;
// Macros
#define DEFINE_MODULE( _module ) static const TCHAR g_szModule[] = TEXT(_module);
#define __MODULE__ g_szModule
#define DEFINE_THISCLASS( _class ) static const TCHAR g_szClass[] = TEXT(_class);
#define __THISCLASS__ g_szClass
#define DEFINE_SUPER( _super ) static const TCHAR g_szSuper[] = TEXT(_super);
#define __SUPER__ g_szSuper
#if defined(_X86_)
#define DEBUG_BREAK do { _try { _asm int 3 } _except (EXCEPTION_EXECUTE_HANDLER) {;} } while (0)
#else
#define DEBUG_BREAK DebugBreak( );
#endif
#define INITIALIZE_TRACE_MEMORY_PROCESS \
g_TraceMemoryIndex = TlsAlloc( ); \ TlsSetValue( g_TraceMemoryIndex, NULL); \ DebugInitializeTraceFlags( ); \ TraceMessage( TEXT(__FILE__), __LINE__, g_szModule, TF_DLL, TEXT("Thread Memory tracing initialize.\n") )
#define INITIALIZE_TRACE_MEMORY_THREAD \
TlsSetValue( g_TraceMemoryIndex, NULL); \ TraceMessage( TEXT(__FILE__), __LINE__, g_szModule, TF_DLL, TEXT("Thread Memory tracing initialize.\n") )
#define UNINITIALIZE_TRACE_MEMORY \
DebugMemoryCheck( ); \ TraceMessage( TEXT(__FILE__), __LINE__, g_szModule, TF_DLL, TEXT("Memory tracing terminated.\n") )
#ifdef Assert
#undef Assert
#endif
#define Assert( _fn ) \
if ( !(_fn) && AssertMessage( TEXT(__FILE__), __LINE__, g_szModule, TEXT(#_fn), !!(_fn) ) ) DEBUG_BREAK
#ifdef AssertMsg
#undef AssertMsg
#endif
#define AssertMsg( _fn, _msg ) \
if ( !(_fn) && AssertMessage( TEXT(__FILE__), __LINE__, g_szModule, TEXT(_msg), !!(_fn) ) ) DEBUG_BREAK
#define TraceAlloc( _flags, _size ) DebugAlloc( TEXT(__FILE__), __LINE__, g_szModule, _flags, _size, TEXT(#_size) )
#define TraceAllocString( _flags, _size ) (LPTSTR) DebugAlloc( TEXT(__FILE__), __LINE__, g_szModule, _flags, (_size) * sizeof(TCHAR), TEXT(#_size) )
#define TraceFree( _hmem ) DebugFree( _hmem )
//
// Tracing Macros
//
// All functions that begin with "Trace" are in both DEBUG and RETAIL, but
// in RETAIL they do not spew output.
//
// Displays file, line number, module and "_msg" only if the TF_FUNC is set
// in g_dwTraceFlags.
#define TraceFunc( _msg ) \
InterlockIncrement(g_dwCounter); \ TraceMessage( TEXT(__FILE__), __LINE__, g_szModule, TF_FUNC, TEXT("+ ") TEXT(_msg) );
// Displays file, line number, module, class name and "_msg" only if the
// TF_FUNC is set in g_dwTraceFlags.
#define TraceClsFunc( _msg ) \
InterlockIncrement(g_dwCounter); \ TraceMessage( TEXT(__FILE__), __LINE__, g_szModule, TF_FUNC, TEXT("+ %s::%s"), g_szClass, TEXT(_msg) );
// Return macro for TraceFunc() and TraceClsFunc()
#define TraceFuncExit() { \
TraceMessage( TEXT(__FILE__), __LINE__, g_szModule, TF_FUNC, TEXT("V*\n") ); \ InterlockDecrement(g_dwCounter); \ return; \ } #define RETURN( _rval ) { \
TraceMessage( TEXT(__FILE__), __LINE__, g_szModule, TF_FUNC, TEXT("V\n") ); \ InterlockDecrement(g_dwCounter); \ return _rval; \ }
// If the value is not S_OK, it will display it.
#define HRETURN( _hr ) { \
if ( _hr ) \ TraceMessage( TEXT(__FILE__), __LINE__, g_szModule, TF_FUNC, TEXT("V hr = 0x%08x\n"), _hr ); \ else \ { TraceMessage( TEXT(__FILE__), __LINE__, g_szModule, TF_FUNC, TEXT("V\n") ); }\ InterlockDecrement(g_dwCounter); \ return _hr; \ }
// Displays the file, line number, module and function call and return from the
// function call (no return value displayed) for "_fn" only if the TF_CALLS is
// set in g_dwTraceFlags.
#define TraceDo( _fn ) {\
InterlockIncrement(g_dwCounter); \ TraceMessage( TEXT(__FILE__), __LINE__, g_szModule, TF_CALLS, TEXT("+ %s\n"), TEXT(#_fn) ); \ _fn; \ TraceMessage( TEXT(__FILE__), __LINE__, g_szModule, TF_CALLS, TEXT("V\n") ); \ InterlockDecrement(g_dwCounter); \ }
// Displays the file, line number, module and function call and return value
// which is formatted in "_msg" for "_fn" only if the TF_CALLS is set in
// g_dwTraceFlags.
#define TraceMsgDo( _fn, _msg ) {\
InterlockIncrement(g_dwCounter); \ TraceMessage( TEXT(__FILE__), __LINE__, g_szModule, TF_CALLS, TEXT("+ %s\n"), TEXT(#_fn) ); \ TraceMessageDo( TEXT(__FILE__), __LINE__, g_szModule, TF_CALLS, TEXT(_msg), TEXT(#_fn), _fn ); \ InterlockDecrement(g_dwCounter); \ }
// This functions only asserts if the result is ZERO.
#define TraceAssertIfZero( _fn ) \
if ( !(_fn) && AssertMessage( TEXT(__FILE__), __LINE__, g_szModule, TEXT(#_fn), !!(_fn) ) ) DEBUG_BREAK
#define TraceMsgGUID( _flag, _guid ) \
TraceMsg( _flag, TEXT("{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"), \ _guid.Data1, _guid.Data2, _guid.Data3, \ _guid.Data4[0], _guid.Data4[1], _guid.Data4[2], _guid.Data4[3], \ _guid.Data4[4], _guid.Data4[5], _guid.Data4[6], _guid.Data4[7] )
#define ErrorMsg( _fmt, _arg ) \
TraceMessage( TEXT(__FILE__), __LINE__, g_szModule, TF_ALWAYS, TEXT(_fmt), _arg );
//
// Debug Macros
//
// These calls are only compiled in DEBUG. They are a NOP in RETAIL (not even
// compiled in.
//
// Same as TraceDo() but only compiled in DEBUG.
#define DebugDo( _fn ) {\
InterlockIncrement(g_dwCounter); \ DebugMessage( TEXT(__FILE__), __LINE__, g_szModule, TEXT("+ %s\n"), TEXT(#_fn) ); \ _fn; \ DebugMessage( TEXT(__FILE__), __LINE__, g_szModule, TEXT("V\n") ); \ InterlockDecrement(g_dwCounter); \ }
// Same as TraceMsgDo() but only compiled in DEBUG.
#define DebugMsgDo( _fn, _msg ) {\
InterlockIncrement(g_dwCounter); \ DebugMessage( TEXT(__FILE__), __LINE__, g_szModule, TEXT("+ %s\n"), TEXT(#_fn) ); \ DebugMessageDo( TEXT(__FILE__), __LINE__, g_szModule, TEXT(_msg), TEXT(#_fn), _fn); \ InterlockDecrement(g_dwCounter); \ }
//
// HRESULT testing macros
//
// These functions check HRESULT return values and display UI if conditions
// warrant only in DEBUG.
//
// Warning is display if HRESULT is anything but S_OK (0).
#define THR( _fn ) \
TraceHR( TEXT(__FILE__), __LINE__, g_szModule, TEXT(#_fn), _fn )
// Warning is display if HRESULT is anything but S_OK (0).
#define RRETURN( _fn ) { \
RETURN( TraceHR( TEXT(__FILE__), __LINE__, g_szModule, TEXT(#_fn), _fn ) ); \ }
// Warning is display if HRESULT is anything but S_OK (0) only if
// TF_QUERYINTERFACE is set in g_dwTraceFlags, otherwise only a debug message
// will be printed.
#define QIRETURN( _hr, _riid ) { \
if ( !!( TF_QUERYINTERFACE & g_dwTraceFlags ) ) { \ RETURN(TraceHR( TEXT(__FILE__), __LINE__, g_szModule, TEXT(#_hr), _hr )); \ } else if ( _hr ) \ DebugMessage( TEXT(__FILE__), __LINE__, g_szModule, TEXT("HRESULT: QueryInterface({%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x}) failed(), hr = 0x%08x\n"), _riid.Data1, _riid.Data2, _riid.Data3, _riid.Data4[0], _riid.Data4[1], _riid.Data4[2], _riid.Data4[3], _riid.Data4[4], _riid.Data4[5], _riid.Data4[6], _riid.Data4[7], _hr ); \ RETURN(_hr); \ }
// Warning is display if HRESULT is not S_OK (0) or "_ok".
#define RRETURN1( _hr, _ok ) {\
RETURN(TraceHR( TEXT(__FILE__), __LINE__, g_szModule, TEXT(#_hr), \ ( ( _hr == _ok ) ? S_OK : _hr ) ) ); \ }
//
// Other
//
#define BOOLTOSTRING( _fBool ) ( !!(_fBool) ? g_szTrue : g_szFalse )
//
// Trace/Debug Functions - these do not exist in RETAIL.
//
void TraceMsg( DWORD dwCheckFlags, LPCSTR pszFormat, ... );
void TraceMsg( DWORD dwCheckFlags, LPCWSTR pszFormat, ... );
void DebugMsg( LPCSTR pszFormat, ... );
void DebugMsg( LPCWSTR pszFormat, ... );
void TraceMessage( LPCTSTR pszFile, const int uLine, LPCTSTR pszModule, DWORD dwCheckFlags, LPCTSTR pszFormat, ... );
void TraceMessageDo( LPCTSTR pszFile, const int uLine, LPCTSTR pszModule, DWORD dwCheckFlags, LPCTSTR pszFormat, LPCTSTR pszFunc, ... );
void DebugMessage( LPCTSTR pszFile, const int uLine, LPCTSTR pszModule, LPCTSTR pszFormat, ... );
void DebugMessageDo( LPCTSTR pszFile, const int uLine, LPCTSTR pszModule, LPCTSTR pszFormat, LPCTSTR pszFunc, ... );
BOOL AssertMessage( LPCTSTR pszFile, const int uLine, LPCTSTR pszModule, LPCTSTR pszfn, BOOL fTrue );
HRESULT TraceHR( LPCTSTR pszFile, const int uLine, LPCTSTR pszModule, LPCTSTR pszfn, HRESULT hr );
//
// Memory tracing functions - these are remapped to the "Global" memory
// functions when in RETAIL.
//
HGLOBAL DebugAlloc( LPCTSTR pszFile, const int uLine, LPCTSTR pszModule, UINT uFlags, DWORD dwBytes, LPCTSTR pszComment );
HGLOBAL DebugFree( HGLOBAL hMem );
// The memory functions don't exist in RETAIL.
HGLOBAL DebugMemoryAdd( HGLOBAL hglobal, LPCTSTR pszFile, const int uLine, LPCTSTR pszModule, UINT uFlags, DWORD dwBytes, LPCTSTR pszComment );
#define DebugMemoryAddHandle( _handle ) \
DebugMemoryAdd( _handle, TEXT(__FILE__), __LINE__, __MODULE__, GMEM_MOVEABLE, 0, TEXT("_handle") );
#define DebugMemoryAddAddress( _pv ) \
DebugMemoryAdd( _pv, TEXT(__FILE__), __LINE__, __MODULE__, GMEM_FIXED, 0, TEXT("_pv") );
#define TraceStrDup( _sz ) \
(LPTSTR) DebugMemoryAdd( StrDup( _sz ), TEXT(__FILE__), __LINE__, __MODULE__, GMEM_FIXED, 0, TEXT("StrDup( _sz )") );
void DebugMemoryDelete( HGLOBAL hglobal );
void DebugMemoryCheck( );
void DebugInitializeTraceFlags( );
#ifdef __cplusplus
extern void* __cdecl operator new( size_t nSize, LPCTSTR pszFile, const int iLine, LPCTSTR pszModule ); #define new new( TEXT(__FILE__), __LINE__, __MODULE__ )
#endif
//
//
#else // it's RETAIL ******************************************************
//
//
#pragma message("BUILD: RETAIL macros being built")
// Debugging -> NOPs
#define Assert( _fn )
#define DebugDo( _fn )
#define DebugMsgDo( _fn, _msg )
#define DEFINE_MODULE( _module )
#define DEFINE_THISCLASS( _class )
#define DEFINE_SUPER( _super )
#define BOOLTOSTRING( _fBool ) NULL
#define AssertMsg 1 ? (void)0 : (void)
#define TraceMsg 1 ? (void)0 : (void)
#define TraceMsgGUID( _f, _g )
#define DebugMsg 1 ? (void)0 : (void)
#define TraceMessage 1 ? (void)0 : (void)
#define DebugMessage 1 ? (void)0 : (void)
#define AssertMessage 1 ? (void)0 : (void)
#define TraceHR 1 ? (void)0 : (void)
#define TraceFunc 1 ? (void)0 : (void)
#define TraceClsFunc 1 ? (void)0 : (void)
#define TraceFuncExit()
#define DebugMemoryAddHandle( _handle )
#define DebugMemoryAddAddress( _pv )
#define INITIALIZE_TRACE_MEMORY_PROCESS
#define INITIALIZE_TRACE_MEMORY_THREAD
#define UNINITIALIZE_TRACE_MEMORY
#define DebugMemoryDelete( _h )
// Tracing -> just do operation
#define TraceDo( _fn ) _fn
#define TraceMsgDo( _fn, _msg ) _fn
#define TraceAssertIfZero( _fn ) _fn
// RETURN testing -> do retail
#define THR
#define RETURN( _fn ) return _fn
#define RRETURN( _fn ) return _fn
#define HRETURN( _hr ) return _hr
#define QIRETURN( _qi, _riid ) return _qi
// Memory Functions -> do retail
#define TraceAlloc( _flags, _size ) GlobalAlloc( _flags, _size )
#define TraceAllocString( _flags, _size ) (LPTSTR) GlobalAlloc( _flags, (_size) * sizeof(TCHAR))
#define TraceFree( _pv ) GlobalFree( _pv )
#define TraceStrDup( _sz ) StrDup( _sz )
#endif // DBG==1
#endif // _DEBUG_H_
|