【问题标题】:DWScript: Getting from IScriptObj to IInfo or TProgramInfoDWScript:从 IScriptObj 到 IInfo 或 TProgramInfo
【发布时间】:2014-12-16 14:59:30
【问题描述】:

给定一个IScriptObj 引用,如何获得对应的IInfoTProgramInfo


我有一个包含 Delphi 对象的脚本对象。

为了管理脚本对象的生命周期,Delphi 对象存储了对脚本对象的引用。 Script 对象用TdwsUnit 组件声明。这是相当标准的,是这样的:

德尔福

type
  TDelphiObject = class
  private
    FScriptObject: IScriptObj;
  public
    procedure DoSomething;
    property ScriptObject: IScriptObj read FScriptObject write FScriptObject;
  end;

脚本

type
  TScriptObject = class
  protected
    procedure DoSomething; virtual;
  public
    constructor Create;
  end;

Delphi 对象的实例化和 Delphi/脚本链接的设置发生在脚本对象构造函数的 Delphi 实现中。也很标准:

德尔福

// Implements TScriptObject.Create
procedure TMyForm.dwsUnitClassesTScriptObjectConstructorsCreateEval(Info: TProgramInfo; var ExtObject: TObject);
var
  DelphiObject: TDelphiObject;
  DelphiObjectInfo: IInfo;
begin
  // Create the Delphi-side object
  DelphiObject := TDelphiObject.Create;

  // Get the script object "self" value
  DelphiObjectInfo := Info.Vars['self'];

  // Store the ScriptObject reference
  DelphiObject.ScriptObject := DelphiObjectInfo.ScriptObj;

  // Return the instance reference to the script
  ExtObject := DelphiObject;
end;

理想情况下,我会保存IInfo 引用而不是IScriptObj,因为IInfo 可以完成我以后需要的所有操作,但根据经验,IInfo 对象似乎仅在方法调用期间有效.

无论如何,稍后在 Delphi 端调用 TDelphiObject.DoSomething 时会出现问题。 TDelphiObject.DoSomething 的意思是调用脚本对象上对应的虚方法:

德尔福

procedure TDelphiObject.DoSomething;
var
  Info: IInfo;
  DoSomethingInfo: IInfo;
begin
  // I have a IScriptObj but I need a IInfo...
  Info := { what happens here? };

  // Call the virtual DoSomething method
  DoSomethingInfo := Info.Method['DoSomething'];
  DoSomethingInfo.Call([]);
end;

我尝试了很多不同的技术来从存储的IScriptObj 中获取可用的IInfoTProgramInfo,但一切都失败了。那么正确的做法是什么?

【问题讨论】:

  • 我对 DWScript 没有太多经验,但您确定您调用脚本方法的方式正确吗?基于对 DWS Wiki (code.google.com/p/dwscript/wiki/FirstSteps#Functions) 的快速浏览,正确的调用将是 "Info.Method['DoSomething'].Call([]);"
  • 这两个表达式是等价的; Method[] 属性返回一个 IInfo 接口引用。
  • 你能显示TProgramInfo的声明吗?
  • 还有什么不工作?你有错误吗?还是什么都没发生?
  • TProgramInfoDWScript class。这不是一个通用的 Delphi 问题。它特定于 DWScript 的使用。问题是 DWScript,除了最基本的使用外,几乎完全没有文档记录。源的评论很差,所以我基本上不得不对其进行逆向工程以了解发生了什么,显然我在这方面失败了。我知道如何从 A 到 B,但我需要的是一种从 B 到 A 的方法(上面源示例中的“这里发生了什么”注释)。

标签: delphi dwscript


【解决方案1】:

问题原来是我认为我需要一个IInfo 接口来封装对象实例,但显然 DWScript 不能那样工作。我需要创建一个指向实例的临时引用/指针,然后在其上创建一个IInfo

这是如何完成的:

procedure TDelphiObject.DoSomething;
var
  ProgramExecution: TdwsProgramExecution;
  ProgramInfo: TProgramInfo;
  Data: TData;
  DataContext: IDataContext;
  Info: IInfo;
  DoSomethingInfo: IInfo;
begin
  (*
  ** Create an IInfo that lets me access the object represented by the IScriptObj pointer.
  *)

  // FProgramExecution is the IdwsProgramExecution reference that is returned by
  // TdwsMainProgram.CreateNewExecution and BeginNewExecution. I have stored this
  // elsewhere.
  ProgramExecution := TdwsProgramExecution(FProgramExecution);
  ProgramInfo := ProgramExecution.AcquireProgramInfo(nil);
  try
    // Create a temporary reference object
    SetLength(Data, 1);
    Data[0] := FScriptObject;
    ProgramInfo.Execution.DataContext_Create(Data, 0, DataContext);
    // Wrap the reference
    Info := TInfoClassObj.Create(ProgramInfo, FScriptObject.ClassSym, DataContext);


    // Call the virtual DoSomething method
    DoSomethingInfo := Info.Method['DoSomething'];
    DoSomethingInfo.Call([]);

  finally
    ProgramExecution.ReleaseProgramInfo(ProgramInfo);
  end;
end;

这样做是启用从 Delphi 到脚本的面向对象的回调。如果没有这个,就只能从 Delphi 调用全局脚本函数。

FWIW,以上两行:

ProgramInfo.Execution.DataContext_Create(Data, 0, DataContext);
Info := TInfoClassObj.Create(ProgramInfo, FScriptObject.ClassSym, DataContext);

可以替换为对CreateInfoOnSymbol的调用(在dwsInfo中声明):

CreateInfoOnSymbol(Info, ProgramInfo, FScriptObject.ClassSym, Data, 0);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多