используемые им ресурсы могут быть освобождены, был применен метод DestroyPointer. Вот как выглядит определение IUnknown на C++:

extern 'С' const IID IID_IUnknown: interface IUnknown

{

virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv) = 0;

virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;

virtual ULONG STDMETHODCALLTYPE Release(void) = 0;

};

Заголовочные файлы SDK дают псевдоним interface ключевому слову C++ struct, используя препроцессор С. Поскольку интерфейсы в СОМ определены не как классы, а как структуры, то для того, чтобы сделать методы интерфейса общедоступными, ключевое слово public не требуется. Чтобы создать для целевой платформы СОМ-совместимые стековые фреймы, необходим макрос STDMETHODCALLTYPE. Если целевыми являются платформы Win32, то при использовании компилятора Microsoft C++ этот макрос раскрывается в _stdcall.

IUnknown функционально эквивалентен IExtensibleObject. Метод QueryInterface используется для динамического определения типа и аналогичен С++-оператору dynamic_cast. Метод AddRef используется для сообщения объекту, что указатель интерфейса дублирован. Метод Release используется для сообщения объекту, что указатель интерфейса уничтожен и все ресурсы, которые объект поддерживал от имени клиента, могут быть отключены. Главное различие между IUnknown и интерфейсом, определенным в предыдущей главе, заключается в том, что IUnknown использует идентификаторы GUID, а не строки для идентификации типов интерфейса на этапе выполнения.

IDL-определение IUnknown можно найти в файле unknwn.idl из директории SDK, содержащей заголовочные файлы:

// unknwn.idl – system IDL file

// unknwn.idl – системный файл IDL

[ local, object, uuid (00000000-0000-0000-C000-000000000046) ] interface IUnknown

{

HRESULT QueryInterface([in] REFIID riid, [out] void **ppv);

ULONG AddRef(void); ULONG Release(void);

}

Атрибут local подавляет генерирование сетевого кода для этого интерфейса. Этот атрибут необходим для того, чтобы смягчить требования СОМ о том, что все методы при вызове с удаленных машин должны возвращать HRESULT. Как будет показано в следующих главах, интерфейс IUnknown трактуется особым образом при работе с удаленными объектами. Заметим, что фактические, то есть использующиеся на практике IDL-описания интерфейсов, которые содержатся в заголовках SDK, немного отличаются от определений, данных в этой книге. Фактические определения часто содержат дополнительные атрибуты для оптимизации генерируемого сетевого кода, которые не имеют отношения к нашему обсуждению. В случае сомнений обратитесь за полными определениями к последней версии заголовочных файлов SDK.

Интерфейс IUnknown является родительским для всех СОМ-интерфейсов. IUnknown – единственный интерфейс СОМ, который не наследует от другого интерфейса. Любой другой допустимый интерфейс СОМ должен быть прямым потомком IUnknown или какого-нибудь другого допустимого интерфейса СОМ, который, в свою очередь, должен сам наследовать или прямо от IUnknown, или от какого-нибудь другого допустимого интерфейса СОМ. Это означает, что на двоичном уровне все интерфейсы СОМ являются указателями на таблицы vtbl, которые начинаются с трех точек входа: QueryInterface, AddRef и Release. Все специфические для интерфейсов методы будут иметь точки входа в vtbl, которые появляются после этих трех общих точек входа.

Чтобы наследовать от интерфейса IDL, нужно или определить базовый интерфейс в том же IDL- файле, или использовать директиву import, чтобы сделать внешнее IDL-определение базового интерфейса явным в данной области действия:

// calculator.idl

[object, uuid(BDA4A270-A1BA-11dO-8C2C-0080C73925BA)]

interface ICalculator : IUnknown

{

import «unknwn.idl»;

// bring in def. of IUnknown

// импортируем определение IUnknown

HRESULT Clear(void);

HRESULT Add([in] long n);

HRESULT Sum([out, retval] long *pn);

}

Оператор import может появляться или внутри определения интерфейса, как показано здесь, или предшествовать описанию интерфейса в глобальной области действия. В любом из этих случаев действия оператора import одинаковы, он может многократно импортировать один IDL-файл без всякого ущерба. Поскольку сгенерированный C/C++ заголовочный файл будет требовать С/С++-версии импортируемого IDL-файла, чтобы обеспечить наследование, оператор import из IDL-файла будет странслирован в команду #include в генерируемом заголовочном С/С++-файле:

// calculator.h – generated by MIDL

// calculator.h – генерированный MIDL

// bring in def. of IUnknown

// вводим определения IUnknown

#include «unknwn.h»

extern 'C' const IID IID_ICalculator;

interface ICalculator : public IUnknown

{

virtual HRESULT STDMETHODCALLTYPE Clear(void) = 0;

virtual HRESULT STDMETHODCALLTYPE Add(long n) = 0;

virtual HRESULT STDMETHODCALLTYPE Sum(long *pn) = 0;

}

Компилятор MIDL также создаст С-файл, содержащий фактические определения всех GUID, имеющихся в исходном IDL-файле:

// calculator_i.с – generated by MIDL

const IID IID_ICalculator =

{ 0xBDA4A270, 0xA1BA, 0x11d0, { 0x8C, 0x2C, 

0x00, 0х80, 0хC7, 0х39, 0x25, 0xBA } };

Каждый проект, который будет использовать этот интерфейс, должен или добавить calculator_i.c к своему файлу сборки (makefile), или включить calculator_i.c в один из исходных файлов на С или C++ с использованием препроцессора С. Если это не сделано, то идентификатору IID_ICalculator не будет выделено памяти для его 128-битного значения и проект не будет скомпонован по причине неразрешенных внешних идентификаторов.

СОМ не накладывает никаких ограничений на глубину иерархии интерфейсов при условии, что

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату