Многие из читателей наверняка пробовали свои силы в написании макросов в Word, Excel, Access и других продуктов Microsoft. А многие программисты завидовали Word и мечтали встроить и в свои приложения поддержку Макрокоманд.
С начать
Конечно настоящие программисты пишут свой собственный интерпретатор макрокоманд. НО поскольку мы еще не совсем законченные программисты, то нам естественно не хочется возится с написанием собственных разборщиков синтаксиса, исполнителей команд и т.п. Вот если бы найти такой компонент, который бы принимал исходный текст макроса и выводил результат. К счастью несчастных программистов и здесь пришла им на помощь всеми гонимая Microsoft, разработав Windows Script Control - компонент соответствующий почти всем необходимым требованиям по поддержке макросов в ваших программах.
Итак для начала нам понадобится сам компонент Windows Script Control, который можно загрузить с сайта разработчика ( название архива sct10en.exe ). Распаковав его мы увидим сам компонент msscript.ocx и дополнительные файлы справки.
Теперь можно смело браться за разработку поддержки макросов в вашем приложении.
Пример 1
Итак к этому времени вы уже запустили среду разработки (которая естественно должна поддерживать работу с ActiveX к примеру Delphi), и создали новое приложение (New -> Application).
Теперь нам надо импортировать данные из библиотеки msscript.ocx в наш проект. Для этого воспользуемся пунктом меню Project->Import Type Library и для достоверности выберем нашу библиотеку щелкнув на кнопке Add:
После этого выберем файл msscript.ocx.
Импортировав библиотеку мы обнаружим в составе нашего проекта файл MSScriptControl_TLB.pas в котором содержатся все необходимые определения интерфейсов и констант. Теперь в главной форме нашего приложения в реакции кнопки (которую мы уже разместили на форме) напишем следующий код:
procedure TForm1.Button2Click(Sender: TObject);
var SC:TScriptControl;
Code:WideString;
begin
SC:=TScriptControl.Create(Self);
SC.Language:='VBScript';
try
Code:='Function DoSmth() '#13#10+
'DoSmth = "This is the Simple Test"'#13#10+
'End Function';
SC.AddCode(Code);
SC.ExecuteStatement('MsgBox "Testing:"+DoSmth()');
finally
SC.Free;
end;
end;
После выполнения этого кода на мы увидим на экране сообщение системы (Testing:This is the Simple Test).
Давайте теперь рассмотрим приведенный выше код более подробно. Итак сперва мы создаем объект TScriptControl, который собственно и проделывает за нас всю грязную работу. Далее мы присваиваем свойству Language значение "VBScript" уведомляя тем самым компонент о том, что переданный ему код будет написан на Visual Basic. Тут возможны разные значения кроме VBScript можно воспользоваться JScript при этом будет использован синтаксис JavaScript или же любого другого интерпретатора поддерживающего технологию ActiveX скриптов (Visual Basic, Java, ActivePython, ActivePerl и т.п).
В следующих строчках мы пишем исходный код функции DoSmth которая возвращает нам вторую часть нашего предложения. Далее мы записываем этот код в компонент, а в следующей строчке исполняем его передавая возвращаемое им значение в функцию MsgBox. Все это пишется с использованием синтаксиса Visual Basic. Функции AddCode и ExecuteStatement имеют следующий вид: procedure AddCode(const Code: WideString); safecall;
где Code - код процедуры, функции или любого их сочетания и в любом количестве, который записывается в компонент и может после этого вызван с помощью ExecuteStatement или Run. procedure ExecuteStatement(const Statement: WideString); safecall;
где Statement - текст программы который будет сразу же исполнен.
Пример 2
Вывод сообщений при помощи макроязыка мы уже научились, но это не единственная возможность компонента. Так компонент TScriptControl представляет нам возможность использования собственной объектной модели в создаваемых макросах т.е. доступ к специфическим объектам нашего приложения. Для этого нам сначала потребуется создать объект автоматизации Automation Object в нашем приложении (пользователи Microsoft Visual Basic могут пропустить этот раздел так как в Visual Basic изначально встроена поддержка объектов автоматизации). Для этого при открытом приложении щелкнем на пункте меню "Новый" и выберем закладку ActiveX. Здесь выберем пункт Automation Object.
Далее нам предстоит создать интерфейс который мы собираемся включить в объектную модель ScriptControl. Для начала мы просто создадим объект с единственной функцией "print", которая будет выводить в компонент TListBox размещенный на главной форме некоторый текст. Все существенные настройки показаны на рис.2.
Далее мы обновляем информацию о нашем объекте щелкнув на соответствующей кнопке (рис.2) и переходим к секции реализации объекта.
Здесь уже нас поджидает шаблон созданный средой разработки, в который остается внести только некоторые исправления:
Теперь мы один раз прогонем наше приложение в холостую для регистрации и проверки на наличие ошибок. Если все прошло удачно, то можно приступать к даленйшему написанию макросов.
Регистрация объекта
Как и в прошлый раз создадим на нашей главной форме кнопку и объект ListBox1. Затем в реакцию кнопки на нажатие мы напишем следующий код:
procedure TForm1.Button1Click(Sender: TObject);
var SC:TScriptControl;
Test:ISimpleTest;
begin
SC:=TScriptControl.Create(Self);
Test:=CoSimpleTest.Create;
try
SC.Language:='VBScript';
SC.AddObject('PrintTest',Test,True);
SC.ExecuteStatement('PrintTest.Print "This is the Test"');
finally
Test:=nil;
SC.Free;
end;
end;
Как и в прошлый раз сначала мы создаем наш компонент ScriptControl, затем инициализируем интерфейс ISimpleText и добавляем его в нашу объектную модель посредством функции: procedure AddObject(const Name: WideString; const Object_: IDispatch; AddMembers: WordBool); safecall;
где
Name - название нашего компонента во внутреннем пространстве имет
Object - ссылка на нащ объект
AddMembers - опциональный параметр, который устанавливается в True если все члены класса Object должны быть доступны глобально и False в противном случае.
Слудующая строка кода демонстрирует использование объекта Test при написании макроса. Как видно в тексте макроса мы пользуемся названием определенным при помощи параметра Name функции AddObject. Результат показан на рис.3
Послесловие
Этот краткий экскурс в практику создания расширяемых приложений предназначен в первую очередь для тех кто как и автор находится в поиске изящных и быстрых решений повседневных задач. В место того чтоб для добавления небольшой функции в уже отлаженное и нормально работающее приложение переписывать часть кода заново, опасаясь при этом возникновения ошибок времени выполнения, можно один раз реализовать поддержку макросов в своем приложении, а затем предоставить пользователям возможность использовать макросы для внедрения тех или иных функциональных возможностей в приложение, в то же время оставив за собой возможность последующей доработки и усовершенствования приложения без потери наработок созданных при помощи макросов.
Более того в составе библиотеки кроме компонента ScriptControl имеется еще ряд компонентов (IScriptError, IScriptModule, IScriptModuleCollection, IScriptProcedure, IScriptProcedureCollection), которые позволяют более тонко наладить работу интерпретатора.
Некоторые методы и свойства компонента ScriptControl
Член класа
Описание
AddCode
Запись в компонент исходных текстов процедур и функций для последующего их выполнения
AddObject
Добавление объекта к внутренней объектной модели макросов
Eval
Выполнение вычисления и возврат результата. То же что и if в нормальных языках программрования
ExecuteStatement
Немедленное выполнение представленного кода
Reset
Восстановление первоначального состояния интерпретатора. Очистка от всех предыдущих исходных кодов
Run
Выполнение предопределенной при помощи AddCode процедуры или функции с заданными параметрами.