Большой архив статей, книг, документации по программированию, вебдизайну, компьютерной графике, сетям, операционным системам и многому другому
 
<Добавить в Избранное>    <Сделать стартовой>    <Реклама на сайте>    <Контакты>
  Главная Документация Новости ИТ Программы Книги Games   Обои   Экспорт RSS E-Books
 
Поиск по сайту

TOP-10 программ
Symantec Norton Ghost 9.0
Partition Magic 8.0.2 Pro
Xilisoft 3GP Video Converter v3.1.7.0616b
Norton AntiVirus 2005
Xilisoft 3GP Video Converter v2.1.52.831b
Антивирус Касперского Personal 5.0.303 beta 2
RAR Password Cracker 4.12
ABBYY PDF Transformer v1.00.820
MP3 To Ringtone Gold v3.02
Windows Movie Maker 2.6
 
Наши сервисы
Рассылка новостей. Подпишитесь на рассылку сейчас и вы всегда будете в курсе последних событий в мире информационных технологий.
Новостные информеры. Поставьте наши информеры к себе и у вас на сайте появится дополнительный постоянно обновляемый раздел.
Добавление статей. Если вы являетесь автором статьи или обзора на тему ИТ присылайте материал нам, мы с удовольствием опубликуем его у себя на сайте.
 
 

   Программирование -> C/C++ -> Сущность технологии COM


Оптимизация QueryInterface

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

Типы данных
Атрибуты и свойства
Исключения
Где мы находимся?

 
Популярные книги

Windows XP для всех

Подробнее

Дизайн помещений и интерьеров в 3ds max 7 (+CD)

Подробнее

Практикум по программированию на языке Си (+CD)

Подробнее


 
Новости ИТ
09.01.2009  Exeda -- корпоративный цифровой ассистент с Android Linux
09.01.2009  Правительство Вьетнама массово переходит на Open Source
09.01.2009  Windows 7 build 7000
09.01.2009  Silicon Power представила скоростную SDHC
09.01.2009  CES 2009: RealView 360 3D Desktop Scanner - настольный 3D-сканер, один из первых в мире
09.01.2009  W90 - очень быстрый мультимедийный ноутбук ASUS «Ultimate-уровня»
09.01.2009  CES 2009: SanDisk представила семейство G3 - самых быстрых SSD-накопителей на флэш-памяти MLC
09.01.2009  ZOTAC GeForce GTX 285 и GTX 285 AMP! Edition - 3D-ускорители для геймеров на новом GPU NVIDIA
09.01.2009  Net Applications: в декабре доли Firefox и Chrome росли за счет IE
09.01.2009  Imation говорит о «новом классе» SSD и первом в отрасли полном наборе для модернизации на основе SSD
09.01.2009  Маршрутизатор D-Link Xtreme N DIR-685 может играть роль NAS, сервера печати... и цифровой фоторамки
09.01.2009  Очень тонкая фотокамера Pentax Optio P70 имеет разрешение 12 Мп
09.01.2009  pureSilicon 1TB Nitro - первый в мире 2,5-дюймовый SSD объемом 1 ТБ
09.01.2009  Дебютировали мобильные GPU ATI Mobility Radeon HD 4000
09.01.2009  NVIDIA GeForce GTX 285 и GTX 295 представлены официально
09.01.2009  Scythe выпустила процессорный кулер Mugen 2
09.01.2009  Optio E70 - новая компактная камера Pentax начального уровня
09.01.2009  Новый iPhone получит четырехъядерный процессор?
08.01.2009  FreeBSD 7.1-RELEASE -- обновление операционной системы
08.01.2009  Появилась сборка Om 2008.12 для Neo FreeRunner от bytestore
 
Полезно

 
Copyright © CompDoc.Ru
При цитировании и перепечатке ссылка на www.compdoc.ru обязательна. Карта сайта.
 
Rambler's Top100