[Solved] RTTI - Method Parameters / Return Type lazarus / 62-General ---------------------------------------------------------------------- darupe · 2015-02-27 17:52 Can anyone tell me how to access the RTTI information for published methods (FPC 2.6.4)? I can easily find the published methods through TVmt.vMethodTable but that's only the method names and addresses. What I would really like to access is the information about parameters and return types. I can't seem to find anything about it in the TypInfo unit, except for GetMethodProp which seems to return NIL no matter what. ---------------------------------------------------------------------- engkin · 2015-02-27 18:28 Did a search for tkMethod in TypInfo: Code: [Select]      TTypeData = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}       packed {$endif FPC_REQUIRES_PROPER_ALIGNMENT}       record          case TTypeKind of ...             tkMethod:               (MethodKind : TMethodKind;                ParamCount : Byte;                ParamList : array[0..1023] of Char              {in reality ParamList is a array[1..ParamCount] of:                   record                     Flags : TParamFlags;                     ParamName : ShortString;                     TypeName : ShortString;                   end;               followed by                   ResultType : ShortString     // for mkFunction, mkClassFunction only                   ResultTypeRef : PTypeInfo;  // for mkFunction, mkClassFunction only                   CC : TCallConv;                   ParamTypeRefs : array[1..ParamCount] of PTypeInfo;}               ); On the other hand, the compiler generates the RTTI data in a unit called ncgrtti. ---------------------------------------------------------------------- marcov · 2015-02-27 18:42 Easiest is probably checking the streaming code in classes? ---------------------------------------------------------------------- darupe · 2015-02-27 21:11 I did see tkMethod in TypInfo but how do you actually get a pointer to the data? I can only find functions for properties in TypInfo though I had hoped GetPropList would also include methods. When it comes to streaming classes, I believe they only focus on class properties, not methods. ---------------------------------------------------------------------- marcov · 2015-02-27 21:50 Quote from: darupe on February 27, 2015, 10:11:51 pmI did see tkMethod in TypInfo but how do you actually get a pointer to the data? I can only find functions for properties in TypInfo though I had hoped GetPropList would also include methods. When it comes to streaming classes, I believe they only focus on class properties, not methods. Well, Lazarus must resolve its eventhandler from the string name on load? ---------------------------------------------------------------------- darupe · 2015-02-27 22:40 I haven't been able to find any references to the RTTI for parameters/return types in the Lazarus streaming classes. Based on ncgrtti, the method information should be available in the RTTI data but the question is still how to retrieve a pointer to the data. I would actually expect GetPropList to return the methods based on what I gather from ncgrtti but this is not the case. ---------------------------------------------------------------------- howardpc · 2015-02-27 23:01 You may find some clues in the LCL propedits.pp unit. For instance the overloaded GetPersistentProperties() procedures. ---------------------------------------------------------------------- darupe · 2015-02-27 23:18 Based on that file, Lazarus seems to use GetPropInfo for methods, like this: Code: [Select]  // search method   PropInfo:=GetPropInfo(AComponent,EventName); However, when I do that, I simply end up with NIL. Other than that, it looks very much like Lazarus tries to avoid RTTI and has created its own set of methods for exposing the method list. I can't say for sure if this is the case as I will need to keep looking through the files but all the TPropHook... methods does seem to indicate exactly that. ---------------------------------------------------------------------- darupe · 2015-03-01 04:41 Based on my findings, RTTI only works for procedures/functions that have been published as properties (events). I had hoped it would be available for regular procedures/functions but I can easily use properties as a workaround. ---------------------------------------------------------------------- marcov · 2015-03-01 13:28 Event Properties and published methods are probably two kinds, but probably in differing RTTI tables. Event Properties are the variable that (can) hold a value, the published methods are the value that is being held. When a form is loaded from a .dfm, all it contains is the event name, and that must be resolvable to a function name. Better look at that code again. ---------------------------------------------------------------------- engkin · 2015-03-01 15:46 I believe Darupe is right. TReader.FindMethod uses TObject.MethodAddress: Code: [Select]function TReader.FindMethod(ARoot: TComponent; const AMethodName: String): Pointer; ..   Result := ARoot.MethodAddress(AMethodName); We have a table for names and addresses only: Code: [Select]       TVmt = record ...          vMethodTable: Pointer; ... Code: [Select]         tmethodnamerec = packed record             name : pshortstring;             addr : pointer;          end;          tmethodnametable = packed record            count : dword;            entries : packed array[0..0] of tmethodnamerec;          end; MethodAddress loops through the method table to find a method with the same name: Code: [Select]      class function TObject.MethodAddress(const name : shortstring) : pointer; ...                 methodtable:=pmethodnametable(ovmt^.vMethodTable); ...                        if ShortCompareText(methodtable^.entries[i].name^, name)=0 then ---------------------------------------------------------------------- marcov · 2015-03-01 17:52 Ah, ok. I count that as RTTI, but indeed that doesn't hold other detail info. The old (pre D2010?) RTTI only supports what's needed for the designer (and as I recently learned a few special cases wrt COM), extra things are the so called extended RTTI were introduced in D2010, and while there is some work on that in various branches, it is not in any of the main branches afaik. ---------------------------------------------------------------------- darupe · 2015-03-17 14:54 Seems like I need a little more help to get this working. Based on TypInfo, the record structure for a tkMethod is described like this: Code: [Select]            tkMethod:               (MethodKind : TMethodKind;                ParamCount : Byte;                ParamList : array[0..1023] of Char              {in reality ParamList is a array[1..ParamCount] of:                   record                     Flags : TParamFlags;                     ParamName : ShortString;                     TypeName : ShortString;                   end;               followed by                   ResultType : ShortString     // for mkFunction, mkClassFunction only                   ResultTypeRef : PPTypeInfo;  // for mkFunction, mkClassFunction only                   CC : TCallConv;                   ParamTypeRefs : array[1..ParamCount] of PPTypeInfo;}               ); To avoid doing pointer calculations, I have created the following records: Code: [Select]  {$PACKRECORDS 1}   TDMethodParamInfo = {$IFNDEF FPC_REQUIRES_PROPER_ALIGNMENT}packed{$ENDIF}   record     Flags     : TParamFlags;     ParamName : ShortString;     TypeName  : ShortString;   end;   {$PACKRECORDS C}   TDFunctionTypeData = {$IFNDEF FPC_REQUIRES_PROPER_ALIGNMENT}packed{$ENDIF}   record     MethodKind    : TMethodKind;     ParamCount    : Byte;     ParamList     : array[1..1] of TDMethodParamInfo;     ResultType    : ShortString;     ResultTypeRef : PPTypeInfo;     CC            : TCallConv;     ParamTypeRefs : array[1..1] of PPTypeInfo;   end;   TDProcedureTypeData = {$IFNDEF FPC_REQUIRES_PROPER_ALIGNMENT}packed{$ENDIF}   record     MethodKind    : TMethodKind;     ParamCount    : Byte;     ParamList     : array[1..1] of TDMethodParamInfo;     CC            : TCallConv;     ParamTypeRefs : array[1..1] of PPTypeInfo;   end;   {$PACKRECORDS 1}   PDFunctionTypeData  = ^TDFunctionTypeData;   PDProcedureTypeData = ^TDProcedureTypeData;  However, when I execute the following procedure: Code: [Select]procedure LoadParameters(const ATypeData: TDProcedureTypeData); begin   WriteLn('> Name: ', ATypeData.ParamList[1].ParamName);   WriteLn('> ------------------------------------------');   WriteLn('> Type: ', ATypeData.ParamList[1].TypeName);   WriteLn('> ------------------------------------------');   WriteLn('> Kind: ', ATypeData.ParamTypeRefs[1]^^.Kind); end;  I end up with this output: Code: [Select]> Name: AInput > ------------------------------------------ > Type: > ------------------------------------------ An unhandled exception occurred at $00427FFD : EAccessViolation : Access violation   $00427FFD   $0042723C   $0042871F   $0042854F   $0042686C   $00401626   $00426540   $00401658 > Kind: Before calling the procedure, I make sure that the data is for a mkProcedure: Code: [Select]if (ATypeData^.MethodKind = mkFunction) then   LoadParameters(PDFunctionTypeData(ATypeData)^) else   LoadParameters(PDProcedureTypeData(ATypeData)^); Anyone that can point out the flaw in the code? All classes are enclosed in {$M+}{$M-} so RTTI data should be available. PS: The procedure only has 1 parameter hence I use array[1..1]. This also means that ParamTypeRefs shouldn't end up at the wrong offset unless there's something I'm missing. ---------------------------------------------------------------------- darupe · 2015-03-17 17:22 Decided to do the pointer calculations myself based on the pointer to the type data. Everything now works as expected. ---------------------------------------------------------------------- Int · 2016-04-07 19:24 @darupe I'm very excited about your library. I haven't found any info about it or another way to connect with you besides writing here. Could you please give any information about your project (or maybe email)? I hope you'll notice this message ---------------------------------------------------------------------- mse · 2016-04-07 20:31 MSEide uses RTTI for method handling, GetMethodParamInfo() reads the parameter names and type names: https://gitlab.com/mseide-msegui/mseide- msegui/raw/master/apps/ide/msedesignparser.pas ---------------------------------------------------------------------- Int · 2016-04-07 22:22 @mse Thanks for the link. That's a big project! Could you please help me with using Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure GetMethodParamInfo(const atype: ptypeinfo; var info: methodparaminfoty);How to get PTypeInfo for a method in FPC? ---------------------------------------------------------------------- mse · 2016-04-08 06:58 Quote from: Int on April 08, 2016, 12:22:03 amHow to get PTypeInfo for a method in FPC? I don't know if methods have parameter RTTI, as enking writes, probably not. MSEide queries the RTTI of method properties in order to get the method parameters. Please have a look at nested procedure doinit() at apps/ide/msedesigner.pas:4430 https://gitlab.com/mseide-msegui/mseide-msegui/tree/master lib/common/kernel/mseclasses.pas:1956 getpropinfoar() reads the propinfos from object instance by calling GetPropInfos() from "typeinfo" unit. The field TPropInfo.PropType returns the PTypeInfo. ---------------------------------------------------------------------- Int · 2016-04-08 16:04 I've read about the GetPropInfo (I suppose it's almost like GetPropInfos), but I haven't find a way how to get PTypeInfo for a method. I've asked about it on Stackoverflow, there's no answer so far (http://stackoverflow.com/questions/36426460/delphi-which-methods-are- supposed-to-be-in-rtti) ---------------------------------------------------------------------- darupe · 2016-07-18 14:19 I'm sorry that I haven't noticed the new replies to this thread. Regarding my library, I never got around to finishing it. However, I now need it for another project where a custom interface would take too long to code. Due to this, I expect to continue my work on it and release it under LGPL at the end of august. I will post a link to the project once it's either done or at least stable enough for testing. I don't expect to include support for ARM in the first release though I will most likely implement that later. To clarify to others, this project is about providing the same classes as the RTTI unit in Delphi. I have implemented most of them already though some features require the latest development version of FPC (a lot of features still work with the latest stable version). The invoke functions currently works with x86 (all calling conventions) and x86_64 (Microsoft x64 and AMD64/System V). ---------------------------------------------------------------------- molly · 2016-12-01 16:02 Quote from: darupe on February 27, 2015, 06:52:40 pmCan anyone tell me how to access the RTTI information for published methods (FPC 2.6.4)? I can easily find the published methods through TVmt.vMethodTable but that's only the method names and addresses. What I would really like to access is the information about parameters and return types. I can't seem to find anything about it in the TypInfo unit, except for GetMethodProp which seems to return NIL no matter what. In short and afaik: you can't. Reason is  because FPC does not create/supply rtti information for (published) methods (or perhaps better rephrase in: i was unable to find it) So, even though the link in Int's SO question (to hallvards blogspot) delivers some interesting code, it unfortunately won't work for Free Pascal (even after adjusting the delphi oriented code to match FPC). The directive $METHODINFO which (if not mistaken) is present in Delphi 7 to generate this information is also not available for FPC. Any chance this will ever be implemented/supported ?