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

Использование Microsoft ScriptControl

 

Интеграция TScriptControl с VCL

В существующем виде возможности TScriptControl сильно ограничены сложным доступом к классам VCL. Исполнение интерпретируемого кода это хорошо, однако хотелось бы иметь возможность их него обращаться к компонентам в программе, получать и устанавливать их свойства, обрабатывать возникающие в них события, например следующим образом:

 

Code:

Sub Main()

Dim Control

Control = Self.Controls("Panel2")

Control.Add "Panel3", "TPanel"

With Panel3

   .Align = "alTop"

   .BevelOuter = "bvNone"

   .Height = 40

   .Caption = ""

   .Add "Btn", "TButton", True

   With Btn

    .Top = 10

    .Left = .Top

    .Caption = "Click me"

   End With

 

End With

End Sub

 

Sub Btn_OnClick()

Dim StatusBar

Dim Panel

Dim I

I = 0

For Each Panel In StatusBar.Panels

   I = I + 1

   With Panel

     .Text = .Text & " " & CStr(I)

   End With

Next

End Sub

 

 

 

Дальнейшая часть главы посвящена реализации такой функциональности, однако, прежде чем приступить к этому, необходимо более подробно рассмотреть некоторые механизмы, лежащие в основе модели расширения TScriptControl и VCL

 

Модель расширения ScriptControl

Как уже было рассмотрено выше, Microsoft ScriptControl позволяет сделать доступными из скрипта объекты, реализованные в программе при помощи метода AddObject. При обращении к таким объектам он предполагает, что они реализуют интерфейс IDispatch и являются, таким образом, OLE-automation серверами. В Delphi в качестве таких объектов могут выступать наследники TAutoObject, создать которых можно при помощи мастера, вызываемого из меню File -> New -> ActiveX -> Automation Object. При вызове методов этих объектов ScriptControl последовательно вызывает методы GetIdsOfNames и Invoke их интерфейса IDispatch, что приводит к вызовам соответствующих методов объекта. Однако здесь имеются определенные сложности:

1. По окончании работы с объектом (например, при выходе его за пределы области видимости процедуры скрипта) TScriptControl автоматически вызывает его метод _Release, что приведет к уничтожению класса Delphi. Таким образом, для каждого класса приходится создавать некий объект-представитель, который бы транслировал вызовы TScriptControl в методы и свойства класса Delphi, а при исчезновении необходимости уничтожался, не уничтожая самого класса
2. Функциональность наследников TAutoObject задается на этапе компиляции и не может быть расширена в процессе исполнения программы. Это заставляет создавать отдельных представителей для каждого класса VCL, что очень сложно в реализации и не позволяет использовать классы, для которых нет соответствующего представителя.

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

 

Интерфейс IDispatch

Интерфейс IDispatch обеспечивает возможность позднего связывания, т.е. вызовов методов объектов не по адресам, а по именам на этапе выполнения программы. Интерфейс определен как:

 

Code:

type

IDispatch = interface(IUnknown)

   ['{00020400-0000-0000-C000-000000000046}']

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

   function GetTypeInfo(Index, LocaleID: Integer;

     out TypeInfo): Integer; stdcall;

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

     NameCount, LocaleID: Integer; DispIDs: Pointer): Integer;

     stdcall;

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

     LocaleID: Integer; Flags: Word; var Params; VarResult,

     ExcepInfo, ArgErr: Pointer): Integer; stdcall;

end;

 

Ключевыми методами интерфейса являются GetIdsOfNames и Invoke.

 

function GetIdsOfNames

Этот метод осуществляет трансляцию имен методов и свойств объекта автоматизации в целочисленные идентификаторы. Если OLE пытается разрешить ссылку вида:

SomeObject.DoSomeThing

Она запрашивает у SomeObject интерфейс IDispatch и вызывает метод GetIdsOfNames, передавая ему ссылку на массив имен требующих разрешения в параметре Names, количество имен в параметре NameCount и региональный контекст в параметре LocaleId. Метод должен заполнить массив, на который указывает параметр DispIds значениями идентификаторов имен. Объект имеет возможность предоставить разные имена методов для каждого поддерживаемого языка. Если это не нужно Вы можете игнорировать параметр LocaleId.

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

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

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

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

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


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