244 lines
6.2 KiB
C
244 lines
6.2 KiB
C
|
//
|
||
|
// 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_
|