Windows script control что такое

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

Автор: Анатолий Тенцер

При разработке настраиваемых информационных систем часто возникает необходимость добавить в свою программу встроенный язык программирования. Такой язык позволял бы конечным пользователям настраивать поведение программы без участия автора и перекомпиляции. Однако самостоятельная реализация интерпретатора является непосильной для многих разработчиков задачей, а от большинства остальных потребует очень много времени и усилий.

В то же время в Windows, как правило, уже имеется достаточно качественный интерпретатор, который может быть легко встроен в вашу программу. Речь идет о Microsoft ScriptControl. Он устанавливается вместе с Microsoft Internet Explorer, входит в Windows 2000 и Windows 98, а для младших версий доступен в виде свободно распространяемого отдельного дистрибутива, объем которого составляет около 200 Кбайт. Его можно получить по адресу http://msdn.microsoft.com/scripting или установить с нашего компакт-диска. В дистрибутив входят ActiveX-компонент и файл помощи с описанием его свойств и методов.

Добавление TScriptControl в программу

Чтобы добавить Microsoft ScriptControl на палитру компонентов Delphi, необходимо импортировать компонент ActiveX под названием Microsoft ScriptControl.

После этого на закладке ActiveX появится невизуальный компонент TScriptControl, который можно разместить на форме.

Настройка свойств и вызов скриптов

Рассмотрим ключевые свойства и методы TScriptControl.

property Language: String

Задает язык, интерпретатор которого будет реализовывать компонент. В стандартной поставке доступны VBScript и JScript, однако, если в вашей системе установлены расширения Windows Scripting, возможно использование других языков, таких как Perl или Rexx.

property Timeout: Integer

Задает интервал исполнения скрипта, по истечении которого генерируется ошибка. Значение –1 позволяет отключить ошибки, связанные с истечением отведенного времени (timeout), что позволит скрипту исполняться неограниченное время.

property UseSafeSubset: Boolean

При установке этого свойства в TRUE компонент может выполнять ограниченный набор действий, заданный текущими установками безопасности в системе. Это свойство полезно, если вы запускаете скрипты, полученные, например, через Интернет.

procedure AddCode(const Code: WideString);

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

function Eval(const Expression: WideString): OleVariant

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

procedure AddObject(const Name: WideString; Object_: IDispatch; AddMembers: WordBool);

Добавляет объект к пространству имен компонента. Объект должен быть сервером автоматизации. Добавленный объект доступен как объект в коде скрипта. Например, если в программе создан сервер автоматизации External, реализующий метод DoSomething(Value: Integer), то, добавив объект

мы можем в коде скрипта использовать его следующим образом:

function Run(const ProcedureName: WideString; var Parameters: PSafeArray): OleVariant;

Выполняет именованную процедуру из числа ранее добавленных при помощи метода AddCode. В массиве Parameters могут быть переданы параметры.

Сбрасывает компонент в начальное состояние, удаляя все добавленные ранее объекты и код.

Таким образом, TScriptControl представляет собой достаточно гибкую исполняющую систему с возможностями расширения путем добавления в ее пространство имен серверов автоматизации.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Свойства компонентов VCL

Константы DISPID_CONTROLS, DISPID_COUNT и т.д. определены как целые числа из диапазона 1…1 000 000. Это вполне безопасно, поскольку адрес структуры TPropInfo никак не может оказаться менее 1 Мбайт.

Использование объекта Microsoft Script Control в среде 1С:Предприятие v7.7

Автор: Людоговский А.И., ООО «Фирма Элли», г. Москва.
Источник: http://script-coding.info/

Объект Microsoft Script Control

Объект Microsoft Script Control в среде 1С:Предприятие v7.7 может быть создан следующим образом:

После этого вы можете вызывать и использовать методы и свойства этого объекта.

Объект позволит исполнить любой код на VBScript или JScript. Может быть очень полезен, если нужно исполнить код, который не может быть исполнен непосредственно в 1С:Предприятии. Например:

  • Для работы с некоторыми OLE-объектами (например, при работе с технологией WMI — образцы кода см. ниже) нужно использовать функцию «GetObject». Этой функции нет во встроенном языке 1С:Предприятие v7.7, но используя Microsoft Script Control, вы сможете работать с ней.
  • Не все методы и свойства различных OLE-объектов корректно работают непосредственно в 1С:Предприятии v7.7. Иногда не удаётся передать или получить какой-то параметр, т.к. не поддерживается тот или иной тип данных. С помощью Microsoft Script Control эти проблемы решаются.
  • В VBScript и JScript есть функции, которых нет во встроенном языке 1С:Предприятие v7.7 (например, функция, вычисляющая квадратный корень числа). Используя Microsoft Script Control, вы сможете полноценно работать с этими функциями.
  • 1С:Предприятие v7.7 не всегда корректно работает с объектами так называемых «коллекций», которые могут быть возвращены различными свойствами и методами тех или иных OLE-объектов. Используя Microsoft Script Control, вы сможете полноценно работать с любыми коллекциями, например, с помощью цикла «for each», которого нет во встроенном языке 1С:Предприятие v7.7.

Полное описание объекта на английском языке можно скачать вместе с его дистрибутивом с сайта Microsoft. При этом, если у вас не слишком старая версия Windows, ничего устанавливать вам скорее всего вообще не придётся. Описание свойств и методов объекта на русском языке в формате синтакс-помощника 1С:Предприятие v7.7 (als-файл) вы можете скачать здесь. Скопируйте ALS-файл в каталог программы (например, «C:Program Files1Cv77BIN»), и в конфигураторе в синтакс-помощнике появится ветка «Некоторые объекты Automation». CHM-файл справки на русском языке по встроенным константам и функциям языка VBScript вы можете скачать здесь. Примеры работы с объектом Microsoft Script Control вы можете также получить, рассмотрев код маленькой конфигурации для 1С:Предприятия v7.7 «Администратор 1С», которую вы можете скачать на главной страничке этого сайта.

Примеры работы

Функция читает список компьютеров, зарегистрированных в доменах локальной сети, и возвращает таблицу значений с колонками «Домен» и «Компьютер»:

Функция читает список зарегистрированных информационных баз 1С из реестра Windows и возвращает таблицу значений с колонками «Название» и «Путь»:

Процедура делает Log Off (Парам=4), Shutdown (Парам=5) или Reboot (Парам=6) выбранному компьютеру:

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

Введение

При разработке настраиваемых информационных систем часто возникает необходимость добавить в свою программу встроенный язык программирования. Такой язык позволял бы конечным пользователям настраивать поведение программы без участия автора и перекомпиляции. Однако самостоятельная реализация интерпретатора является непосильной для многих разработчиков задачей, а от большинства остальных потребует очень много времени и усилий.

В то же время в Windows, как правило, уже имеется достаточно качественный интерпретатор, который может быть легко встроен в вашу программу. Речь идет о Microsoft ScriptControl. Он устанавливается вместе с Microsoft Internet Explorer, входит в Windows 2000 и Windows 98, а для младших версий доступен в виде свободно распространяемого отдельного дистрибутива, объем которого составляет около 200 Кбайт. Его можно получить по адресу http://msdn.microsoft.com/scripting или установить с нашего компакт-диска. В дистрибутив входят ActiveX-компонент и файл помощи с описанием его свойств и методов.

Добавление TScriptControl в программу

Импорт ActiveX-сервера

Чтобы добавить Microsoft ScriptControl на палитру компонентов Delphi, необходимо импортировать компонент ActiveX под названием Microsoft ScriptControl.

После этого на закладке ActiveX появится невизуальный компонент TScriptControl, который можно разместить на форме.

Настройка свойств и вызов скриптов

Рассмотрим ключевые свойства и методы TScriptControl.

property Language: String

Задает язык, интерпретатор которого будет реализовывать компонент. В стандартной поставке доступны VBScript и JScript, однако, если в вашей системе установлены расширения Windows Scripting, возможно использование других языков, таких как Perl или Rexx.

property Timeout: Integer

Задает интервал исполнения скрипта, по истечении которого генерируется ошибка. Значение –1 позволяет отключить ошибки, связанные с истечением отведенного времени (timeout), что позволит скрипту исполняться неограниченное время.

property UseSafeSubset: Boolean

При установке этого свойства в TRUE компонент может выполнять ограниченный набор действий, заданный текущими установками безопасности в системе. Это свойство полезно, если вы запускаете скрипты, полученные, например, через Интернет.

procedure AddCode(const Code: WideString);

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

function Eval(const Expression: WideString): OleVariant

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

procedure AddObject(const Name: WideString; Object_: IDispatch; AddMembers: WordBool);

Добавляет объект к пространству имен компонента. Объект должен быть сервером автоматизации. Добавленный объект доступен как объект в коде скрипта. Например, если в программе создан сервер автоматизации External, реализующий метод DoSomething(Value: Integer), то, добавив объект

мы можем в коде скрипта использовать его следующим образом:

function Run(const ProcedureName: WideString; var Parameters: PSafeArray): OleVariant;

Выполняет именованную процедуру из числа ранее добавленных при помощи метода AddCode. В массиве Parameters могут быть переданы параметры.

Сбрасывает компонент в начальное состояние, удаляя все добавленные ранее объекты и код.

Таким образом, TScriptControl представляет собой достаточно гибкую исполняющую систему с возможностями расширения путем добавления в ее пространство имен серверов автоматизации.

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

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

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

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

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

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

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

Интерфейс IDispatch

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

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

function GetIdsOfNames

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

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

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

function Invoke

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

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

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

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

DISPATCH_METHOD Вызывается метод. Если у объекта есть свойство с таким же именем, то будет установлен также флаг DISPATCH_PROPERTYGET
DISPATCH_PROPERTYGET Запрашивается значение свойства
DISPATCH_PROPERTYPUT Устанавливается значение свойства
DISPATCH_PROPERTYPUTREF Параметр передается по ссылке. Если флаг не установлен – по значению.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Пишем GetIdsOfNames

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

Свойства компонентов VCL

Дополним нашу реализацию возможностью вызова некоторых дополнительных функций:

Для наследников TWinControl возвращает ссылку на дочерний компонент с именем или индексом, заданным в параметре.

Для компонентов TWinControl – возвращает количество дочерних компонентов.

Для TCollection – возвращает количество элементов.

Для TStrings – возвращает количество строк.

Для компонентов TWinControl – создает дочерний компонент.

Для TCollection – добавляет элемент в коллекцию.

Для TStrings – добавляет строку.

Возвращает истину, если у объекта есть свойство с заданным именем.

Для этого дополним метод GetIdsOfNames следующим кодом:

Константы DISPID_CONTROLS, DISPID_COUNT и т.д. определены как целые числа из диапазона 1…1 000 000. Это вполне безопасно, поскольку адрес структуры TPropInfo никак не может оказаться менее 1 Мбайт.

Читайте также:  Обучение mac os для начинающих
Оцените статью