Andre1
Members-
Content Count
7 -
Joined
-
Last visited
Everything posted by Andre1
-
Extract public parts of a given Delphi unit source code file
Andre1 posted a topic in Delphi IDE and APIs
Hi, I have written a library to make use of Firemonkey from the programming language D. Therefore I need to generate D wrapper classes / structures / enumerations for the Delphi classes / records /.... Sample: alias TCloseEvent = void delegate(TObject sender, ref TCloseAction action); alias TCloseQueryEvent = void delegate (TObject sender, ref bool canClose); enum TDeviceKind { Desktop, iPhone, iPad }; enum TFormPosition {Designed, Default, DefaultPosOnly, DefaultSizeOnly, ScreenCenter, DesktopCenter, MainFormCenter, OwnerFormCenter}; alias TDeviceKinds = TDeviceKind[]; // TODO Set of TDeviceKinds class TFormFactor: TPersistent { mixin(GenSetProperty!("Devices", TDeviceKind)); mixin(GenIntProperty!("Height")); mixin(GenIntProperty!("Width")); this(int reference) { super(reference); } } This is a manual and error prone effort. I wonder whether there is maybe a tool included in Delphi which gives me the info about the classes / records / ... for a given Delphi unit source code file like FMX.Forms.pas. Best solution would be if I can get the info as JSON / XML after the IFDEFs are sorted out by the compiler... Based on the JSON then I could easily generate the D artifacts. Is there something like this available? Kind regards André -
Extract public parts of a given Delphi unit source code file
Andre1 replied to Andre1's topic in Delphi IDE and APIs
@Fr0sT.Brutal Thank you. -
Hi, I have written a wrapper library to make use of Firemonkey from the programming language D. A simple example looks like this: import delta.core; import System.Classes, System.UITypes, FMX.Forms, FMX.Types, FMX.Memo; void main() { deltaLibrary.load(`.\views\Win32\Debug\Project1.dll`); Application.Initialize; Application.MainForm = TCustomForm.CreateNew(Application); Application.MainForm.Caption = "Sample"; auto memo = TMemo.Create(Application.MainForm); memo.Lines.Add("Hello World!"); memo.Align = TAlignLayout.Client; memo.Parent = Application.MainForm; Application.MainForm.Show(); Application.Run(); } The Project1.dll is written in Delphi and provides generic functions for dynamically creating Delphi class instances and calling their methods. While this is working fine, I have issues calling method which have record arguments. Example TCanvas.DrawLine has two time the record type TPointF: procedure DrawLine(const APt1, APt2: TPointF; const AOpacity: Single); overload; Within my DLL I have a generic function to call instance methods which have exactly this kind of arguments (record, record, single) procedure executeInstanceMethodReturnNoneArgsStructStructFloat(const Reference: Integer; const AName: PAnsiChar; Reference2, Reference3: Integer; s: Single); stdcall; begin // What needs to be done here executeInstanceMethod(Reference, string(AName), [???]); end; function executeInstanceMethod(const Reference: Integer; const AName: string; const Args: array of TValue): TValue; var context: TRttiContext; instType: TRttiInstanceType; obj: TObject; begin context := TRttiContext.Create; try try obj := TObject(Reference); instType := (context.GetType(obj.ClassType) as TRttiInstanceType); result := instType.GetMethod(AName).Invoke(obj, Args); except on E: Exception do writeln(E.ClassName + ' error raised, with message : ' + E.Message); end; finally context.Free; end; end; (Argument Reference has the class reference to e.g. TCanvas, AName has the method name e.g. DrawLine. After that the actual methods of DrawLine are following). From my application written in D I want to call executeInstanceMethodReturnNoneArgsStructStructFloat and pass references to records (D structs binary compatible with the Delphi records). Within the Delphi procedure executeInstanceMethodReturnNoneArgsStructStructFloat these record references should be converted into something which can be used by TRttiMethod.Invoke. Is this technically possible and can you give me a hint or an example how the coding in executeInstanceMethodReturnNoneArgsStructStructFloat should look like? Kind regards André
-
Dynamic method call with record references
Andre1 replied to Andre1's topic in RTL and Delphi Object Pascal
@Fr0sT.Brutal Thank you so much Kind regards André -
Dynamic method call with record references
Andre1 replied to Andre1's topic in RTL and Delphi Object Pascal
By adding 2 more integer fields to record: TDateRec = record Year: Integer; Month: Integer; Day: Integer; end; the error messages changes to "var- and out arguments must exactly match". Is my understanding correct, that rtti does not support calling the method and passing the record reference as untyped pointer? Kind regards André -
Dynamic method call with record references
Andre1 replied to Andre1's topic in RTL and Delphi Object Pascal
Thanks. Yes, for the moment my library targets x86 only. In a later iteration I will make it architecture independent. Below System.Rtti.TRttiMethod.Invoke there is System.Rtti.TValue.Cast which seems unable to handle the untyped pointer to the Record. Exception EInvalidCast is thrown. Is the Rtti Invoke method capable to invoke the method with an untyped pointer or have I somehow convert the untyped pointer to a typed pointer by making use of some other Rtti functions? Kind regards André -
Dynamic method call with record references
Andre1 replied to Andre1's topic in RTL and Delphi Object Pascal
Thanks I tried your suggestion but it didnt' worked. An invalid type conversion is show. It seems just passing untyped pointer of the record is not possible in the invoke method. I simplified the problem by creating the example just as Delphi console application: program foo; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Classes, System.rtti, System.TypInfo; type TDateRec = record Year: Integer; end; TExample = class public function Calc(const dateRec: TDateRec): Integer; end; function TExample.Calc(const dateRec: TDateRec): Integer; begin result := dateRec.Year; end; var ex: TExample; dateRec: TDateRec; intResult: Integer; function executeInstanceMethod(const Reference: Integer; const AName: string; const Args: array of TValue): TValue; var context: TRttiContext; instType: TRttiInstanceType; obj: TObject; begin context := TRttiContext.Create; try try obj := TObject(Reference); instType := (context.GetType(obj.ClassType) as TRttiInstanceType); result := instType.GetMethod(AName).Invoke(obj, Args); except on E: Exception do writeln(E.ClassName + ' error raised, with message : ' + E.Message); end; finally context.Free; end; end; function executeInstanceMethodReturnIntArgsStruct(const Reference: Integer; const AName: PAnsiChar; Reference2: Pointer): Integer; begin // Just passing the untyped pointer does not work ? result := executeInstanceMethod(Reference, string(AName), [Reference2]) .AsInteger; end; begin try ex := TExample.Create; dateRec.Year := 2022; executeInstanceMethodReturnIntArgsStruct(Integer(ex), 'Calc', @dateRec); except on E: Exception do writeln(E.ClassName, ': ', E.Message); end; end. Kind regards André