//------------------------------------------------------------------------------ // File: WXDebug.h // // Desc: DirectShow base classes - provides debugging facilities. // //@@BEGIN_MSINTERNAL // // January 1995 // //@@END_MSINTERNAL // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ #ifndef __WXDEBUG__ #define __WXDEBUG__ // This library provides fairly straight forward debugging functionality, this // is split into two main sections. The first is assertion handling, there are // three types of assertions provided here. The most commonly used one is the // ASSERT(condition) macro which will pop up a message box including the file // and line number if the condition evaluates to FALSE. Then there is the // EXECUTE_ASSERT macro which is the same as ASSERT except the condition will // still be executed in NON debug builds. The final type of assertion is the // KASSERT macro which is more suitable for pure (perhaps kernel) filters as // the condition is printed onto the debugger rather than in a message box. // // The other part of the debug module facilties is general purpose logging. // This is accessed by calling DbgLog(). The function takes a type and level // field which define the type of informational string you are presenting and // it's relative importance. The type field can be a combination (one or more) // of LOG_TIMING, LOG_TRACE, LOG_MEMORY, LOG_LOCKING and LOG_ERROR. The level // is a DWORD value where zero defines highest important. Use of zero as the // debug logging level is to be encouraged ONLY for major errors or events as // they will ALWAYS be displayed on the debugger. Other debug output has it's // level matched against the current debug output level stored in the registry // for this module and if less than the current setting it will be displayed. // // Each module or executable has it's own debug output level for each of the // five types. These are read in when the DbgInitialise function is called // for DLLs linking to STRMBASE.LIB this is done automatically when the DLL // is loaded, executables must call it explicitely with the module instance // handle given to them through the WINMAIN entry point. An executable must // also call DbgTerminate when they have finished to clean up the resources // the debug library uses, once again this is done automatically for DLLs // These are the five different categories of logging information enum { LOG_TIMING = 0x01, // Timing and performance measurements LOG_TRACE = 0x02, // General step point call tracing LOG_MEMORY = 0x04, // Memory and object allocation/destruction LOG_LOCKING = 0x08, // Locking/unlocking of critical sections LOG_ERROR = 0x10, // Debug error notification LOG_CUSTOM1 = 0x20, LOG_CUSTOM2 = 0x40, LOG_CUSTOM3 = 0x80, LOG_CUSTOM4 = 0x100, LOG_CUSTOM5 = 0x200, }; #define LOG_FORCIBLY_SET 0x80000000 enum { CDISP_HEX = 0x01, CDISP_DEC = 0x02}; // For each object created derived from CBaseObject (in debug builds) we // create a descriptor that holds it's name (statically allocated memory) // and a cookie we assign it. We keep a list of all the active objects // we have registered so that we can dump a list of remaining objects typedef struct tag_ObjectDesc { const CHAR *m_szName; const WCHAR *m_wszName; DWORD m_dwCookie; tag_ObjectDesc *m_pNext; } ObjectDesc; #define DLLIMPORT __declspec(dllimport) #define DLLEXPORT __declspec(dllexport) #ifdef DEBUG #define NAME(x) TEXT(x) // These are used internally by the debug library (PRIVATE) void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax); void WINAPI DbgInitGlobalSettings(bool fTakeMax); void WINAPI DbgInitModuleSettings(bool fTakeMax); void WINAPI DbgInitModuleName(); DWORD WINAPI DbgRegisterObjectCreation( const CHAR *szObjectName, const WCHAR *wszObjectName); BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie); // These are the PUBLIC entry points BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level); void WINAPI DbgSetModuleLevel(DWORD Type,DWORD Level); void WINAPI DbgSetAutoRefreshLevels(bool fAuto); // Initialise the library with the module handle void WINAPI DbgInitialise(HINSTANCE hInst); void WINAPI DbgTerminate(); void WINAPI DbgDumpObjectRegister(); // Display error and logging to the user void WINAPI DbgAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); void WINAPI DbgBreakPoint(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); void WINAPI DbgBreakPoint(const TCHAR *pFileName,INT iLine,const TCHAR* szFormatString,...); void WINAPI DbgKernelAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); void WINAPI DbgLogInfo(DWORD Type,DWORD Level,const TCHAR *pFormat,...); #ifdef UNICODE void WINAPI DbgLogInfo(DWORD Type,DWORD Level,const CHAR *pFormat,...); void WINAPI DbgAssert(const CHAR *pCondition,const CHAR *pFileName,INT iLine); void WINAPI DbgBreakPoint(const CHAR *pCondition,const CHAR *pFileName,INT iLine); void WINAPI DbgKernelAssert(const CHAR *pCondition,const CHAR *pFileName,INT iLine); #endif void WINAPI DbgOutString(LPCTSTR psz); // Debug infinite wait stuff DWORD WINAPI DbgWaitForSingleObject(HANDLE h); DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount, CONST HANDLE *lpHandles, BOOL bWaitAll); void WINAPI DbgSetWaitTimeout(DWORD dwTimeout); #ifdef __strmif_h__ // Display a media type: Terse at level 2, verbose at level 5 void WINAPI DisplayType(LPTSTR label, const AM_MEDIA_TYPE *pmtIn); // Dump lots of information about a filter graph void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel); #endif #define KASSERT(_x_) if (!(_x_)) \ DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) // Break on the debugger without putting up a message box // message goes to debugger instead #define KDbgBreak(_x_) \ DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) // We chose a common name for our ASSERT macro, MFC also uses this name // So long as the implementation evaluates the condition and handles it // then we will be ok. Rather than override the behaviour expected we // will leave whatever first defines ASSERT as the handler (i.e. MFC) #ifndef ASSERT #define ASSERT(_x_) if (!(_x_)) \ DbgAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) #endif #define DbgAssertAligned( _ptr_, _alignment_ ) ASSERT( ((DWORD_PTR) (_ptr_)) % (_alignment_) == 0) // Put up a message box informing the user of a halt // condition in the program #define DbgBreak(_x_) \ DbgBreakPoint(TEXT(#_x_),TEXT(__FILE__),__LINE__) #define EXECUTE_ASSERT(_x_) ASSERT(_x_) #define DbgLog(_x_) DbgLogInfo _x_ // MFC style trace macros #define NOTE(_x_) DbgLog((LOG_TRACE,5,TEXT(_x_))) #define NOTE1(_x_,a) DbgLog((LOG_TRACE,5,TEXT(_x_),a)) #define NOTE2(_x_,a,b) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b)) #define NOTE3(_x_,a,b,c) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c)) #define NOTE4(_x_,a,b,c,d) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d)) #define NOTE5(_x_,a,b,c,d,e) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d,e)) #else // Retail builds make public debug functions inert - WARNING the source // files do not define or build any of the entry points in debug builds // (public entry points compile to nothing) so if you go trying to call // any of the private entry points in your source they won't compile #define NAME(_x_) ((TCHAR *) NULL) #define DbgInitialise(hInst) #define DbgTerminate() #define DbgLog(_x_) 0 #define DbgOutString(psz) #define DbgAssertAligned( _ptr_, _alignment_ ) 0 #define DbgRegisterObjectCreation(pObjectName) #define DbgRegisterObjectDestruction(dwCookie) #define DbgDumpObjectRegister() #define DbgCheckModuleLevel(Type,Level) #define DbgSetModuleLevel(Type,Level) #define DbgSetAutoRefreshLevels(fAuto) #define DbgWaitForSingleObject(h) WaitForSingleObject(h, INFINITE) #define DbgWaitForMultipleObjects(nCount, lpHandles, bWaitAll) \ WaitForMultipleObjects(nCount, lpHandles, bWaitAll, INFINITE) #define DbgSetWaitTimeout(dwTimeout) #define KDbgBreak(_x_) #define DbgBreak(_x_) #define KASSERT(_x_) ((void)0) #ifndef ASSERT #define ASSERT(_x_) ((void)0) #endif #define EXECUTE_ASSERT(_x_) ((void)(_x_)) // MFC style trace macros #define NOTE(_x_) ((void)0) #define NOTE1(_x_,a) ((void)0) #define NOTE2(_x_,a,b) ((void)0) #define NOTE3(_x_,a,b,c) ((void)0) #define NOTE4(_x_,a,b,c,d) ((void)0) #define NOTE5(_x_,a,b,c,d,e) ((void)0) #define DisplayType(label, pmtIn) ((void)0) #define DumpGraph(pGraph, label) ((void)0) #endif // Checks a pointer which should be non NULL - can be used as follows. #define CheckPointer(p,ret) {if((p)==NULL) return (ret);} // HRESULT Foo(VOID *pBar) // { // CheckPointer(pBar,E_INVALIDARG) // } // // Or if the function returns a boolean // // BOOL Foo(VOID *pBar) // { // CheckPointer(pBar,FALSE) // } // These validate pointers when symbol VFWROBUST is defined // This will normally be defined in debug not retail builds #ifdef DEBUG #define VFWROBUST #endif #ifdef VFWROBUST #define ValidateReadPtr(p,cb) \ {if(IsBadReadPtr((PVOID)p,cb) == TRUE) \ DbgBreak("Invalid read pointer");} #define ValidateWritePtr(p,cb) \ {if(IsBadWritePtr((PVOID)p,cb) == TRUE) \ DbgBreak("Invalid write pointer");} #define ValidateReadWritePtr(p,cb) \ {ValidateReadPtr(p,cb) ValidateWritePtr(p,cb)} #define ValidateStringPtr(p) \ {if(IsBadStringPtr((LPCTSTR)p,INFINITE) == TRUE) \ DbgBreak("Invalid string pointer");} #define ValidateStringPtrA(p) \ {if(IsBadStringPtrA((LPCSTR)p,INFINITE) == TRUE) \ DbgBreak("Invalid ANSI string pointer");} #define ValidateStringPtrW(p) \ {if(IsBadStringPtrW((LPCWSTR)p,INFINITE) == TRUE) \ DbgBreak("Invalid UNICODE string pointer");} #else #define ValidateReadPtr(p,cb) 0 #define ValidateWritePtr(p,cb) 0 #define ValidateReadWritePtr(p,cb) 0 #define ValidateStringPtr(p) 0 #define ValidateStringPtrA(p) 0 #define ValidateStringPtrW(p) 0 #endif #ifdef _OBJBASE_H_ // Outputting GUID names. If you want to include the name // associated with a GUID (eg CLSID_...) then // // GuidNames[yourGUID] // // Returns the name defined in uuids.h as a string typedef struct { CHAR *szName; GUID guid; } GUID_STRING_ENTRY; class CGuidNameList { public: CHAR *operator [] (const GUID& guid); }; extern CGuidNameList GuidNames; #endif #ifndef REMIND // REMIND macro - generates warning as reminder to complete coding // (eg) usage: // // #pragma message (REMIND("Add automation support")) #define QUOTE(x) #x #define QQUOTE(y) QUOTE(y) #define REMIND(str) __FILE__ "(" QQUOTE(__LINE__) ") : " str #endif // Method to display objects in a useful format // // eg If you want to display a LONGLONG ll in a debug string do (eg) // // DbgLog((LOG_TRACE, n, TEXT("Value is %s"), (LPCTSTR)CDisp(ll, CDISP_HEX))); class CDispBasic { public: CDispBasic() { m_pString = m_String; }; ~CDispBasic(); protected: PTCHAR m_pString; // normally points to m_String... unless too much data TCHAR m_String[50]; }; class CDisp : public CDispBasic { public: CDisp(LONGLONG ll, int Format = CDISP_HEX); // Display a LONGLONG in CDISP_HEX or CDISP_DEC form CDisp(REFCLSID clsid); // Display a GUID CDisp(double d); // Display a floating point number #ifdef __strmif_h__ #ifdef __STREAMS__ CDisp(CRefTime t); // Display a Reference Time #endif CDisp(IPin *pPin); // Display a pin as {filter clsid}(pin name) CDisp(IUnknown *pUnk); // Display a filter or pin #endif // __strmif_h__ ~CDisp(); // Implement cast to (LPCTSTR) as parameter to logger operator LPCTSTR() { return (LPCTSTR)m_pString; }; }; #if defined(DEBUG) class CAutoTrace { private: const TCHAR* _szBlkName; const int _level; static const TCHAR _szEntering[]; static const TCHAR _szLeaving[]; public: CAutoTrace(const TCHAR* szBlkName, const int level = 15) : _szBlkName(szBlkName), _level(level) {DbgLog((LOG_TRACE, _level, _szEntering, _szBlkName));} ~CAutoTrace() {DbgLog((LOG_TRACE, _level, _szLeaving, _szBlkName));} }; #define AMTRACE(_x_) CAutoTrace __trace _x_ #else #define AMTRACE(_x_) #endif #endif // __WXDEBUG__