|
|
//
// Copyright 1997 - Microsoft
//
//
// QI.H - Handles the query interface functions
//
#ifndef _QI_H_
#define _QI_H_
///////////////////////////////////////
//
// QueryInterface Definitions
//
typedef struct { LPUNKNOWN pvtbl; // "punk" - pointer to a specific interface
const struct _GUID *riid; // GUID of interfaace
#ifdef DEBUG
LPCTSTR pszName; // Text name of interface - used to make sure tables are consistant
DWORD cFunctions; // Number of function entries in this interface's vtbl.
#endif // DEBUG
} QITABLE, *LPQITABLE, QIENTRY, *LPQIENTRY;
///////////////////////////////////////
//
// Quick-Lookup table declaration macro
//
#define DECLARE_QITABLE( _Class) QITABLE _QITable[ARRAYSIZE(QIT_##_Class)];
///////////////////////////////////////
//
// Quick-Lookup table construction macros
//
#ifdef DEBUG
#define DEFINE_QI( _iface, _name, _nFunctions ) \
{ NULL, &_iface, TEXT(#_name), _nFunctions }, #else // RETAIL
#define DEFINE_QI( _iface, _name, _nFunctions ) \
{ NULL, &_iface }, #endif // DEBUG
#define BEGIN_QITABLE( _Class ) \
static const QITABLE QIT_##_Class[] = { DEFINE_QI( IID_IUnknown, IUnknown, 0 )
#define END_QITABLE { NULL, NULL } };
///////////////////////////////////////
//
// Common Quick-Lookup QueryInterface( )
//
extern HRESULT QueryInterface( LPVOID that, LPQITABLE pQI, REFIID riid, LPVOID *ppv );
#ifdef DEBUG
///////////////////////////////////////
//
// BEGIN DEBUG
//
#ifndef NO_TRACE_INTERFACES
///////////////////////////////////////
//
// BEGIN DEBUG INTERFACE TRACKING
//
#pragma message("BUILD: Interface tracking enabled")
///////////////////////////////////////
//
// Debug Quick-Lookup QI Interface Macros
//
// Begins construction of the runtime Quick-Lookup table.
// Adds IUnknown by default.
#define BEGIN_QITABLE_IMP( _Class, _IUnknownPrimaryInterface ) \
int _i = 0; \ CopyMemory( _QITable, &QIT_##_Class, sizeof( QIT_##_Class ) ); \ _QITable[_i].pvtbl = (_IUnknownPrimaryInterface *) this;
// Checks that the QIENTRY matches the current QITABLE_IMP.
#define QITABLE_IMP( _Interface ) \
_i++; \ _QITable[_i].pvtbl = (_Interface *) this; \ { int ___i = lstrcmp( TEXT(#_Interface), _QITable[_i].pszName ); \ AssertMsg( ___i == 0, \ "DEFINE_QIs and QITABLE_IMPs don't match. Incorrect order.\n" ); }
// Verifies that the number of entries in the QITABLE match
// the number of QITABLE_IMP in the runtime section
#define END_QITABLE_IMP( _Class ) \
AssertMsg( _i == ( ARRAYSIZE( QIT_##_Class ) - 2 ), \ "The number of DEFINE_QIs and QITABLE_IMPs don't match.\n" ); \ LPVOID pCITracker; \ TraceMsgDo( pCITracker = CITracker_CreateInstance( _QITable ), "0x%08x" );
///////////////////////////////////////
//
// 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 { LPCTSTR pszInterface; UINT cRef; LPUNKNOWN punk; LPVTBL pOrginalVtbl; LPUNKNOWN pITracker; // These must be last and in this order QI, AddRef, Release.
LPFNQUERYINTERFACE lpfnQueryInterface; LPFNADDREF lpfnAddRef; LPFNRELEASE lpfnRelease; } VTBL2, *LPVTBL2;
#define VTBL2OFFSET ( sizeof( VTBL2 ) - ( 3 * sizeof(LPVOID) ) )
///////////////////////////////////////
//
// CITracker Functions
//
LPVOID CITracker_CreateInstance( LPQITABLE pQITable ); // QI Table of the object
///////////////////////////////////////
//
// CCITracker Class
//
//
class CITracker: public IUnknown { private: // Members
VTBL2 _vtbl;
private: // Methods
CITracker( ); ~CITracker( ); STDMETHOD(Init)( LPQITABLE pQITable );
public: // Methods
friend LPVOID CITracker_CreateInstance( LPQITABLE pQITable );
// IUnknown (Translates to IUnknown2)
STDMETHOD(QueryInterface)( REFIID riid, LPVOID *ppv ); STDMETHOD_(ULONG, AddRef)(void); STDMETHOD_(ULONG, Release)(void);
// IUnknown2 (Real Implementation)
STDMETHOD(_QueryInterface)( REFIID riid, LPVOID *ppv ); STDMETHOD_(ULONG, _AddRef)(void); STDMETHOD_(ULONG, _Release)(void); };
typedef CITracker* LPITRACKER;
//
// END DEBUG INTERFACE TRACKING
//
///////////////////////////////////////
#else // !NO_TRACE_INTERFACES
///////////////////////////////////////
//
// BEGIN DEBUG WITHOUT INTERFACE TRACKING
//
// Begins construction of the runtime Quick-Lookup table.
// Adds IUnknown by default.
#define BEGIN_QITABLE_IMP( _Class, _IUnknownPrimaryInterface ) \
int _i = 0; \ LPVOID pCITracker; \ CopyMemory( _QITable, &QIT_##_Class, sizeof( QIT_##_Class ) ); \ _QITable[_i].pvtbl = (_IUnknownPrimaryInterface *) this;
// Adds a CITracker to interface and checks that the QIENRTY
// matches the current QITABLE_IMP.
#define QITABLE_IMP( _Interface ) \
_i++; \ _QITable[_i].pvtbl = (_Interface *) this; \ { int ___i = lstrcmp( TEXT(#_Interface), _QITable[_i].pszName ); \ AssertMsg( ___i == 0, \ "DEFINE_QIs and QITABLE_IMPs don't match. Incorrect order.\n" ); }
// Verifies that the number of entries in the QITABLE match
// the number of QITABLE_IMP in the runtime section
#define END_QITABLE_IMP( _Class )\
AssertMsg( _i == ( ARRAYSIZE( QIT_##_Class ) - 2 ), \ "The number of DEFINE_QIs and QITABLE_IMPs don't match.\n" );
//
// END DEBUG INTERFACE TRACKING
//
///////////////////////////////////////
#endif // NO_TRACE_INTERFACES
#else
///////////////////////////////////////
//
// BEGIN RETAIL
//
//
// Debug Macros -> Retail Code
//
#define BEGIN_QITABLE_IMP( _Class, _IUnknownPrimaryInterface ) \
int _i = 0; \ CopyMemory( _QITable, &QIT_##_Class, sizeof( QIT_##_Class ) ); \ _QITable[_i++].pvtbl = (_IUnknownPrimaryInterface *) this;
#define QITABLE_IMP( _Interface ) \
_QITable[_i++].pvtbl = (_Interface *) this;
#define END_QITABLE_IMP( _Class )
//
// END RETAIL
//
///////////////////////////////////////
#endif // DEBUG
#endif _QI_H_
|