Delphi Web Script (DWScript) link a script method to an external control event
Asked Answered
B

2

5

I'm wondering if DWScript supports using a script method as an event handler for a control on a Delphi form. For example I want to link a TButton OnClick event to a method that exists in script.

I am able to do this with the RemObjects Delphi script engine by calling GetProcMethod which returns a TMethod object. I then use SetMethodProp to assign the script method to the OnClick event of a button.

procedure LinkMethod(SourceMethodName: String; Instance: TObject; ScriptMethodName: String);
var
  ScriptMethod: TMethod;
begin
  ScriptMethod := ScriptEngine.GetProcMethod(ScripMethodName);

  SetMethodProp(Instance, SourceMethodName, ScriptMethod);
end;

I would like to do this in DWScript instead of the Rem objects script engine as it does some other stuff that I need.

Beilul answered 23/9, 2012 at 4:3 Comment(0)
B
2

I decided to go with RemObjects instead. It was the easiest to use and does what I need.

Beilul answered 30/10, 2012 at 4:3 Comment(0)
C
1

AFAIK DWScript doesn't support directly what you're trying to achieve but it could be implemented in different manner. I'll try to post some source code how it could be implemented but you will probably need to adapt it to your needs.

First, declare a little wrapper class which should be separate for each script method:

type
  TDwsMethod = class
  private
    FDoExecute: TNotifyEvent;
    FScriptText: string;
    FDws: TDelphiWebScript;
    FLastResult: string;
    FMethod: TMethod;
  protected
    procedure Execute(Sender: TObject);
  public
    constructor Create(const AScriptText: string); virtual;
    destructor Destroy; override;

    property Method: TMethod read FMethod;
    property LastResult: string read FLastResult;
  published
    property DoExecute: TNotifyEvent read FDoExecute write FDoExecute;
  end;

constructor TDwsMethod.Create(const AScriptText: string);
begin
  inherited Create();
  FDoExecute := Execute;
  FScriptText := AScriptText;
  FDws := TDelphiWebScript.Create(nil);
  FMethod := GetMethodProp(Self, 'DoExecute');
end;

destructor TDwsMethod.Destroy;
begin
  FDws.Free;
  inherited Destroy;
end;

procedure TDwsMethod.Execute(Sender: TObject);
begin
  ShowMessage('My Method executed. Value: ' + FDws.Compile(FScriptText).Execute().Result.ToString);
end;

Now we must create an instance of this class somewhere in our code (e.g. in form's create event):

procedure TMainForm.FormCreate(Sender: TObject);
begin
  FDWSMethod := TDwsMethod.Create('PrintLn(100);'); //in constructor we pass script text which needs to be executed
  //now we can set form's mainclick event to our DWS method
  SetMethodProp(Self, 'MainClick', FDWSMethod.Method);
end;

procedure TMainForm.FormDestroy(Sender: TObject);
begin
  FDWSMethod.Free;
end;

Now when we call MainClick our script is compiled and executed:

Script method executed from form's event

Carabineer answered 2/10, 2012 at 14:21 Comment(2)
Thanks for that. Unfortunately however I won't know the name of the event of the parameters required until runtime. RemObjects handles intercepting the event call and forwarding the parameters onto the scripted event handler. This way you don't need to know anything about the method being invoked at compile time. I was hoping that DWS does something like this.Beilul
It isn't done at the moment because DWScript is meant to be fully sandboxable and aims for safety, the approach RemObject uses will result in memory corruption or crashes if there is a mismatch between parameters. The RTTI has progressed a bit on that, but it will still be vulnerable to memory leaks or AV, since there is no way to automate the memory management for Delphi events. If someone can live with those limitations and publish supporting code, I'll integrate it... with appropriate "caution" notices ;-)Propend

© 2022 - 2024 — McMap. All rights reserved.