Сущность технологии COM


Оптимизация QueryInterface - часть 2


#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; } }




Начало  Назад  Вперед