Delphi部分:

我有一个带有该事件的类,从该事件中我需要调用一个将接口(interface)对象传递给它的过程。它在Delphi中工作正常,但是在Pascal Script中声明它时遇到了问题。

对于后台-IGPGraphics接口(interface)是 Delphi GDI+ library 的一部分,并且没有如下定义的方法:

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

以下只是我需要在Pascal脚本中执行的简化的Delphi伪代码:
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 Script中提供带有事件的类,并且需要像上面那样将接口(interface)对象传递给该过程,因此,我首先尝试在编译时声明此时间(但我什至不确定是否这是正确的方法):
// 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脚本运行时部分:

我绝对迷失的地方是运行时部分。我不知道如何从调用堆栈中获取接口(interface)对象并将其传递给我的RenderObject过程:
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;

而问题是:

谁能建议我这种情况下如何正确定义编译和运行时部分,或者通过某种方式传递接口(interface)对象来纠正我?

P.S.对于该Inno-Setup标签感到抱歉,但也许那里的某个人试图以此方式自定义InnoSetup。

非常感谢!

最佳答案

如果我了解您的要求,则希望将接口(interface)作为参数传递给方法。不幸的是,我没有确切的答案,但是我知道如何为PascalScript的全局变量分配接口(interface)。这是我在Castalia中的做法:

在PSScript OnCompile事件中,使用PS.Comp.AddInterface添加接口(interface),然后添加每个必需的方法。之后,添加接口(interface)类型的变量。看起来像这样,例如:

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事件中,将先前创建的变量绑定(bind)到实例:
P := PS.GetVariable('Clipboard'); //P is type PIFVariant
SetVariantToInterface(P, Implementing object as ICastaliaMacroClipboardAccess);

完成此操作后,脚本可以通过变量访问接口(interface)对象,因此在此实例中,脚本可以包含对Clipboard.GetText的调用,并且可以按预期工作。

那是经过测试并且可以工作的。

现在,我推测您可能可以使用TPSScript.ExecuteFunction从上方传入PIFVariant,使其更接近您想要的内容。但是,那不是我测试过的东西。

祝你好运!

10-07 19:10
查看更多