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




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



Книжный магазин