如何通过接口对象的Pascal脚本函数调用?(How to pass the interfaced

2019-09-19 09:29发布

德尔福部分:

我有一类事件,并从该事件中,我需要调用一个程序接口的对象传递给它。 它工作正常在Delphi中,但我有在Pascal脚本宣布它的问题。

到背景- IGPGraphics接口是的一部分Delphi GDI+ library并且没有被定义像这样的方法:

type
  IGdiplusBase = interface
  ['{24A5D3F5-4A9B-42A2-9F60-20825E2740F5}']
  IGPGraphics = interface(IGdiPlusBase)
  ['{57F85BA4-CB01-4466-8441-948D03588F54}']

以下仅仅是我所需要的Pascal脚本做一个简化的德尔福伪代码:

type
  TRenderEvent = procedure(Sender: TObject; const GPGraphics: IGPGraphics) of object;
  TRenderClass = class(TGraphicControl)
  private
    FOnRender: TRenderEvent;
  public
    property OnRender: TRenderEvent read FOnRender write FOnRender;
  end;

// when the TRenderClass object instance fires its OnRender event I want to call 
// the RenderObject procedure passing the IGPGraphics interfaced object to it; I
// hope I'm doing it right, I'm just a newbie to this stuff - but it works so far
// in Delphi (since I didn't get it to work in Pascal Script)

procedure TForm1.RenderClass1Render(Sender: TObject; const GPGraphics: IGPGraphics);
begin
  RenderObject(GPGraphics, 10, 10);
end;

// what I need in Pascal Script is between these two lines; just pass the interface
// object from the event fired by component to the procedure called from inside it

procedure RenderObject(const GPGraphics: IGPGraphics; X, Y);
begin
  // and here to work with the interfaced object somehow
end;

Pascal脚本编译部分:

我的目标是与事件Pascal脚本可用的类,需要的是接口的对象传递给该过程就像上面,所以我第一次尝试申报编译时间这个(但我也不知道这是这样做)的正确方法:

// the interface
PS.AddInterface(Cl.FindInterface('IUnknown'), StringToGuid('{57F85BA4-CB01-4466-8441-948D03588F54}'), 'IGPGraphics');
// the type for the event
PS.AddTypeS('TRenderEvent', 'procedure(Sender: TObject; const GPGraphics: IGPGraphics)');
// and the class with the event itself
with PS.AddClassN(PS.FindClass('TGraphicControl'), 'TRenderClass') do
begin
  RegisterProperty('OnRender', 'TRenderEvent', iptrw);
end;

Pascal脚本运行时的部分:

凡我肯定失去是运行时的一部分。 我无法弄清楚如何从调用堆栈获取接口对象,并把它传递给我的渲染对象的过程:

function RenderClassProc(Caller: TPSExec; Proc: TPSExternalProcRec; Global, 
  Stack: TPSStack): Boolean;
var
  PStart: Cardinal;
begin
  PStart := Stack.Count-1;
  Result := True;
  if Proc.Name = 'RENDEROBJECT' then
  begin
    // how do I get the interfaced object from Stack (or whatever else) and pass 
    // it to the RenderObject proc here ? I can't find anything related about it
    // except functions that has no parameter index
    RenderObject(Stack.Get ?, Stack.GetInt(PStart-2), Stack.GetInt(PStart-3));
  end;
end;

而问题是:

任何人都可以建议我如何正确定义编译和运行一部分这种情况下或以某种方式传递接口对象指正?

PS为InnoSetup标签抱歉,但也许从那里有人试图自定义InnoSetup这样。

非常感谢!

Answer 1:

如果我知道你要问什么,你想传递一个接口作为参数的方法。 不幸的是,我没有一个确切的答案,但我知道如何将接口分配为PascalScript一个全局变量。 下面是我如何做到这一点的CASTALIA:

在PSScript OnCompile事件,添加界面PS.Comp.AddInterface,然后添加每一个的必要方法。 在此之后,添加接口类型的变量。 它看起来像这样,例如:

with PS.Comp.AddInterface(ARunner.Comp.FindInterface('IUnknown'),
  StringToGUID('{0346F7DF-CA7B-4B15-AEC9-2BDD680EE7AD}'),
  'ICastaliaMacroClipboardAccess') do
begin
  RegisterMethod('function GetText: string', cdRegister);
  RegisterMethod('procedure SetText(AText: string)', cdRegister);
end;
PS.AddRegisteredVariable('Clipboard', 'ICastaliaMacroClipboardAccess');

然后,在OnExectute事件,结合以前创建的变量,实例:

P := PS.GetVariable('Clipboard'); //P is type PIFVariant
SetVariantToInterface(P, Implementing object as ICastaliaMacroClipboardAccess);    

已经这样做了,剧本已经通过变量访问接口的对象,所以在这种情况下,该脚本可以包含对Clipboard.GetText一个电话,和它的作品如你所愿。

这是测试和工程。

现在,我会猜测,你可能能够使用TPSScript.ExecuteFunction,在PIFVariant通过从上面来接近你想要什么。 这是不是我测试过,但是。

祝好运!



Answer 2:

这是很难相信,但我发现了怎么办呢

procedure TApp.CallProcedureWithClassArg(x: TPSExec);
var
  o: TSampleObject;
  argumentList: TPSList;
  arg1: TPSVariantClass;
  proc: Integer;
begin
  o := TSampleObject.Create;
  o.X := 1; // do something with the object maybe
  proc := x.GetProc('TakeThis');
  argumentList := TPSList.Create;
  arg1.VI.FType := x.FindType2(btClass);
  arg1.Data := o;
  argumentList.Add(@arg1);
  x.RunProc(argumentList, proc);
  argumentList.Free;
end;

这基本上就是应该做的。

  • 用户的TPSExec例如,假设X
  • 然后使用x.GetProc方法获得程序数
  • 然后创建TPSList类型的参数列表
  • 创建TPSVariantClass VAR,您的类的实例(应该通过)分配给它的数据字段
  • 还可以指派x.FindType2(btClass)其VI.FType场(绝对不知道为什么这工作)
  • 指针TPSVariantClass变量添加到列表TPSList
  • 而.......调用过程x.RunProc(ARGLIST,PROC); 其中PROC是以前获得的过程的数量

这适用于类,但它应该是接口没有太大的区别,只是使用TPSVariantInterface类型参数变量代替TPSVariantClass; 一切应该是相同的

我希望这会帮助别人,也许。



文章来源: How to pass the interfaced object to the Pascal Script function call?