Delphi部分:
我有一个带有事件的类,从那个事件我需要调用一个将interfaced对象传递给它的过程。它在Delphi中工作正常,但我在Pascal脚本中声明它有问题。
到后台 - IGPGraphics
接口是Delphi GDI+ library
的一部分,没有方法定义如下:
type
IGdiplusBase = interface
['{24A5D3F5-4A9B-42A2-9F60-20825E2740F5}']
IGPGraphics = interface(IGdiPlusBase)
['{57F85BA4-CB01-4466-8441-948D03588F54}']
以下是我在Pascal Script中需要做的简化的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脚本中的事件可用,并且需要像上面那样将该interfaced对象传递给该过程,所以第一次尝试为编译时声明这个(但我不是甚至确定这是否是正确的方法):
// 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脚本运行时部分:
我绝对丢失的是运行时部分。我无法弄清楚如何从调用堆栈中获取interfaced对象并将其传递给我的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;
问题是:
有人可以建议我如何正确定义此案例的编译和运行时部分,或以某种方式通过传递接口对象来纠正我吗?
P.S。对于那个Inno-Setup标签感到抱歉,但也许某人从那里试图以这种方式自定义InnoSetup。
非常感谢!
答案 0 :(得分: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);
完成此操作后,脚本可以通过变量访问interfaced对象,因此在这个实例中,脚本可以包含对Clipboard.GetText的调用,并且它可以正常工作。
经过测试和运作。
现在,我推测您可以使用TPSScript.ExecuteFunction,从上面传入PIFVariant,以更接近您想要的。然而,这不是我测试过的。
祝你好运!答案 1 :(得分:1)
很难相信,但我发现了如何做到这一点
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;
这基本上应该做什么。
这适用于类,但接口应该没有太大的不同,只需使用TPSVariantInterface类型作为参数变量而不是TPSVariantClass;其他一切都应该是相同。
我希望这可以帮助某些人。