Содержание материала

function Invoke

После получения идентификатора запрошенного метода OLE вызывает функцию Invoke, передавая в неё:

DispID

Идентификатор вызываемого метода или свойства, полученный от GetIdsOfNames

LocaleId

Региональный контекст (тот же, что и в GetIdsOfNames)

Flags

Битовая маска, состоящая из следующих флагов

Значение        Комментарий        

DISPATCH_METHOD        Вызывается метод. Если у объекта есть свойство с таким же именем, то будет установлен также флаг DISPATCH_PROPERTYGET        

DISPATCH_PROPERTYGET        Запрашивается значение свойства        

DISPATCH_PROPERTYPUT        Устанавливается значение свойства        

DISPATCH_PROPERTYPUTREF        Параметр передается по ссылке. Если флаг не установлен по значению        

Params

Структура DISPPARAMS, содержащая массив параметров, массив идентификаторов для именованных параметров, и количества элементов в этих массивах. Параметры передаются в порядке, обратном их порядку следования в функции, как это принято в Visual Basic

VarResult

Адрес переменной типа OleVariant, в которую должен быть помещен результат вызова метода или значение свойства или NIL, если возвращаемое значение не требуется.

ExcepInfo

Адрес структуры EXCEPTINFO, которую метод должен заполнить информацией об ошибке, если она возникнет.

ArgErr

Адрес массива, в который должны быть помещены индексы неверных параметров, в случае, если такая ситуация будет обнаружена.

При вызове Invoke не осуществляется никаких проверок, поэтому при его самостоятельной реализации необходимо соблюдать аккуратность при работе с переданными адресами массивов и переменных.

Как видно из описания IDispatch имеется возможность самостоятельно реализовать этот интерфейс, динамически преобразуя обращения к объекту автоматизации в обращения к соответствующим свойствам классов Delphi.

 

Информация RTTI Delphi

Delphi имеет свой внутренний протокол, позволяющий осуществлять обращение к опубликованным (объявленным в секции published) свойствам и методам класса. Для этого служат функции модуля TypInfo.pas. Ключевой является функция

function GetPropInfo(TypeInfo: PTypeInfo;

const PropName: String): PPropInfo;

которая позволяет по имени свойства получить адрес структуры PPropInfo, содержащей информацию о свойстве. В дальнейшем можно получить значение этого свойства при помощи функций GetXXXProp или установить его функциями SetXXXProp. При этом будут корректно вызваны функции получения или установки свойства. Таким образом, у нас есть возможность по имени свойства определить его наличие и установить или получить его значение. Такая возможность позволяет нам создать реализацию IDispatch, динамически транслирующую обращения к свойствам зарегистрированного в TScriptControl объекта автоматизации в обращения к свойствам связанного с ним экземпляра класса VCL

 

Сводим воедино

Итак, как рассмотрено выше RTTI Delphi предоставляет достаточную функциональность для того, чтобы обеспечить трансляцию вызовов OLE-Automation в обращения к свойствам компонентов VCL. Для этого необходимо:

1. В методе GetIdsOfNames проверить существование свойства, при помощи функции GetPropInfo и, если такое свойство найдено вернуть какой-нибудь числовой идентификатор. В роли такого идентификатора удобно использовать результат, возвращаемый функцией GetPropInfo.
2. В методе Invoke установить или получить значение свойства, используя функции GetXXXProp или SetXXXProp.

Для трансляции вызовов OLE в VCL создадим класс TVCLProxy

Code:

type

// Этот интерфейс понадобится для получения ссылки на

// класс VCL из методов, в которые передается его

// интерфейс IDispatch

IQueryPersistent = interface

['{26F5B6E1-9DA5-11D3-BCAD-00902759A497}']

   function GetPersistent: TPersistent;

end;

 

TVCLProxy = class(TInterfacedObject, IDispatch, IQueryPersistent)

private

   FOwner: TPersistent;

   FScriptControl: TVCLScriptControl;

   procedure DoCreateControl(AName, AClassName: WideString;

     WithEvents: Boolean);

   function SetVCLProperty(PropInfo: PPropInfo;

     Argument: TVariantArg): HRESULT;

   function GetVCLProperty(PropInfo: PPropInfo; dps: TDispParams;

     PDispIds: PDispIdList; var Value: OleVariant): HRESULT;

   { IDispatch }

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

   function GetTypeInfo(Index, LocaleID: Integer;

     out TypeInfo): HResult; stdcall;

   function GetIDsOfNames(const IID: TGUID; Names: Pointer;

     NameCount, LocaleID: Integer;

     DispIDs: Pointer): HResult; stdcall;

   function Invoke(DispID: Integer; const IID: TGUID;

     LocaleID: Integer; Flags: Word; var Params;

     VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;

   { IQueryPersistent }

   function GetPersistent: TPersistent;

protected

   function DoInvoke (DispID: Integer; const IID: TGUID;

     LocaleID: Integer; Flags: Word; var dps : TDispParams;

     pDispIds : PDispIdList; VarResult, ExcepInfo,

     ArgErr: Pointer): HResult; virtual;

public

   constructor Create(AOwner: TPersistent;

     ScriptControl: TVCLScriptControl);

   destructor Destroy; override;

end;

 

 

Экземпляр этого класса создается при регистрации объекта в TScriptControl и уничтожается автоматически, когда необходимость в нем исчезает.

Поле FOwner хранит ссылку на экземпляр класса VCL, интерфейс к которому предоставляет этот объект. TVCLScriptControl это наследник TScriptControl.

Главным его отличием является наличие списка зарегистрированных экземпляров TVCLProxy и обработчиков событий, позволяющих компонентам VCL вызывать методы скрипта.

Здесь рассмотрены лишь ключевые моменты реализации, полный код, вместе с примером использования, приведен на компакт диске.

Добавить комментарий

Не использовать не нормативную лексику.

Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.

ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!


Защитный код
Обновить