Библиотека программиста

«Программирование, как и любовь - это одно слово, за которым скрывается бесчисленное множество занятий»

Главная страница > Технология COM > 55. Интерфейсы

55. Интерфейсы

Три вида интерфейсов:

· базовый интерфейс IUnknown;

· диспетчерский интерфейс IDispatch;

· диспинтерфейс (dispinterface);

· двойственный интерфейс (dual interface).

Интерфейс IUnknown поддерживает три метода и таблица виртуальных методов VTBL для объекта, поддерживающего этот интерфейс, должна иметь такой вид:

IUnknown.QueryInterface

IUnknown.AddRef

IUnknown.Release

Когда разработчик объекта добавляет свой интерфейс IMyInterface, предоставляющий методы и свойства некоторого объекта, таблица VTBL приобретает такой вид:

IUnknown.QueryInterface

IUnknown.AddRef

IUnknown.Release

IMyInterface.Method1

IMyInterface.Method2

другие методы и свойства IMyInterface

Для объекта, поддерживающего интерфейсы IUnknown и IDispatch, та же таблица приобретает вид:

IUnknown.QueryInterface

IUnknown.AddRef

IUnknown.Release

IDispatch.GetIDsOfNames

IDispatch.GetTypeInfo

IDispatch.GetTypeInfoCount

IDispatch.Invoke

Отметим, что объекты, имеющие диспетчерский интерфейс, не могут не иметь интерфейса IUnknown.

Интерфейс IDispatch, в отличие от IUnknown, предоставляет возможность позднего связывания, что необходимо при программировании на интерпретируемых языках. IDispatch не имеет индивидуальных методов для доступа к методам и свойствам объекта автоматизации. Вместо этого он предоставляет единственный метод Invoke, предназначенный для доступа к свойствам COM объекта и вызова его методов.

Для вызова конкретного метода объекта необходимо, сначала, получить номер метода с помощью функции GetIDsOfNames, а затем полученный номер метода указать в вызове функции Invoke. Функция GetIDsOfNames имеет такой заголовок:

Function GetIDsOfNames(const IID: TGUID; Names: Pointer; NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;

Вызывающая программа должна передать через указатель Names имя (или имена) требуемого метода, а номер (или номера) метода получает через указатель DispIDs. Возвращаемое функцией значение описано в табл.

Возвращаемое значение

Описание

S_OK

Ошибки нет

E_OUTOFMEMORY

Недостаточно памяти

DISP_E_UNKNOWNNAME

Одно или более имен неизвестны. Возвращаемый массив идентификаторов DISPIDs содержит значение DISPID_UNKNOWN для каждого неизвестного имени

DISP_E_UNKNOWNLCID

Не распознан идентификатор локализации LCID

Главный метод интерфейса IDispatch имеет описан как:

Function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word;
var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;

Номер метода передается через параметр DispID, а фактические параметры вызываемого метода – через Params, который представляет собой указатель на структуру. Не вдаваясь в подробное толкование параметров Invoke отметим только, что формирование списка фактических параметров является сравнительно трудоемким занятием. Этих трудностей можно избежать, так как вызывающая программа на Object Pascal может и не использовать метод Invoke, что будет рассмотрено позже.

Метод GetTypeInfoCount

Function GetTypeInfoCount(out Count: Integer): HResult; stdcall;

позволяет узнать, доступна ли информация о типах данного COM объекта. Если он возвращает значение Count=1, то информация доступна, а если Count=0 – то нет.

Получить информацию о типах можно с помощью метода

Function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;

который возвращает информацию через указатель на интерфейс библиотеки типов TypeInfo.

Диспинтерфейс (dispinterface) представляет собой объявление методов, доступных через интерфейс IDispatch. Он позволяет упростить использование методов интерфейса IDispatch благодаря тому, что компилятор в этом случае имеет возможность выполнить контроль типов при вызове методов объекта или обращении к его свойствам. При этом, тем не менее, используется позднее связывание. В конечном итоге вызов метода диспинтерфейса Delphi преобразует в вызов метода Invoke с соответствующими параметрами. Из этого следует, что на самом деле, в отличие от раннего связывания, наличие вызываемого метода или свойства у объекта не проверяется и не может быть проверено на этапе компиляции. Вот пример описания диспинтерфейса:

ISomeDispInterf = dispinterface

['{40BC066A-D946-11D5-BE01-ABCDCE4D71F9}']

function Summa(X: Integer; Y: Integer): Integer; dispid 1;

end;

Если к объекту, имеющему интерфейс IDispatch, добавить свой собственный интерфейс (custom interface), то мы получим двойственный (дуальный) интерфейс (dual interface) и таблица VTBL в этом случае приобретает такой вид:

IUnknown.QueryInterface

IUnknown.AddRef

IUnknown.Release

IDispatch.GetIDsOfNames

IDispatch.GetTypeInfo

IDispatch.GetTypeInfoCount

IDispatch.Invoke

IMyInterface.Method1

IMyInterface.Method2

другие методы и свойства IMyInterface

Дуальный интерфейс удобен тем, что предоставляет возможность осуществления как раннего, так и позднего связывания методов COM объекта. Для его реализации объявления методов собственного интерфейса (производного от IUnknown) должны быть идентичны объявлениям методов в диспинтерфейсе.





<< Предыдущая статья
«54. Разработка и использование локального сервера»
Следующая статья >>
56. Апартаменты и многопоточность в СОМ