Jump to content

Andre1

Members
  • Content Count

    7
  • Joined

  • Last visited

Posts posted by Andre1


  1. 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é

     

     

     

     


  2. 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é


  3. 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é

     

     


  4. 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é


  5. 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é

     

×