Re: [fpc-pascal] Read Field names from VMT
I see... The trick was to define TMyClass! Thanks! On 2/1/24 02:19, Michael Van Canneyt via fpc-pascal wrote: On Wed, 31 Jan 2024, Amir--- via fpc-pascal wrote: Without more info (declaration of ChildTClass, declaration of the constructor of that class etc), it is not possible to comment. We need a complete compilable code sample to provide you with more insight. Please have a look at the attachment. The constructor of TObject is not virtual, in difference with the destructor. Given the definitions ChildObj: TObject; ChildTClass: TClass; The following statement ChildObj := ChildTClass.Create; will always use the TObject.Create, since it is not virtual. In general, you cannot use TObject for this kind of thing. For this to work, you need to create a descendent of TObject with a virtual constructor (call it TMyObject) of known signature, and do ChildObj: TMyObject; ChildTClass: TMyClass; // class of TMyobject then ChildObj := ChildTClass.Create; will take the correct overridden constructor. Your code is also incomplete in the sense that it will only work for classes with a constructor without arguments. If a overloaded constructor exists which takes arguments (like TComponent), it will not be called and the class will not be instantiated correctly. But maybe that will not be your use-case. I attached a version of your program that works and has no memleaks. Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Read Field names from VMT
On Wed, 31 Jan 2024, Amir--- via fpc-pascal wrote: Without more info (declaration of ChildTClass, declaration of the constructor of that class etc), it is not possible to comment. We need a complete compilable code sample to provide you with more insight. Please have a look at the attachment. The constructor of TObject is not virtual, in difference with the destructor. Given the definitions ChildObj: TObject; ChildTClass: TClass; The following statement ChildObj := ChildTClass.Create; will always use the TObject.Create, since it is not virtual. In general, you cannot use TObject for this kind of thing. For this to work, you need to create a descendent of TObject with a virtual constructor (call it TMyObject) of known signature, and do ChildObj: TMyObject; ChildTClass: TMyClass; // class of TMyobject then ChildObj := ChildTClass.Create; will take the correct overridden constructor. Your code is also incomplete in the sense that it will only work for classes with a constructor without arguments. If a overloaded constructor exists which takes arguments (like TComponent), it will not be called and the class will not be instantiated correctly. But maybe that will not be your use-case. I attached a version of your program that works and has no memleaks. Michael.program FieldAddress; {$mode objfpc}{$H+} uses {$IFDEF UNIX} cthreads, {$ENDIF} Classes, TypInfo { you can add units after this }; type {$M+} { TValue } TMyObject = class (TObject) constructor create; virtual; end; TMyClass = class of TMyObject; TValue = class(TMyObject) private FV: PInteger; public constructor Create; override; destructor destroy; override; end; { TParam } TParam = class(TObject) public destructor destroy; override; published V1: TValue; V2: TValue; end; procedure Process(vft: PVmtFieldTable; Obj: TObject); var vfe: PVmtFieldEntry; i: SizeInt; Name: AnsiString; ChildObj: TMyObject; ChildTClass: TMyClass; FieldClass : TClass; begin if vft=nil then exit; Writeln(vft^.Count, ' field(s) with ', vft^.ClassTab^.Count, ' type(s)'); for i := 0 to vft^.Count - 1 do begin vfe := vft^.Field[i]; Name := vfe^.Name; Writeln(i, ' -> ', vfe^.Name, ' @ ', vfe^.FieldOffset, ' of type ', vft^.ClassTab^.ClassRef[vfe^.TypeIndex - 1]^.ClassName); FieldClass := vft^.ClassTab^.ClassRef[vfe^.TypeIndex - 1]^; if FieldClass.InheritsFrom(TMyObject) then begin Writeln('Inherits'); ChildTClass := TMyClass(FieldClass); WriteLn('ChidTClass: ', ChildTClass.ClassName); ChildObj := ChildTClass.Create; if ((ChildObj as TValue).FV = nil) or ((ChildObj as TValue).FV^ <> 1) then begin WriteLn('ERROR'); Halt(1); end; writeln('Calling sub'); TObject(Obj.FieldAddress(Name)^):=ChildObj; Process( PVmtFieldTable(PVMT(ChildTClass)^.vFieldTable), ChildObj ); end; end; end; { TValue } constructor TMyObject.create; begin end; constructor TValue.Create; begin inherited Create; Writeln('Called'); FV := New(PInteger); FV^ := 1; end; destructor TValue.Destroy; begin dispose(FV); inherited; end; { TParam} destructor TParam.Destroy; begin V1.Free; V2.Free; Inherited; end; var Param: TParam; begin Param := TParam.Create; Process(PVmtFieldTable(PVMT(TParam)^.vFieldTable), Param); Param.Free; end. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Read Field names from VMT
Without more info (declaration of ChildTClass, declaration of the constructor of that class etc), it is not possible to comment. We need a complete compilable code sample to provide you with more insight. Please have a look at the attachment. Best, Amir FieldAddress.lpr.gz Description: application/gzip ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Read Field names from VMT
On Mon, 29 Jan 2024, Amir--- via fpc-pascal wrote: I am still struggling with this! for i := 0 to vft^.Count - 1 do begin vfe := vft^.Field[i]; Name := vfe^.Name; ChildTClass := vft^.ClassTab^.ClassRef[vfe^.TypeIndex - 1]^; ChildObj := ChildTClass.Create; TObject(Obj.FieldAddress(Name)^) := ChildObj; end; Looks like "ChildTClass.ClassName" is correct but the constructor of the appropriate class is not being called. Without more info (declaration of ChildTClass, declaration of the constructor of that class etc), it is not possible to comment. We need a complete compilable code sample to provide you with more insight. Michael.___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Read Field names from VMT
I am still struggling with this! for i := 0 to vft^.Count - 1 do begin vfe := vft^.Field[i]; Name := vfe^.Name; ChildTClass := vft^.ClassTab^.ClassRef[vfe^.TypeIndex - 1]^; ChildObj := ChildTClass.Create; TObject(Obj.FieldAddress(Name)^) := ChildObj; end; Looks like "ChildTClass.ClassName" is correct but the constructor of the appropriate class is not being called. On 1/22/24 23:05, Michael Van Canneyt via fpc-pascal wrote: On Mon, 22 Jan 2024, Amir--- via fpc-pascal wrote: Params := TParams.Create; WriteLn(Params.Int2.IntVal); WriteLn(TInteger(Params.FieldAddress('Int2')).IntVal); The third line does not work (the zipped code is attached). It should be WriteLn(TInteger(Params.FieldAddress('Int2')^).IntVal); Terribly convoluted code, though... Michael. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Read Field names from VMT
On 1/22/24 23:05, Michael Van Canneyt via fpc-pascal wrote: On Mon, 22 Jan 2024, Amir--- via fpc-pascal wrote: Params := TParams.Create; WriteLn(Params.Int2.IntVal); WriteLn(TInteger(Params.FieldAddress('Int2')).IntVal); The third line does not work (the zipped code is attached). It should be WriteLn(TInteger(Params.FieldAddress('Int2')^).IntVal); +1 ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Read Field names from VMT
On Mon, 22 Jan 2024, Amir--- via fpc-pascal wrote: Params := TParams.Create; WriteLn(Params.Int2.IntVal); WriteLn(TInteger(Params.FieldAddress('Int2')).IntVal); The third line does not work (the zipped code is attached). It should be WriteLn(TInteger(Params.FieldAddress('Int2')^).IntVal); Terribly convoluted code, though... Michael.___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Read Field names from VMT
Params := TParams.Create; WriteLn(Params.Int2.IntVal); WriteLn(TInteger(Params.FieldAddress('Int2')).IntVal); The third line does not work (the zipped code is attached). On 1/21/24 23:43, Michael Van Canneyt via fpc-pascal wrote: On Sun, 21 Jan 2024, Amir--- via fpc-pascal wrote: How can I set the value? I tried something like Test := TTest.Create Ptr := Pointer(Test); TSub(Ptr+8) := TSub.Create; But it is not working? Depending on your platform, it can be an alignment issue. Use function TObject.FieldAddress(const name : shortstring) : pointer; This function is used internally by the streaming system (see TComponent.SetReference), so it should always work. Michael. You can use the PVmtFieldTable and PVmtFieldEntry types from the TypInfo unit: === code begin === program tfield; {$mode objfpc}{$H+} uses TypInfo; type {$M+} TSub = class end; TTest = class published fTest: TSub; end; var vft: PVmtFieldTable; vfe: PVmtFieldEntry; i: SizeInt; begin vft := PVmtFieldTable(PVMT(TTest)^.vFieldTable); Writeln(vft^.Count, ' field(s) with ', vft^.ClassTab^.Count, ' type(s)'); for i := 0 to vft^.Count - 1 do begin vfe := vft^.Field[i]; Writeln(i, ' -> ', vfe^.Name, ' @ ', vfe^.FieldOffset, ' of type ', vft^.ClassTab^.ClassRef[vfe^.TypeIndex - 1]^.ClassName); end; end. === code end === === output begin === PS C:\fpc\git> .\testoutput\tfield.exe 1 field(s) with 1 type(s) 0 -> fTest @ 8 of type TSub === output end === Side note: contrary to what I had originally written only classes, but not interfaces are allowed for published fields and they need to have $M enabled. Regards, Sven ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal FieldAddress.lpr.gz Description: application/gzip ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Read Field names from VMT
On Sun, 21 Jan 2024, Amir--- via fpc-pascal wrote: How can I set the value? I tried something like Test := TTest.Create Ptr := Pointer(Test); TSub(Ptr+8) := TSub.Create; But it is not working? Depending on your platform, it can be an alignment issue. Use function TObject.FieldAddress(const name : shortstring) : pointer; This function is used internally by the streaming system (see TComponent.SetReference), so it should always work. Michael. You can use the PVmtFieldTable and PVmtFieldEntry types from the TypInfo unit: === code begin === program tfield; {$mode objfpc}{$H+} uses TypInfo; type {$M+} TSub = class end; TTest = class published fTest: TSub; end; var vft: PVmtFieldTable; vfe: PVmtFieldEntry; i: SizeInt; begin vft := PVmtFieldTable(PVMT(TTest)^.vFieldTable); Writeln(vft^.Count, ' field(s) with ', vft^.ClassTab^.Count, ' type(s)'); for i := 0 to vft^.Count - 1 do begin vfe := vft^.Field[i]; Writeln(i, ' -> ', vfe^.Name, ' @ ', vfe^.FieldOffset, ' of type ', vft^.ClassTab^.ClassRef[vfe^.TypeIndex - 1]^.ClassName); end; end. === code end === === output begin === PS C:\fpc\git> .\testoutput\tfield.exe 1 field(s) with 1 type(s) 0 -> fTest @ 8 of type TSub === output end === Side note: contrary to what I had originally written only classes, but not interfaces are allowed for published fields and they need to have $M enabled. Regards, Sven ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Read Field names from VMT
How can I set the value? I tried something like Test := TTest.Create Ptr := Pointer(Test); TSub(Ptr+8) := TSub.Create; But it is not working? You can use the PVmtFieldTable and PVmtFieldEntry types from the TypInfo unit: === code begin === program tfield; {$mode objfpc}{$H+} uses TypInfo; type {$M+} TSub = class end; TTest = class published fTest: TSub; end; var vft: PVmtFieldTable; vfe: PVmtFieldEntry; i: SizeInt; begin vft := PVmtFieldTable(PVMT(TTest)^.vFieldTable); Writeln(vft^.Count, ' field(s) with ', vft^.ClassTab^.Count, ' type(s)'); for i := 0 to vft^.Count - 1 do begin vfe := vft^.Field[i]; Writeln(i, ' -> ', vfe^.Name, ' @ ', vfe^.FieldOffset, ' of type ', vft^.ClassTab^.ClassRef[vfe^.TypeIndex - 1]^.ClassName); end; end. === code end === === output begin === PS C:\fpc\git> .\testoutput\tfield.exe 1 field(s) with 1 type(s) 0 -> fTest @ 8 of type TSub === output end === Side note: contrary to what I had originally written only classes, but not interfaces are allowed for published fields and they need to have $M enabled. Regards, Sven ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Read Field names from VMT
Thank you!On Dec 27, 2023 7:46 AM, Sven Barth via fpc-pascal wrote: Am 26.12.2023 um 21:29 schrieb Amir--- via fpc-pascal: On 12/26/23 01:14, Sven Barth via fpc-pascal wrote: Amir--- via fpc-pascalschrieb am Di., 26. Dez. 2023, 07:03: Hi, I want to retrieve the name of the fields in a record/class, at run time. It looks like "TVmt.vFieldTable" is what I need. But I cannot find any documentation about how to explore the content of this table. I appreciate any pointer. This only works for published fields and only fields of type class or interface can be published. That would work for me. How can I enumerate over those fields? You can use the PVmtFieldTable and PVmtFieldEntry types from the TypInfo unit: === code begin === program tfield; {$mode objfpc}{$H+} uses TypInfo; type {$M+} TSub = class end; TTest = class published fTest: TSub; end; var vft: PVmtFieldTable; vfe: PVmtFieldEntry; i: SizeInt; begin vft := PVmtFieldTable(PVMT(TTest)^.vFieldTable); Writeln(vft^.Count, ' field(s) with ', vft^.ClassTab^.Count, ' type(s)'); for i := 0 to vft^.Count - 1 do begin vfe := vft^.Field[i]; Writeln(i, ' -> ', vfe^.Name, ' @ ', vfe^.FieldOffset, ' of type ', vft^.ClassTab^.ClassRef[vfe^.TypeIndex - 1]^.ClassName); end; end. === code end === === output begin === PS C:\fpc\git> .\testoutput\tfield.exe 1 field(s) with 1 type(s) 0 -> fTest @ 8 of type TSub === output end === Side note: contrary to what I had originally written only classes, but not interfaces are allowed for published fields and they need to have $M enabled. Regards, Sven ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Read Field names from VMT
Am 26.12.2023 um 21:29 schrieb Amir--- via fpc-pascal: On 12/26/23 01:14, Sven Barth via fpc-pascal wrote: Amir--- via fpc-pascal schrieb am Di., 26. Dez. 2023, 07:03: Hi, I want to retrieve the name of the fields in a record/class, at run time. It looks like "TVmt.vFieldTable" is what I need. But I cannot find any documentation about how to explore the content of this table. I appreciate any pointer. This only works for published fields and only fields of type class or interface can be published. That would work for me. How can I enumerate over those fields? You can use the PVmtFieldTable and PVmtFieldEntry types from the TypInfo unit: === code begin === program tfield; {$mode objfpc}{$H+} uses TypInfo; type {$M+} TSub = class end; TTest = class published fTest: TSub; end; var vft: PVmtFieldTable; vfe: PVmtFieldEntry; i: SizeInt; begin vft := PVmtFieldTable(PVMT(TTest)^.vFieldTable); Writeln(vft^.Count, ' field(s) with ', vft^.ClassTab^.Count, ' type(s)'); for i := 0 to vft^.Count - 1 do begin vfe := vft^.Field[i]; Writeln(i, ' -> ', vfe^.Name, ' @ ', vfe^.FieldOffset, ' of type ', vft^.ClassTab^.ClassRef[vfe^.TypeIndex - 1]^.ClassName); end; end. === code end === === output begin === PS C:\fpc\git> .\testoutput\tfield.exe 1 field(s) with 1 type(s) 0 -> fTest @ 8 of type TSub === output end === Side note: contrary to what I had originally written only classes, but not interfaces are allowed for published fields and they need to have $M enabled. Regards, Sven___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Read Field names from VMT
On 12/26/23 01:14, Sven Barth via fpc-pascal wrote: Amir--- via fpc-pascal schrieb am Di., 26. Dez. 2023, 07:03: Hi, I want to retrieve the name of the fields in a record/class, at run time. It looks like "TVmt.vFieldTable" is what I need. But I cannot find any documentation about how to explore the content of this table. I appreciate any pointer. This only works for published fields and only fields of type class or interface can be published. That would work for me. How can I enumerate over those fields? Best, Amir ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Read Field names from VMT
Amir--- via fpc-pascal schrieb am Di., 26. Dez. 2023, 07:03: > Hi, > >I want to retrieve the name of the fields in a record/class, at run > time. It looks like "TVmt.vFieldTable" is what I need. But I cannot find > any documentation about how to explore the content of this table. I > appreciate any pointer. > This only works for published fields and only fields of type class or interface can be published. Anything more requires extended RTTI, which is not yet implemented in FPC (it's already more or less ready in a merge request, but there's still the one or other issue that needs to be addressed). Regards, Sven > ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal