Оптимизация QueryInterface
Оптимизация QueryInterface
Фактически реализация QueryInterface, показанная ранее в этой главе, очень проста и легко может поддерживаться любым программистом, имеющим хоть некоторое представление о СОМ и C++. Тем не менее, многие среды и каркасы приложений поддерживают реализацию, управляемую данными. Это помогает достичь большей расширяемости и эффективности благодаря уменьшению размера кода. Такие реализации предполагают, что каждый совместимый с СОМ класс предусматривает таблицу, которая отображает каждый поддерживаемый IID на какой-нибудь аспект объекта, используя фиксированные смещения или какие-то другие способы. В сущности, реализация QueryInterface , приведенная ранее в этой главе, строит таблицу, основанную на скомпилированном машинном коде для каждого из последовательных операторов if, а фиксированные смещения вычисляются с использованием оператора staticcast (staticcast просто добавляет смещение базового класса, чтобы найти совместимый с типом указатель vptr).
Чтобы реализовать управляемый таблицей QueryInterface, необходимо сначала определить, что эта таблица будет содержать. Как минимум, каждый элемент таблицы должен содержать указатель на IID и некое дополнительное состояние, которое позволит реализации найти указатель vptr объекта для запрошенного интерфейса. Хранение указателя функции в каждом элементе таблицы придаст этому способу максимальную гибкость, так как это даст возможность добавлять новые методики поиска интерфейсов к обычному вычислению смещения, которое используется для приведения к базовому классу. Исходный код в приложении к данной книге содержит заголовочный файл inttable.h , который определяет элементы таблицы интерфейсов следующим образом:
// inttable.h (book-specific header file)
// inttable.h (заголовочный файл, специфический для этой книги)
// typedef for extensibility function
// typedef для функции расширяемости
typedef HRESULT (*INTERFACEFINDER) (void *pThis, DWORD dwData, REFIID riid, void **ppv);
// pseudo-function to indicate entry is just offset
// псевдофункция для индикации того, что запись просто
// является смещением
#define ENTRYISOFFSET INTERFACEFINDER(-1)
// basic table layout // представление базовой таблицы
typedef struct INTERFACEENTRY
{
const IID * pIID;
// the IID to match
// соответствующий IID
INTERFACEFINDER pfnFinder;
// функция finder DWORD dwData;
// offset/aux data
// данные по offset/aux
} INTERFACEENTRY;
Заголовочный файл также содержит следующие макросы для создания интерфейсных таблиц внутри определения класса:
// Inttable.h (book-specific header file)
// Inttable.h (заголовочный файл, специфический для данной книги)
#define BASEOFFSET(ClassName, BaseName) (DWORD(staticcast<BaseName*>(reinterpretcast <ClassName*>(0x10000000))) – 0х10000000)
#define BEGININTERFACETABLE(ClassName) typedef ClassName ITCls; const INTERFACEENTRY *GetInterfaceTable(void) { static const INTERFACEENTRY table [] = {
#define IMPLEMENTSINTERFACE(Itf) {&IID##Itf,ENTRYISOFFSET,BASEOFFSET(ITCls,Itf)},
#define IMPLEMENTSINTERFACEAS(req, Itf) {&IID##req,ENTRYISOFFSET, BASEOFFSET(ITCls, Itf)},
#define ENDINTERFACETABLE() { 0, 0, 0 } }; return table; }
Все, что требуется, – это стандартная функция, которая может анализировать интерфейсную таблицу в ответ на запрос QueryInterface. Такая функция содержится в файле Inttable.h:
// inttable.cpp (book-specific source file)
// inttable.h (заголовочный файл, специфический для данной книги)
HRESULT InterfaceTableQueryInterface(void *pThis, const INTERFACEENTRY *pTable, REFIID riid, void **ppv)
{
if (InlineIsEqualGUID(riid, IIDIUnknown))
{
// first entry must be an offset
// первый элемент должен быть смещением
*ppv = (char*)pThis + pTable->dwData;
((Unknown*) (*ppv))->AddRef () ;
// A2
return SOK;
} else
{
HRESULT hr = ENOINTERFACE;
while (pTable->pfnFinder)
{
// null fn ptr == EOT
if (!pTable->pIID || InlineIsEqualGUID(riid,*pTable->pIID))
{
if (pTable->pfnFinder == ENTRYISOFFSET)
{
*ppv = (char*)pThis + pTable->dwData;
((IUnknown*)(*ppv))->AddRef();
// A2
hr = SOK;
break;
} else
{
hr = pTable->pfnFinder(pThis, pTable->dwData, riid, ppv);
if (hr == SOK) break;
}
}
pTable++;
}
if (hr!= SOK)
*ppv = 0;
return hr;
}
}
Получив указатель на запрошенный объект, InterfaceTableQueryInterface сканирует таблицу в поисках элемента, соответствующего запрошенному IID, и либо добавляет соответствующее смещение, либо вызывает соответствующую функцию. Приведенный выше код использует усовершенствованную версию IsEqualGUID, которая генерирует несколько больший код, но результаты по скорости примерно на 20-30 процентов превышают данные по существующей реализации, которая не управляется таблицей. Поскольку код для InterfaceTableQueryInterface появится в исполняемой программе только один раз, это весьма неплохой компромисс.
Очень легко автоматизировать поддержку СОМ для любого класса C++, основанную на таком табличном управлении, простым использованием С-препроцессора. Следующий фрагмент из заголовочного файла impunk.h определяет QueryInterface, AddRef и Release для объекта, использующего интерфейсные таблицы и расположенного в динамически распределяемой области памяти:
// impunk.h (book-specific header file)
// impunk.h (заголовочный файл, специфический для данной книги)
// AUTOLONG is just a long that constructs to zero
// AUTOLONG – это просто long, с конструктором,
// устанавливающим значение в О
struct AUTOLONG
{
LONG value;
AUTOLONG (void) : value (0) {}
};
#define IMPLEMENTUNKNOWN(ClassName)
AUTOLONG mcRef;
STDMETHODIMP QueryInterface(REFIID riid, void **ppv){
return InterfaceTableQueryInterface(this,
GetInterfaceTable(), riid, ppv);
}
STDMETHODIMP(ULONG) AddRef(void) {
return InterlockedIncrement(&mcRef.value);
}
STDMETHODIMP(ULONG) Release(void) {
ULONG res = InterlockedDecrement(&mcRef.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
IMPLEMENTUNKNOWN (PugCat)
BEGININTERFACETABLE(PugCat)
IMPLEMENTSINTERFACE(IPug)
IMPLEMENTSINTERFACE(IDog)
IMPLEMENTSINTERFACEAS(IAnimal,IDog)
IMPLEMENTSINTERFACE(ICat)
ENDINTERFACETABLE()
// 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 не требуется никакого дополнительного кода. Все, что осталось сделать, это реализовать текущие методы интерфейса, которые делают этот класс уникальным.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Поисковая оптимизация
Поисковая оптимизация Под поисковой оптимизацией (англ. Search Engine Optimization, SEO) понимается комплекс работ по корректировке внутреннего устройства сайта и внешних факторов с целью усиления позиции сайта по определенным запросам в поисковых системах.Поисковые системы — это
Оптимизация
Оптимизация Теперь сайт работает точно так, как и планировалось. Вы открываете доступ всем желающим, и начинается веселье.Если вы аккуратно и точно выполнили все необходимые действия, не торопясь, прошли каждый этап создания сайта, то настало время переходить к
Оптимизация сайта
Оптимизация сайта Поговорим о том, как лучше оформить сайт для того, чтобы он способствовал продвижению в социальных сетях и соответствовал поставленным задачам. Сайт – это точка вашего контакта с клиентом, первая и основная. У вашего сайта должны быть хороший дизайн и
QueryInterface симметрична
QueryInterface симметрична Спецификация СОМ требует, чтобы, если запрос QueryInterface на интерфейс B удовлетворяется через интерфейсный указатель типа A, то запрос QueryInterface на интерфейс A того же самого объекта через результирующий интерфейсный указатель типа В всегда был успешным.
QueryInterface транзитивна
QueryInterface транзитивна Спецификация СОМ требует также, чтобы, если запрос QueryInterface на интерфейс В удовлетворяется через интерфейсный указатель типа A, а второй запрос QueryInterface на интерфейс C удовлетворяется через указатель типа В , то запрос QueryInterface на интерфейс C через
QueryInterface рефлективна
QueryInterface рефлективна Спецификация СОМ требует, чтобы запрос QueryInterface через интерфейсный указатель всегда достигал цели, если запрошенный тип соответствует типу указателя, с помощью которого произведен запрос. Это означает, что QI(A)->A всегда должен быть верным. Это
QueryInterface и IUnknown
QueryInterface и IUnknown Свойство рефлективности QueryInterface гарантирует, что любой интерфейсный указатель сможет удовлетворить запросы на IUnknown, поскольку все интерфейсные указатели неявно принадлежат к типу IUnknown. Спецификация СОМ имеет немного больше ограничений при описании
4. Оптимизация Windows XP
4. Оптимизация Windows XP Мир, в котором мы живем, не совершенен. Нам все время приходится выбирать между хорошим и тем, что еще лучше.Несомненно, Windows XP – быстрая и красивая операционная система. Но если вам вдруг показалось, что игры работают немного медленно, а приложения
12 Оптимизация
12 Оптимизация Преждевременная оптимизация — корень всех зол. —Ч. Хоар Данная глава очень короткая, поскольку главное, чему учит опыт Unix относительно оптимизации производительности, — как узнать, когда не следует выполнять оптимизацию. Второстепенный урок заключается
12 Оптимизация
12 Оптимизация Преждевременная оптимизация — корень всех зол. -Ч. Хоар Данная глава очень короткая, поскольку главное, чему учит опыт Unix относительно оптимизации производительности, — как узнать, когда не следует выполнять оптимизацию. Второстепенный урок заключается в
Глава 6 Оптимизация
Глава 6 Оптимизация Если с увеличением объема вашей базы данных она стала работать слишком медленно, зачастую самый простой путь решения этой проблемы – увеличение мощности аппаратной платформы сервера. Однако повысить быстродействие системы можно и без наращивания
6.2. Оптимизация запросов
6.2. Оптимизация запросов Основным способом повышения производительности запросов являются индексы. Определить, действительно ли созданные вами индексы используются запросом, позволяет командаEXPLAIN <Текст запроса>; Набор данных, выводимый командой EXPLAIN, содержит
33.6. Оптимизация
33.6. Оптимизация По большей части, сценарии на языке командной оболочки, используются для быстрого решения несложных задач. Поэтому оптимизация сценариев, по скорости исполнения, не является насущной проблемой. Тем не менее, представьте себе ситуацию, когда сценарий,
Настройка и оптимизация
Настройка и оптимизация Установка драйверов и настройкаПосле того, как была успешно установлена операционная система Windows ХР, нам надо её настроить. Для начала, конечно, установим все драйвера. Вот в какой последовательности:• Драйвера на материнскую
Оптимизация вызовов
Оптимизация вызовов На уровнях 2 и 3 неизбежно использование явных вызовов процедуры подобных my_polygon.set_size (5) для изменения значения атрибута. Существует опасение, что использование такого стиля на уровне 4 негативно скажется на производительности. Тем не менее компилятор