Andre1
Members-
Content Count
12 -
Joined
-
Last visited
Everything posted by Andre1
-
Hi, I wrote a framework to call delphi methods from other programming languages. This works quite well, except for the method procedure TBitmap.Clear(const AColor: TAlphaColor); TAlphaColor is defined as dedicated type with base type Cardinal TAlphaColor = type Cardinal; The generic logic to execute delphi methods fails, because from the foreign programming language an Unsigned Integer is passed, while the logic expects exactly TAlphaColor. The condition "if parameters[Index].ParamType.Handle <> Args[Index].TypeInfo then" evaluates to false. function executeInstanceMethod(Reference: Pointer; const AName: string; const Args: array of TValue): TValue; var context: TRttiContext; instType: TRttiInstanceType; obj: TObject; meth: TRttiMethod; parameters: TArray<TRttiParameter>; Found: Boolean; index: Integer; begin context := TRttiContext.Create; try meth := nil; Found := false; obj := TObject(Reference); instType := (context.GetType(obj.ClassType) as TRttiInstanceType); for meth in instType.GetMethods do if SameText(meth.Name, AName) then begin parameters := meth.GetParameters; if Length(Args) = Length(parameters) then begin Found := True; for Index := 0 to Length(parameters) - 1 do if parameters[Index].ParamType.Handle <> Args[Index].TypeInfo then begin IF Args[Index].IsObject AND Args[Index].AsObject.InheritsFrom (parameters[Index].ParamType.AsInstance.MetaclassType) then begin end else begin Found := false; Break; end; end; end; if Found then Break; end; if (meth <> nil) and Found then begin result := meth.Invoke(obj, Args); end else raise Exception.CreateFmt('method %s not found', [AName]); finally context.Free; end; end; I wonder whether there are some means to check whether the dedicated type (parameters[Index].ParamType.Handle) has the base type (Args[Index].TypeInfo) ? Kind regards André
-
Hi All, thanks a lot. This helps me. Kind regards André
-
Hi, thanks I will try. But to get it right, there is no way in Delphi to extract the information from TAlphaColor that it is dedicated type of Cardinal? Or is the only information I can get from TAlphaColor, that it is a Ordinal type? Kind regards André
-
Hi, it works due to the isOrdinal addition, but this has 2 issues: if Args[Index].IsObject AND Args[Index].AsObject.InheritsFrom (parameters[Index].ParamType.AsInstance.MetaclassType) then begin end // I added this line, because TAlphaColor ist obviously a Ordninal and not a class else if Args[Index].IsOrdinal then begin // everything is okay, Found is still True end else 1) The framework I build should work with any dedicated type, not only with Ordinal types. Therefore this solution is limited to this specific sample (TBitmap.Clear) while I search a solution which will work with any dedicated types, indepedent of the base type. 2) It introduces a bug. Without the isOrdinal addition I will get the exception "Method not found" in case a wrong argument type is provided. But this does not work now anymore. For example if I call now this method with a cardinal, a conversion exception is thrown instead: executeInstanceMethod(MyBitmap, 'LoadFromFile', [black_card]); (As explanation the inheritsFrom function is used to enable calling methods with sub classes. As example, a method expect a class of type Animal. The Inheritsfrom Method is needed to allow calling the method with a class Dog or Duck. Exactly the same mechanism I search for the issue with dedicated types). I need to identify the case that I have a dedicted type and need to verify that the passed argument is the base type of the dedicated type in a generic way. Therefor it must also work if the dedicated type is not a ordinal.... Kind regards André
-
Hi, thanks for having a look. In the button1Click method you have used the dedicated type TAlphaColorRec.Black. This is correct in Delphi but I call the function from another programming language, therefor I have only the primitive known to C. To simulate the behavior, the button1Click could look like this: procedure TForm1.Button1Click(Sender: TObject); var MyBitmap: TBitmap; black_card: Cardinal; begin MyBitmap := TBitmap.Create(256, 256); try // if you set a breakpoint in FMX.Graphics.TBitmap.Clear, you will see that the Clear() method is called twice MyBitmap.Clear(TAlphaColorRec.Black); black_card := TAlphaColorRec.Black; executeInstanceMethod(MyBitmap, 'Clear', [black_card]); finally MyBitmap.Free; end; end; I noticed you added in the method executeInstanceMethod a very specific solution for this sample. While this works fine for this specific case, it is not generic. I will fail if the dedicated type is not based on Ordinal type. else if Args[Index].IsOrdinal then I wonder whether there is some generic function in Delphi to check whether the given arg from the method signature (in this case Cardinal) is the base type of the called method parameter (in this case TAlphaColor)? Kind regards André
-
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é