////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 1999-2002 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: // David Potter (DavidP) 25-MAR-2002 // 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; LPCWSTR 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 ) : L"riid" ) LPCWSTR PszDebugFindInterface( REFIID riidIn, LPWSTR 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; LPCWSTR 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( LPCWSTR pszFileIn, const int nLineIn, LPCWSTR pszModuleIn, LPCWSTR 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, LPCWSTR pszNameIn, LONG cRefIn ); public: // Methods friend LPUNKNOWN DebugTrackInterface( LPCWSTR pszFileIn, const int nLineIn, LPCWSTR pszModuleIn, LPCWSTR 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