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


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


Получив указатель на запрошенный объект, 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 не требуется никакого дополнительного кода. Все, что осталось сделать, это реализовать текущие методы интерфейса, которые делают этот класс уникальным.




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