Recent

Author Topic: [Solved] RTTI - Method Parameters / Return Type  (Read 16996 times)

darupe

  • New Member
  • *
  • Posts: 15
[Solved] RTTI - Method Parameters / Return Type
« on: February 27, 2015, 06:52:40 pm »
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.
« Last Edit: March 17, 2015, 06:23:12 pm by darupe »

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: RTTI - Method Parameters / Return Type
« Reply #1 on: February 27, 2015, 07:28:43 pm »
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

  • Administrator
  • Hero Member
  • *
  • Posts: 11447
  • FPC developer.
Re: RTTI - Method Parameters / Return Type
« Reply #2 on: February 27, 2015, 07:42:05 pm »
Easiest is probably checking the streaming code in classes?

darupe

  • New Member
  • *
  • Posts: 15
Re: RTTI - Method Parameters / Return Type
« Reply #3 on: February 27, 2015, 10:11:51 pm »
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

  • Administrator
  • Hero Member
  • *
  • Posts: 11447
  • FPC developer.
Re: RTTI - Method Parameters / Return Type
« Reply #4 on: February 27, 2015, 10:50:14 pm »
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.

Well, Lazarus must resolve its eventhandler from the string name on load?

darupe

  • New Member
  • *
  • Posts: 15
Re: RTTI - Method Parameters / Return Type
« Reply #5 on: February 27, 2015, 11:40:09 pm »
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

  • Hero Member
  • *****
  • Posts: 4144
Re: RTTI - Method Parameters / Return Type
« Reply #6 on: February 28, 2015, 12:01:05 am »
You may find some clues in the LCL propedits.pp unit. For instance the overloaded GetPersistentProperties() procedures.

darupe

  • New Member
  • *
  • Posts: 15
Re: RTTI - Method Parameters / Return Type
« Reply #7 on: February 28, 2015, 12:18:50 am »
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

  • New Member
  • *
  • Posts: 15
Re: RTTI - Method Parameters / Return Type
« Reply #8 on: March 01, 2015, 05:41:21 am »
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

  • Administrator
  • Hero Member
  • *
  • Posts: 11447
  • FPC developer.
Re: [Solved] RTTI - Method Parameters / Return Type
« Reply #9 on: March 01, 2015, 02:28:18 pm »
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

  • Hero Member
  • *****
  • Posts: 3112
Re: [Solved] RTTI - Method Parameters / Return Type
« Reply #10 on: March 01, 2015, 04:46:31 pm »
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

  • Administrator
  • Hero Member
  • *
  • Posts: 11447
  • FPC developer.
Re: [Solved] RTTI - Method Parameters / Return Type
« Reply #11 on: March 01, 2015, 06:52:28 pm »
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.
« Last Edit: March 17, 2015, 04:09:54 pm by marcov »

darupe

  • New Member
  • *
  • Posts: 15
Re: RTTI - Method Parameters / Return Type
« Reply #12 on: March 17, 2015, 03:54:03 pm »
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.
« Last Edit: March 17, 2015, 03:58:06 pm by darupe »

darupe

  • New Member
  • *
  • Posts: 15
Re: RTTI - Method Parameters / Return Type
« Reply #13 on: March 17, 2015, 06:22:55 pm »
Decided to do the pointer calculations myself based on the pointer to the type data. Everything now works as expected.

Int

  • Newbie
  • Posts: 5
Re: [Solved] RTTI - Method Parameters / Return Type
« Reply #14 on: April 07, 2016, 09:24:43 pm »
@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

 

TinyPortal © 2005-2018