/**************************************************************************** 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[]; // 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); \ 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 ) 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( _fn, _riid ) { \ if ( !!( TF_QUERYINTERFACE & g_dwTraceFlags ) ) { \ RETURN(TraceHR( TEXT(__FILE__), __LINE__, g_szModule, TEXT(#_fn), _fn )); \ } else if ( hr ) \ DebugMessage( TEXT(__FILE__), __LINE__, g_szModule, TEXT("HRESULT: QueryInterface({%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x}) failed()\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] ); \ RETURN(_fn); \ } // 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 ) \ DebugMemoryAdd( StrDup( _sz ), TEXT(__FILE__), __LINE__, __MODULE__, GMEM_FIXED, 0, TEXT("StrDup(") TEXT(#_sz) TEXT(")") ); void DebugMemoryDelete( HGLOBAL hglobal ); void DebugMemoryCheck( ); #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 ****************************************************** // // // 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 ErrorMsg 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 ) GlobalAlloc( _flags, (_size) * sizeof(TCHAR) ) #define TraceFree( _pv ) GlobalFree( _pv ) #define TraceStrDup( _sz ) StrDup( _sz ) #endif // DBG==1 #endif // _DEBUG_H_