389 lines
12 KiB
C
389 lines
12 KiB
C
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Copyright (c) 1999 - 2000 Microsoft Corporation
|
||
|
//
|
||
|
// Module Name:
|
||
|
// CITracker.H
|
||
|
//
|
||
|
// Description:
|
||
|
// Implementation of a COM interface tracker.
|
||
|
//
|
||
|
// [Documentation:]
|
||
|
// Debugging.PPT - A power-point presentation of the debug utilities.
|
||
|
//
|
||
|
// Maintained By:
|
||
|
// Geoffrey Pease (gpease) 19-NOV-1999
|
||
|
//
|
||
|
// Notes:
|
||
|
// This is X86 specific for now. It can be adapted for other platforms
|
||
|
// as required. Since today, most of our developement is done on the
|
||
|
// X86 platform, there is not a need to do this (yet).
|
||
|
//
|
||
|
// Define NO_TRACE_INTERFACES to disable interface tracking in DEBUG
|
||
|
// builds.
|
||
|
//
|
||
|
// Define TRACE_INTERFACES_ENABLED to enable interface tracking in RETAIL
|
||
|
// builds.
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
//
|
||
|
// Combine this complex expression in to one simple #define.
|
||
|
//
|
||
|
#if ( DBG==1 || defined( _DEBUG ) ) && !defined( NO_TRACE_INTERFACES )
|
||
|
#define TRACE_INTERFACES_ENABLED
|
||
|
#endif
|
||
|
|
||
|
#if defined( _X86_ ) && defined( TRACE_INTERFACES_ENABLED )
|
||
|
#define FULL_TRACE_INTERFACES_ENABLED
|
||
|
#endif
|
||
|
|
||
|
#if defined( TRACE_INTERFACES_ENABLED )
|
||
|
///////////////////////////////////////
|
||
|
//
|
||
|
// BEGIN DEBUG INTERFACE TRACKING
|
||
|
//
|
||
|
|
||
|
#pragma message("BUILD: Interface Tracking Enabled")
|
||
|
|
||
|
//
|
||
|
// DLL Interface Table Macros
|
||
|
//
|
||
|
#define BEGIN_INTERFACETABLE const INTERFACE_TABLE g_itTable = {
|
||
|
#define DEFINE_INTERFACE( _iid, _name, _count ) { &_iid, TEXT(_name), _count },
|
||
|
#define END_INTERFACETABLE { NULL, NULL, NULL } };
|
||
|
|
||
|
///////////////////////////////////////
|
||
|
//
|
||
|
// TraceInterface definitions
|
||
|
//
|
||
|
typedef struct {
|
||
|
const struct _GUID * riid;
|
||
|
LPCTSTR pszName;
|
||
|
ULONG cFunctions;
|
||
|
} INTERFACE_TABLE[], INTERFACE_TABLE_ENTRY, * LPINTERFACE_TABLE_ENTRY;
|
||
|
|
||
|
//
|
||
|
// Interface Table
|
||
|
//
|
||
|
// This table is used in builds in which interface tracking was turned on. It
|
||
|
// is used to map an name with a particular IID. It also helps the CITracker
|
||
|
// determine the size of the interfaces Vtable to mimic (haven't figured out
|
||
|
// a runtime or compile time way to do this).
|
||
|
//
|
||
|
extern const INTERFACE_TABLE g_itTable;
|
||
|
|
||
|
///////////////////////////////////////
|
||
|
//
|
||
|
// IID --> Name lookup stuff
|
||
|
//
|
||
|
#if defined( DEBUG )
|
||
|
static const cchGUID_STRING_SIZE = sizeof("{12345678-1234-1234-1234-123456789012}");
|
||
|
|
||
|
#define PszTraceFindInterface( _riid, _szguid ) \
|
||
|
( g_tfModule ? PszDebugFindInterface( _riid, _szguid ) : TEXT("riid") )
|
||
|
|
||
|
LPCTSTR
|
||
|
PszDebugFindInterface(
|
||
|
REFIID riidIn,
|
||
|
LPTSTR pszGuidBufOut
|
||
|
);
|
||
|
#endif // DEBUG
|
||
|
|
||
|
//
|
||
|
// END DEBUG INTERFACE TRACKING
|
||
|
//
|
||
|
///////////////////////////////////////
|
||
|
#else // !TRACE_INTERFACES_ENABLED
|
||
|
///////////////////////////////////////
|
||
|
//
|
||
|
// BEGIN DEBUG WITHOUT INTERFACE TRACKING
|
||
|
//
|
||
|
|
||
|
#define BEGIN_INTERFACETABLE
|
||
|
#define DEFINE_INTERFACE( _iid, _name, _count )
|
||
|
#define END_INTERFACETABLE
|
||
|
|
||
|
//
|
||
|
// END DEBUG WITHOUT INTERFACE TRACKING
|
||
|
//
|
||
|
///////////////////////////////////////
|
||
|
#endif // TRACE_INTERFACES_ENABLED
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#if defined( FULL_TRACE_INTERFACES_ENABLED )
|
||
|
///////////////////////////////////////
|
||
|
//
|
||
|
// BEGIN DEBUG INTERFACE TRACKING
|
||
|
//
|
||
|
#pragma message("BUILD: Full Interface Tracking Enabled")
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// MACRO
|
||
|
// _interface *
|
||
|
// TraceInterface(
|
||
|
// _nameIn,
|
||
|
// _interface,
|
||
|
// _punkIn,
|
||
|
// _addrefIn
|
||
|
// )
|
||
|
//
|
||
|
// Description:
|
||
|
// This is the macro wrapper for DebugTrackInterface( ) which is only
|
||
|
// defined in DEBUG builds. Using the TraceInterface( ) macro eliminates
|
||
|
// the need for specifying compile time parameters as well as the
|
||
|
// #ifdef/#endif definitions around the call.
|
||
|
//
|
||
|
// This "routine" creates a CITracker for the interface specified by
|
||
|
// _interface and returns a new punk to the interface. You specify the
|
||
|
// initial ref count on the interface using the _addrefIn parameter. You
|
||
|
// can assign a name to the object that the interface refereneces in the
|
||
|
// _nameIn parameter. The returned punk will be cast to the _interface
|
||
|
// parameter.
|
||
|
//
|
||
|
// If there is insufficent memory to create the CITracker, the _punkIn
|
||
|
// will be returned instead. There is no need to check the output for
|
||
|
// failures as they are all handle internally to provide worry-free use.
|
||
|
//
|
||
|
// If you are getting an AV after adding tracing to the interface, this
|
||
|
// usually indicates that the Interface Table entry for that interface
|
||
|
// is incorrect. Double check the number of methods on the interface
|
||
|
// against the tables.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// _nameIn - Name of the object this interface references (string).
|
||
|
// _interface - Name of the interface (typedef).
|
||
|
// _punkIn - Pointer to interface to track
|
||
|
// _addrefIn - Initial reference count on the interface.
|
||
|
//
|
||
|
// Return Values:
|
||
|
// a VALID _interface pointer
|
||
|
// Points to the CITracker that can be used as if it were the
|
||
|
// orginal _punkIn. If there was insufficent memory, the orginal
|
||
|
// _punkIn will be returned.
|
||
|
//
|
||
|
// NOTES:
|
||
|
// _addrefIn should be 0 if your going to be giving out the interface
|
||
|
// from your QueryInterface routine if you AddRef( ) before giving it
|
||
|
// out (typical QueryInterface( ) routines do this ).
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////////////
|
||
|
#define TraceInterface( _nameIn, _interface, _punkIn, _addrefIn ) \
|
||
|
reinterpret_cast<_interface*>( \
|
||
|
DebugTrackInterface( TEXT(__FILE__), \
|
||
|
__LINE__, \
|
||
|
__MODULE__, \
|
||
|
_nameIn, \
|
||
|
IID_##_interface, \
|
||
|
static_cast<_interface*>( _punkIn), \
|
||
|
_addrefIn \
|
||
|
) )
|
||
|
|
||
|
///////////////////////////////////////
|
||
|
//
|
||
|
// CITracker Structures
|
||
|
//
|
||
|
typedef HRESULT (CALLBACK *LPFNQUERYINTERFACE)(
|
||
|
LPUNKNOWN punk,
|
||
|
REFIID riid,
|
||
|
LPVOID* ppv );
|
||
|
|
||
|
typedef ULONG (CALLBACK *LPFNADDREF)(
|
||
|
LPUNKNOWN punk );
|
||
|
|
||
|
typedef ULONG (CALLBACK *LPFNRELEASE)(
|
||
|
LPUNKNOWN punk );
|
||
|
|
||
|
typedef struct __vtbl {
|
||
|
LPFNQUERYINTERFACE lpfnQueryInterface;
|
||
|
LPFNADDREF lpfnAddRef;
|
||
|
LPFNRELEASE lpfnRelease;
|
||
|
} VTBL, *LPVTBL;
|
||
|
|
||
|
typedef struct __vtbl2 {
|
||
|
ULONG cRef;
|
||
|
LPUNKNOWN punk;
|
||
|
LPCTSTR pszInterface;
|
||
|
DWORD dwSize;
|
||
|
LPVTBL pNewVtbl;
|
||
|
// These must be last and in this order: QI, AddRef, Release.
|
||
|
LPFNQUERYINTERFACE lpfnQueryInterface;
|
||
|
LPFNADDREF lpfnAddRef;
|
||
|
LPFNRELEASE lpfnRelease;
|
||
|
// additional vtbl entries hang off the end
|
||
|
} VTBL2, *LPVTBL2;
|
||
|
|
||
|
#define VTBL2OFFSET ( sizeof( VTBL2 ) - ( 3 * sizeof(LPVOID) ) )
|
||
|
|
||
|
///////////////////////////////////////
|
||
|
//
|
||
|
// CITracker Functions
|
||
|
//
|
||
|
LPUNKNOWN
|
||
|
DebugTrackInterface(
|
||
|
LPCTSTR pszFileIn,
|
||
|
const int nLineIn,
|
||
|
LPCTSTR pszModuleIn,
|
||
|
LPCTSTR pszNameIn,
|
||
|
REFIID riidIn,
|
||
|
LPUNKNOWN pvtblIn,
|
||
|
LONG cRefIn
|
||
|
);
|
||
|
|
||
|
///////////////////////////////////////
|
||
|
//
|
||
|
// interface IUnknownTracker
|
||
|
//
|
||
|
//
|
||
|
class
|
||
|
IUnknownTracker :
|
||
|
public IUnknown
|
||
|
{
|
||
|
public:
|
||
|
STDMETHOD(QueryInterface)( REFIID riid, LPVOID *ppv );
|
||
|
STDMETHOD_(ULONG, AddRef)( void );
|
||
|
STDMETHOD_(ULONG, Release)( void );
|
||
|
STDMETHOD_(void, Stub3 )( void );
|
||
|
STDMETHOD_(void, Stub4 )( void );
|
||
|
STDMETHOD_(void, Stub5 )( void );
|
||
|
STDMETHOD_(void, Stub6 )( void );
|
||
|
STDMETHOD_(void, Stub7 )( void );
|
||
|
STDMETHOD_(void, Stub8 )( void );
|
||
|
STDMETHOD_(void, Stub9 )( void );
|
||
|
STDMETHOD_(void, Stub10 )( void );
|
||
|
STDMETHOD_(void, Stub11 )( void );
|
||
|
STDMETHOD_(void, Stub12 )( void );
|
||
|
STDMETHOD_(void, Stub13 )( void );
|
||
|
STDMETHOD_(void, Stub14 )( void );
|
||
|
STDMETHOD_(void, Stub15 )( void );
|
||
|
STDMETHOD_(void, Stub16 )( void );
|
||
|
STDMETHOD_(void, Stub17 )( void );
|
||
|
STDMETHOD_(void, Stub18 )( void );
|
||
|
STDMETHOD_(void, Stub19 )( void );
|
||
|
STDMETHOD_(void, Stub20 )( void );
|
||
|
STDMETHOD_(void, Stub21 )( void );
|
||
|
STDMETHOD_(void, Stub22 )( void );
|
||
|
STDMETHOD_(void, Stub23 )( void );
|
||
|
STDMETHOD_(void, Stub24 )( void );
|
||
|
STDMETHOD_(void, Stub25 )( void );
|
||
|
STDMETHOD_(void, Stub26 )( void );
|
||
|
STDMETHOD_(void, Stub27 )( void );
|
||
|
STDMETHOD_(void, Stub28 )( void );
|
||
|
STDMETHOD_(void, Stub29 )( void );
|
||
|
STDMETHOD_(void, Stub30 )( void );
|
||
|
|
||
|
}; //*** interface IUnknownTracker
|
||
|
|
||
|
///////////////////////////////////////
|
||
|
//
|
||
|
// interface IDeadObjTracker
|
||
|
//
|
||
|
class
|
||
|
IDeadObjTracker
|
||
|
{
|
||
|
private: // Members
|
||
|
VTBL2 m_vtbl;
|
||
|
|
||
|
public:
|
||
|
STDMETHOD( Stub0 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub1 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub2 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub3 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub4 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub5 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub6 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub7 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub8 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub9 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub10 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub11 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub12 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub13 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub14 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub15 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub16 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub17 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub18 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub19 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub20 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub21 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub22 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub23 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub24 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub25 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub26 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub27 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub28 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub29 )( LPVOID* punk );
|
||
|
STDMETHOD( Stub30 )( LPVOID* punk );
|
||
|
|
||
|
}; //*** interface IDeadObject
|
||
|
|
||
|
|
||
|
///////////////////////////////////////
|
||
|
//
|
||
|
// CITracker Class
|
||
|
//
|
||
|
class
|
||
|
CITracker:
|
||
|
public IUnknownTracker
|
||
|
{
|
||
|
private: // Members
|
||
|
VTBL2 m_vtbl;
|
||
|
|
||
|
private: // Methods
|
||
|
CITracker( );
|
||
|
~CITracker( );
|
||
|
STDMETHOD(Init)( LPUNKNOWN * ppunkOut,
|
||
|
LPUNKNOWN punkIn,
|
||
|
const INTERFACE_TABLE_ENTRY * piteIn,
|
||
|
LPCTSTR pszNameIn,
|
||
|
LONG cRefIn
|
||
|
);
|
||
|
|
||
|
public: // Methods
|
||
|
friend LPUNKNOWN DebugTrackInterface( LPCTSTR pszFileIn,
|
||
|
const int nLineIn,
|
||
|
LPCTSTR pszModuleIn,
|
||
|
LPCTSTR pszNameIn,
|
||
|
REFIID riidIn,
|
||
|
LPUNKNOWN pvtblIn,
|
||
|
LONG cRefIn
|
||
|
);
|
||
|
|
||
|
// IUnknown
|
||
|
STDMETHOD(QueryInterface)( REFIID riid, LPVOID *ppv );
|
||
|
STDMETHOD_(ULONG, AddRef)(void);
|
||
|
STDMETHOD_(ULONG, Release)(void);
|
||
|
|
||
|
}; //*** class CITracker
|
||
|
|
||
|
//
|
||
|
// END DEBUG WITH FULL INTERFACE TRACKING
|
||
|
//
|
||
|
///////////////////////////////////////
|
||
|
#else // !FULL_TRACE_INTERFACES_ENABLED
|
||
|
///////////////////////////////////////
|
||
|
//
|
||
|
// BEGIN DEBUG WITHOUT FULL INTERFACE TRACKING
|
||
|
//
|
||
|
|
||
|
#ifdef _X86_
|
||
|
#define TraceInterface( _nameIn, _interface, _punkIn, _faddrefIn ) static_cast<##_interface *>( _punkIn )
|
||
|
#else
|
||
|
#define TraceInterface( _nameIn, _interface, _punkIn, _faddrefIn ) static_cast<##_interface *>( _punkIn )
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// END DEBUG WITHOUT FULL INTERFACE TRACKING
|
||
|
//
|
||
|
///////////////////////////////////////
|
||
|
#endif // FULL_TRACE_INTERFACES_ENABLED
|