使用RemObjects Pascal Script
摘自RemObjects Wiki
本文提供RemObjects Pascal Script的整体概要并演示如何创建一些简单的脚本.
Pascal Script包括两个不同部分:
- 编译器 (uPSCompiler.pas)
- 运行时 (uPSRuntime.pas)
两部分彼此独立.可以分开使用,或通过TPSScript 控件使用他们,这个控件定义在uPSComponent.pas单元,对这两个部分进行简易封装.
要使用控件版本的Pascal Script,首先要将控件放在窗体或data module上,并设置script属性,调用Compile和Execute方法.编译的错误,警告,提示可在CompilerMessages数组属性中获取,同样运行时错误存储在ExecErrorToString属性中.
下面的范例将编译并执行一个空脚本("begin end."):
var
Messages: string;
compiled: boolean;
begin
ce.Script.Text := 'begin end.';
Compiled := Ce.Compile;
for i := 0 to ce.CompilerMessageCount -1 do
Messages := Messages +
ce.CompilerMessages[i].MessageToString +
#13#10;
if Compiled then
Messages := Messages + 'Succesfully compiled'#13#10;
ShowMessage('Compiled Script: '#13#10+Messages);
if Compiled then begin
if Ce.Execute then
ShowMessage('Succesfully Executed')
else
ShowMessage('Error while executing script: '+
Ce.ExecErrorToString);
end;
end;
默认情况下,控件只向脚本引擎添加少数几个标准函数(具体函数可从uPSComponents.pas单元顶部获取).
除了标准函数,Pascal Script还包含几个函数库:
TPSDllPlugin |
允许脚本使用DLL中的导出函数,语法: |
TPSImport_Classes |
导入Tobject和Classes单元. |
TPSImport_DateUtils |
导入date/time相关函数. |
TPSImport_ComObj |
在脚本中可使用COM对象. |
TPSImport_DB |
导入db.pas. |
TPSImport_Forms |
导入Forms及Menus单元. |
TPSImport_Controls |
导入Controls.pas和Graphics.pas单元. |
TPSImport_StdCtrls |
导入ExtCtrls和Buttons. |
要使用这些库,将相应控件添加到窗体或Data Module中,选择TPSCompiler控件点击plugins属性后的[...]按钮,增加一个新项并设置其Plugin属性为特定的插件控件.除了这些标准库函数,还可以轻松的向脚本引擎添加新函数.为了实现这个目的,首先创建要导出给脚本引擎的函数,例如:
procedure TForm1.ShowNewMessage(const Message: string);
begin
ShowMessage('ShowNewMessage invoked:'#13#10+Message);
end;
然后,实现TPSCompile控件的OnCompile事件,使用AddMethod方法注册实际方法:
procedure TForm1.CECompile(Sender: TPSScript);
begin
Sender.AddMethod(Self, @TForm1.ShowNewMessage,
'procedure ShowNewMessage
(const Message: string);');
end;
在脚本中调用方式:
begin
ShowNewMessage('Show This !');
end.
高级特性
Pascal脚本支持预编译,可以使用{$IFDEF}, {$ELSE}, {$ENDIF}指令,而且可以使用{$I filename.inc}指令将其他文件内容引入脚本中.为了使用这个特性,必须设置UsePreprocessor属性为True,而且MainFileName属性必须与Script属性中的脚本名称相匹配.Defines属性指定预定义指令,在OnNeedFile事件中处理引入其他文件.
function TForm1.ceNeedFile(Sender: TObject;
const OrginFileName: String;
var FileName, Output: String): Boolean;
var
path: string;
f: TFileStream;
begin
Path := ExtractFilePath(ParamStr(0)) + FileName;
try
F := TFileStream.Create(Path, fmOpenRead or fmShareDenyWrite);
except
Result := false;
exit;
end;
try
SetLength(Output, f.Size);
f.Read(Output[1], Length(Output));
finally
f.Free;
end;
Result := True;
end;
当设置了这些属性,CompilerMessages数组属性将输出包含文件的名称.
另外,你可以在Delphi中调用脚本中的函数.下面的代码定义在脚本中:
function TestFunction(Param1: Double; Data: String): Longint;
begin
ShowNewMessage('Param1: '+FloatToString(param1)
+#13#10+'Data: '+Data);
Result := 1234567;
end;
begin
end.
在使用脚本中的函数之前,必须检查函数参数与返回值类型,可在OnVerifyProc事件中进行.
procedure TForm1.CEVerifyProc(Sender: TPSScript;
Proc: TPSInternalProcedure;
const Decl: String;
var Error: Boolean);
begin
if Proc.Name = 'TESTFUNCTION' then begin
if not ExportCheck(Sender.Comp, Proc,
[btS32, btDouble, btString], [pmIn, pmIn]) then begin
Sender.Comp.MakeError('', ecCustomError, 'Function header for
TestFunction does not match.');
Error := True;
end
else begin
Error := False;
end;
end
else
Error := False;
end;
ExportCheck函数检查参数是否匹配.本例中,btu8是boolean (返回值类型), btdouble是第一个参数, btString是第二个参数.[pmIn, pmIn]指示两个参数都是IN参数.要调用这个脚本函数还需要为这个函数创建一个事件声明.
type
TTestFunction = function (Param1: Double;
Data: String): Longint of object;
//...
var
Meth: TTestFunction;
Meth := TTestFunction(ce.GetProcMethod('TESTFUNCTION'));
if @Meth = nil then
raise Exception.Create('Unable to call TestFunction');
ShowMessage('Result: '+IntToStr(Meth(pi, DateTimeToStr(Now))));
也可以向脚本引擎中添加变量,使之可在脚本中使用.可在OnExecute事件中调用AddRegisteredVariable函数实现:
procedure TForm1.ceExecute(Sender: TPSScript);
begin
CE.SetVarToInstance('SELF', Self);
// ^^^ For class variables
VSetInt(CE.GetVariable('MYVAR'), 1234567);
end;
在脚本执行完毕后,读取变量的新值,可在OnAfterExecute事件中调用: VGetInt(CE.GetVariable('MYVAR')).
向脚本引擎注册外部变量,有两个步骤,首先在OnCompile事件中,使用AddRegisteredPTRVariable函数向脚本中添加变量声明.
procedure TMyForm.PSScriptCompile(Sender: TPSScript);
begin
Sender.AddRegisteredPTRVariable('MyClass', 'TButton');
Sender.AddRegisteredPTRVariable('MyVar', 'Longint');
end;
这就将外部变量MyClass和MyVar导入了.其次,在OnExecute事件中将变量与具体指针关联:
procedure TMyForm.PSScriptExecute(Sender: TPSScript);
begin
PSScript.SetPointerToData('MyVar', @MyVar, PSScript.FindBaseType(bts32));
PSScript.SetPointerToData('Memo1', @Memo1, PSScript.FindNamedType('TMemo'));
end;
这里在脚本中有两种类型变量,基础类型(如下表的简单类型),及类类型.基础类型定义在uPSUtils.pas单元,可使用FindBaseType函数获取.类类型使用FindNamedType按名称获取.在脚本中修改变量将直接影响关联的变量.
基础类型:
btU8 |
Byte |
btS8 |
Shortint |
btU16 |
Word |
btS16 |
Smallint |
btU32 |
Longword |
btS32 |
Longint |
btS64 |
Int64 |
btSingle |
Single |
btDouble |
Double |
btExtended |
Extended |
btVariant |
Variant |
btString |
String |
btWideString |
WideString |
btChar |
Char |
btWideChar |
WideChar |
基于控件的Pascal脚本也可执行脚本函数.需要使用ExecuteFunction方法.
ShowMessage(CompExec.ExecuteFunction([1234.5678, 4321,
'test'],
'TestFunction'));
这将执行叫做'TestFunction'的函数,有三个参数,一个float类型,一个integer类型和一个string类型.返回值直接传给ShowMessage.
注意:
- 为使用一些函数和常量,有必要将uPSCompiler.pas, uPSRuntime.pas和uPSUtils.pas引入到uses中.
- 脚本引擎不会主动调用Application.ProcessMessages,导致脚本运行时应用程序挂起.为了避免这个问题,可在TPSScript.OnLine事件中调用Application.ProcessMessages.
- 如果要向脚本引擎导入自定义的类,可以使用/Unit-Importing/目录下的工具生成导入类库.
- 如果要向脚本脚本引擎导入自定义类,可使用Bin目录下的工具生成导入类库.
- 如果分开使用compiler和runtime,请见Import和Kylix范例.
- Debug范例需要控件SynEdit http://synedit.sourceforge.net.
Retrieved from "http://wiki.remobjects.com/wiki/Using_RemObjects_Pascal_Script"