How to pass a conjugated object to a Pascal Script function call?

Part of Delphi:

I have a class with an event, and from this event I need to call a procedure that passes an adjoining object to it. It works great in Delphi, but I have problems declaring it in Pascal Script.

In the background - the IGPGraphics interface is part of the Delphi GDI+ library and, without methods, is defined as follows:

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

Below is just a simplified Delphi pseudo-fix of what I need to do in Pascal Script:

 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 Script compilation part:

My goal is to have a class with an event available in Pascal Script and should pass this conjugate object to the same procedure as above, so first I tried to declare this for compile time (but I'm not even sure if it is The right way):

 // 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 Script execution part:

If I'm definitely lost, this is part of the runtime. I cannot figure out how to get the conjugate object from the call stack and pass it to my RenderObject procedure:

 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; 

And the question is:

Can someone suggest me how to correctly determine the compilation and part of the runtime for this case, or correct me with passing the conjugate object?

PS sorry for the Inno-Setup tag, but maybe someone out there tried to configure InnoSetup this way.

Thank you so much!

+7
source share
2 answers

If I understand what you are asking, you want to pass the interface as a parameter to the method. Unfortunately, I do not have an exact answer to this question, but I know how to assign an interface to a global variable for PascalScript. Here's how I do it in Castile:

In the PSScript OnCompile event, add an interface with PS.Comp.AddInterface, and then add each of the required methods. After that, add an interface type variable. It looks like this:

 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'); 

Then, in the OnExectute event, bind the previously created variable to the instance:

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

Having done this, the script has access to the conjugated object through a variable, so in this case the script may contain a call to Clipboard.GetText, and it works as you expected.

It is tested and works.

Now I would suggest that you can use TPSScript.ExecuteFunction by passing in a PIFVariant from above to get closer to what you want. However, this is not what I tested.

Good luck

+1
source

Hard to believe BUT I found out how to do it

 procedure TApp.CallProcedureWithClassArg(x: TPSExec); var o: TSampleObject; argumentList: TPSList; arg1: TPSVariantClass; proc: Integer; begin o := TSampleObject.Create; oX := 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; 

This is basically what needs to be done.

  • The user of your TPSExec instance, say x
  • Then enter the procedure number using the x.GetProc method
  • then create a list of arguments like TPSList
  • Create the variable TPSVariantClass var, assign your instance of the class (which should be passed) in the data field
  • also assign x.FindType2 (btClass) to its VI.FType field (I have no idea why this works)
  • add a pointer to the variable TPSVariantClass in the list of TPSList
  • And ....... Call the procedure x.RunProc (argList, proc); where proc is the number of the procedure received earlier

This works for classes, but for interfaces it shouldn't differ much, just use the type TPSVariantInterface for the argument variable instead of TPSVariantClass; everything else should be the same .

Hope this helps someone.

+1
source

All Articles