Доступ к объекту автоматизации
Сервер автоматизации предоставляет своим клиентам для доступа объект специального типа — dispatch object. При этом в адресном пространстве приложения клиента, называемого в этом случае контроллером, присутствует вариантная переменная, содержащая интерфейс IDispatch, предоставляющий ему доступ к этому объекту на OLE-сервере.
Фактически у клиента имеется три варианта доступа к объектам:
• Используя интерфейс IDispatch (доступ не отличается от доступа к обычному СОМ-серверу. Вызов методов происходит через VMT).
pSum:=CoSum.Create; (с помощью библиотеки типов)
• Используя в качестве интерфейса диспинтерфейс (этот вариант похож на предыдущий).
pdSum:=CoSum.Create As ISumDisp;
pdSum:=ISumDisp(CoSum.Create);
pdSum:=CreateComObject(Class_Sum) As ISumDisp;
• Используя вариантную переменную (Variant), которая инициализируется функцией:
CreateOleObject(Const ProgID: String): IDispatch;
В этом случае доступ осуществляется по имени объекта — ProgID. Считается, что этот вариант вызова более медленный, чем через виртуальную таблицу.
Посредством вызова единственного метода интерфейса с виртуальной таблицей — Invoke, клиент может вызвать любой метод диспинтерфейса. Для работы с одним виртуальным методом достаточно одной пары заместителя и заглушки для реализации маршалинга и демаршалинга. Однако через этот метод вызываются другие методы, которые могут оперировать параметрами всевозможных типов.
Фактически, вызывающий метод диспинтерфейса клиент, сам выполняет своеобразный маршалинг и демаршалинг. Перед вызовом метода Invoke, он должен упаковать параметры диспинтерфейса в вариант (variant).
Фактически для любого метода, вызываемого через переменную типа Variant, происходит следующее:
• Приложение Delphi передает имя метода объекта на сервере методу интерфейса IDispatch.GetDsOfName.
• Метод интерфейса IDispatch.GetDsOfName возвращает DispID, который однозначно соответствует имени метода объекта сервера.
• Приложение Delphi вызывает метод Invoke, используя DispID.
Для обращения к объектам Automation в Delphi используется тип Ole Variant — запись TVarData с четырьмя фиксированными и 16 вариантными полями. Когда OleVariant ссылается на объект Automation, можно вызвать как методы объекта, так и методы доступа разделов Read или Write свойства. Чтобы это сделать, необходимо включить модуль ComObj в секцию Uses одного из модулей, программы или библиотеки.
Массивы Variant с элементами типа varByte — привилегированный метод пересылки двоичных данных между контроллерами Automation и серверами. Такие массивы не подчинены никакой трансляции их данных и могут эффективно применяться, используя функции VarArrayLock и VarArrayUnlock. С их помощью можно обеспечить маршалинг произвольных структур данных.
Вызов методов объекта Automation происходит во время выполнения программы и не требует никаких предыдущих объявлений метода. Проверка правильности этих обращений во время компиляции программы не проводится.
Методика создания контролера автоматизации
Программы-клиенты для доступа к объектам автоматизации обычно называют контроллерами автоматизации.
Для создания контроллера автоматизации следует:
а) Создать проект и включить, например, в класс TForm1 переменные:
Туре
TForm1=Class(TForm)
Public
vSum: Variant; //Для доступа по имени программы
pSum: ISum; // Для доступа через интерфейс
pdSum: ISumDisp; // Для доступа через диспинтерфеис
End;
б) В число блоков экранной формы следует включить блок с описанием интерфейсов, поместив в рабочий каталог файл библиотеки типов сервера.
Uses OLEXE_TLB;
в) Далее следует обеспечить доступ к объекту одним из следующих способов:
vSum:=CreateOleObject(‘OLEXE.Sum’);
pSum:=CoSum.Create;
pdSum:=CoSum.Create As ISumDisp;
// Можно и иначе:
pdSum:=ISumDisp(CoSum.Create);
pdSum:=CreateComObject(Class_Sum) As ISumDisp;
Любой из указанных вызовов приведет к загрузке сервера и созданию объекта. После этого можно обращаться к методам и свойствам объекта.
Следует иметь в виду, что использование интерфейсов всегда более производительно, чем использование диспинтерфейсов и, тем более, переменных типа Variant (OleVariant), поскольку они используют позднее связывание.
Двойной (dual) интерфейс — интерфейс, поддерживающий связывание времени компиляции (раннее связывание с помощью интерфейсов) и связывание времени выполнения (позднее связывание с помощью переменной типа Variant). Двойные интерфейсы наследуются от IDispatch. В dual интерфейсах VMT увеличивается за счет включения прямых указателей на методы диспинтерфейса. Поэтому возможен доступ и через метод Invoke и напрямую.
Все методы двойного интерфейса должен использовать safecall соглашение, и все параметры метода и тип результата должны быть типа: Byte, Integer, Smalllnt, Currency, Real, Double, Real48, Single, AnsiString, ShortString, TDateTime, Variant, OleVariant и WordBool.
Серверы автоматизации, создаваемые в Delphi, автоматически поддерживают дуальность.