QueryInterface, , , C++. , , . . , , IID - , - . , QueryInterface, , , if, static_cast (static_cast , vptr).
QueryInterface, , . , IID , vptr . , , . inttable.h, :
// inttable.h (book-specific header file) // inttable.h ( , ) // typedef for extensibility function // typedef typedef HRESULT (*INTERFACE_FINDER) (void *pThis, DWORD dwData, REFIID riid, void **ppv); // pseudo-function to indicate entry is just offset // , // #define ENTRY_IS_OFFSET INTERFACE_FINDER(-1) // basic table layout // typedef struct INTERFACE_ENTRY { const IID * pIID; // the IID to match // IID INTERFACE_FINDER pfnFinder; // finder DWORD dwData; // offset/aux data // offset/aux } INTERFACE_ENTRY;
:
// Inttable.h (book-specific header file) // Inttable.h ( , ) #define BASE_OFFSET(ClassName, BaseName) \ (DWORD(static_cast<BaseName*>(reinterpret_cast\ <ClassName*>(0x10000000))) - 0 10000000) #define BEGIN_INTERFACE_TABLE(ClassName) \ typedef ClassName _ITCls;\ const INTERFACE_ENTRY *GetInterfaceTable(void) {\ static const INTERFACE_ENTRY table [] = {\ #define IMPLEMENTS_INTERFACE(Itf) \ {&IID_##Itf,ENTRY_IS_OFFSET,BASE_OFFSET(_ITCls,Itf)}, #define IMPLEMENTS_INTERFACE_AS(req, Itf) \ {&IID_##req,ENTRY_IS_OFFSET, BASE_OFFSET(_ITCls, Itf)}, #define END_INTERFACE_TABLE() \ { 0, 0, 0 } }; return table; }
, , , QueryInterface. Inttable.h:
// inttable.cpp (book-specific source file) // inttable.h ( , ) HRESULT InterfaceTableQueryInterface(void *pThis, const INTERFACE_ENTRY *pTable, REFIID riid, void **ppv) { if (InlineIsEqualGUID(riid, IID_IUnknown)) { // first entry must be an offset // *ppv = (char*)pThis + pTable->dwData; ((Unknown*) (*ppv))->AddRef () ; // A2 return S_OK; } else { HRESULT hr = E_NOINTERFACE; while (pTable->pfnFinder) { // null fn ptr == EOT if (!pTable->pIID || InlineIsEqualGUID(riid,*pTable->pIID)) { if (pTable->pfnFinder == ENTRY_IS_OFFSET) { *ppv = (char*)pThis + pTable->dwData; ((IUnknown*)(*ppv))->AddRef(); // A2 hr = S_OK; break; } else { hr = pTable->pfnFinder(pThis, pTable->dwData, riid, ppv); if (hr == S_OK) break; } } pTable++; } if (hr != S_OK) *ppv = 0; return hr; } }
, InterfaceTableQueryInterface , IID, , . IsEqualGUID, , 20-30 , . InterfaceTableQueryInterface , .
C++, , - . impunk.h QueryInterface, AddRef Release , :
// impunk.h (book-specific header file) // impunk.h ( , ) // AUTO_LONG is just a long that constructs to zero // AUTO_LONG - long, , // struct AUTO_LONG { LONG value; AUTO_LONG (void) : value (0) {} }; #define IMPLEMENT_UNKNOWN(ClassName) \ AUTO_LONG m_cRef;\ STDMETHODIMP QueryInterface(REFIID riid, void **ppv){\ return InterfaceTableQueryInterface(this,\ GetInterfaceTable(), riid, ppv);\ }\ STDMETHODIMP_(ULONG) AddRef(void) { \ return InterlockedIncrement(&m_cRef.value); \ }\ STDMETHODIMP_(ULONG) Release(void) {\ ULONG res = InterlockedDecrement(&m_cRef.value) ;\ if (res == 0) \ delete this;\ return res;\ }\
, .
PugCat, , QueryInterface, AddRef Release :
class PugCat : public IPug, public ICat { protected: virtual ~PugCat(void); public: PugCat(void); // IUnknown methods // IUnknown IMPLEMENT_UNKNOWN (PugCat) BEGIN_INTERFACE_TABLE(PugCat) IMPLEMENTS_INTERFACE(IPug) IMPLEMENTS_INTERFACE(IDog) IMPLEMENTS_INTERFACE_AS(IAnimal,IDog) IMPLEMENTS_INTERFACE(ICat) END_INTERFACE_TABLE() // IAnimal methods // IAnimal STDMETHODIMP Eat(void); // IDog methods // IDog STDMETHODIMP Bark(void); // IPug methods // IPug STDMETHODIMP Snore(void); // ICat methods // ICat STDMETHODIMP IgnoreMaster(void); };
, IUnknown . , , , .