//------------------------------------------------------------------------------ | |
// File: WXDebug.h | |
// | |
// Desc: DirectShow base classes - provides debugging facilities. | |
// | |
// 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 { | |
LPCSTR m_szName; | |
LPCWSTR 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( | |
LPCSTR szObjectName, LPCWSTR 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(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine); | |
void WINAPI DbgBreakPoint(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine); | |
void WINAPI DbgBreakPoint(LPCTSTR pFileName,INT iLine,__format_string LPCTSTR szFormatString,...); | |
void WINAPI DbgKernelAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine); | |
void WINAPI DbgLogInfo(DWORD Type,DWORD Level,__format_string LPCTSTR pFormat,...); | |
#ifdef UNICODE | |
void WINAPI DbgLogInfo(DWORD Type,DWORD Level,__format_string LPCSTR pFormat,...); | |
void WINAPI DbgAssert(LPCSTR pCondition,LPCSTR pFileName,INT iLine); | |
void WINAPI DbgBreakPoint(LPCSTR pCondition,LPCSTR pFileName,INT iLine); | |
void WINAPI DbgKernelAssert(LPCSTR pCondition,LPCSTR pFileName,INT iLine); | |
#endif | |
void WINAPI DbgOutString(LPCTSTR psz); | |
// Debug infinite wait stuff | |
DWORD WINAPI DbgWaitForSingleObject(HANDLE h); | |
DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount, | |
__in_ecount(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(LPCTSTR 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_) ((LPTSTR) 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) | |
// } | |
#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 | |
#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: | |
LPCTSTR _szBlkName; | |
const int _level; | |
static const TCHAR _szEntering[]; | |
static const TCHAR _szLeaving[]; | |
public: | |
CAutoTrace(LPCTSTR szBlkName, const int level = 15) | |
: _szBlkName(szBlkName), _level(level) | |
{DbgLog((LOG_TRACE, _level, _szEntering, _szBlkName));} | |
~CAutoTrace() | |
{DbgLog((LOG_TRACE, _level, _szLeaving, _szBlkName));} | |
}; | |
#if defined (__FUNCTION__) | |
#define AMTRACEFN() CAutoTrace __trace(TEXT(__FUNCTION__)) | |
#define AMTRACE(_x_) CAutoTrace __trace(TEXT(__FUNCTION__)) | |
#else | |
#define AMTRACE(_x_) CAutoTrace __trace _x_ | |
#define AMTRACEFN() | |
#endif | |
#else | |
#define AMTRACE(_x_) | |
#define AMTRACEFN() | |
#endif | |
#endif // __WXDEBUG__ | |