简体   繁体   English

如何声明从具有过程类型参数的脚本调用的Delphi对象的方法

[英]How to declare a method of a Delphi object called from a script having a procedure type argument

In have a Delphi application running a DWS script. 有一个运行DWS脚本的Delphi应用程序。 The Delphi application exposes an object instance, let's call it "MyApplication", to the script. Delphi应用程序向脚本公开一个对象实例,我们称之为“MyApplication”。 The exposed object has a method which has one argument being a procedure. 被暴露的对象有一个方法,其中一个参数是一个过程。

Fundamentally by goal is to have a Delphi method doing some computation and stopping this computation when a callback procedure says it is done. 从根本上说,目标是让一个Delphi方法进行一些计算,并在回调程序说它完成时停止这个计算。 The callback procedure is Inside the script. 回调过程在脚本内部。

I have implemented this by passing the name of the callback function as a string. 我已经通过将回调函数的名称作为字符串传递来实现这一点。 It works nicely except that no type checking is done at script compile time. 它工作得很好,除了在脚本编译时没有进行类型检查。 I would like to pass an actual procedure so that the script compiler can catch any error at compile time. 我想传递一个实际的过程,以便脚本编译器可以在编译时捕获任何错误。

How to do that? 怎么做?

To help the reader understand what I mean, I show some - not working - code: 为了帮助读者理解我的意思,我展示了一些 - 不工作 - 代码:

First a simplified verion of the Delphi side: 首先是Delphi方面的简化版本:

Interface
type
    TAppCheckProc = procedure (var Done : Boolean);

TMyApplication = class(TPersistent)
published
    procedure Demo(CheckProc : TAppCheckProc);
end;

Implementation

TMyApplication.Demo(CheckProc : TAppCheckProc);
var
    Done : Boolean;
begin
    Done := FALSE;
    while not Done do begin
        // Some more code here...
        CheckProc(Done);
    end;
end;

Second, on the script side I have this (Also simplified ): 第二,在脚本方面我有这个(也简化 ):

procedure CheckProc(
    var Done : Boolean);
var
    Value : Integer;
begin
    DigitalIO.DataIn(1, Value);
    Done := (Value and 8) = 0;
end;

procedure Test;
begin
    MyApplication.Demo(CheckProc);
end;

It is likely that Demo method argument should be declared differently and should be called differently. Demo方法参数可能应该以不同方式声明,并且应该以不同方式调用。 That is the question... 就是那个问题...

Edit: Removed extra Tag argument (Error when simplified the code, this is not the question). 编辑:删除了额外的Tag参数(简化代码时出错,这不是问题)。

I put this together quickly and it works. 我把它快速地放在一起就可以了。 It gives a compile error when the parameters for the callback aren't correct. 当回调参数不正确时,它会产生编译错误。 You need to create a delegate and use that as the type. 您需要创建一个委托并将其用作类型。

Example using standalone function 使用独立功能的示例

dwsUnit is the TdwsUnit that is being used for the custom Delphi methods. dwsUnit是用于自定义Delphi方法的TdwsUnit。

procedure TMainForm.FormCreate(Sender: TObject);
var
  delegate: TdwsDelegate;
  func: TdwsFunction;
  parm: TdwsParameter;
begin
  // Create a delegate
  delegate := dwsUnit.Delegates.Add;
  delegate.Name := 'TAppCheckProc';
  parm := delegate.Parameters.Add;
  parm.Name := 'Done';
  parm.DataType := 'Boolean';
  parm.IsVarParam := True;

  // Create our function and link it to the event handler
  func := dwsUnit.Functions.Add;
  func.Name := 'Demo';
  func.OnEval := dwsUnitFunctionsDemoEval;
  parm := func.Parameters.Add;
  parm.Name := 'CheckProc';
  parm.DataType := 'TAppCheckProc';
end;

The script that I used to test this is as follows: 我用来测试它的脚本如下:

procedure CheckProc(
    var Done : Boolean);
begin
  if Done then
    SayHello('World');
end;

Demo(CheckProc);

If I change the parameter from a Boolean to an Integer I get a compile error on the script. 如果我将参数从布尔值更改为整数,我会在脚本上遇到编译错误。

My event handler for completeness looks like this: 我的完整性事件处理程序如下所示:

procedure TMainForm.dwsUnitFunctionsDemoEval(info: TProgramInfo);
begin
  info.Vars['CheckProc'].Call([True]);
end;

Example using classes 使用类的示例

If you want to use classes then the code would be slightly different. 如果你想使用类,那么代码会略有不同。 Assuming you are using the CustomClasses demo and wanted to use the TEarth class then this would be the code to create the method and delegate. 假设您正在使用CustomClasses演示并想要使用TEarth类,那么这将是创建方法和委托的代码。

procedure TMainForm.FormCreate(Sender: TObject);
var
  delegate: TdwsDelegate;
  method: TdwsMethod;
  parm: TdwsParameter;
begin
  // Create a delegate
  delegate := dwsUnit.Delegates.Add;
  delegate.Name := 'TAppCheckProc';
  parm := delegate.Parameters.Add;
  parm.Name := 'Done';
  parm.DataType := 'Boolean';
  parm.IsVarParam := True;

  // Create our method and link it to the event handler
  method := TdwsClass(dwsUnit.Classes.Symbols['TEarth']).Methods.Add;
  method.Name := 'Demo';
  method.OnEval := dwsUnitFunctionsDemoEval;
  parm := method.Parameters.Add;
  parm.Name := 'CheckProc';
  parm.DataType := 'TAppCheckProc';
end;

The script to use this would be: 使用它的脚本是:

procedure CheckProc(
    var Done : Boolean);
begin
  if Done then
    PrintLn('Called with true')
  else
    PrintLn('Called with false');
end;

var earth: TEarth;
earth:=TEarth.Create;
earth.Demo(CheckProc);

The event handler is as follows: 事件处理程序如下:

procedure TMainForm.dwsUnitFunctionsDemoEval(info: TProgramInfo; ExtObject:
    TObject);
begin
  info.Vars['CheckProc'].Call([True]);
end;

As with the standalone version, changing the script parameter type produces a "compiler" error. 与独立版本一样,更改脚本参数类型会产生“编译器”错误。

As SpeedFreak indicates in the comments. 正如SpeedFreak在评论中指出的那样。 You can also do this through the IDE designer instead of in code. 您也可以通过IDE设计器而不是代码执行此操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM