385 lines
13 KiB
C++
385 lines
13 KiB
C++
//------------------------------------------------------------------------------
|
|
// 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__
|
|
|
|
|