Hello together! I'm pleased to finally announce the addition of Interface RTTI to Free Pascal.
Interface RTTI essentially provides a list of all methods available in an interface if it's declared is parsed with $M+ or has such an interface as parent. For now however this only applies to COM style interfaces. CORBA/Raw style interfaces don't respect $M+ yet, so they don't have that RTTI. Also note that while this RTTI provides the same content as Delphi it is *not* Delphi compatible. In fact since FPC's TypInfo unit never has been fully compatible with Delphi it's save to come out and say that the TypInfo unit is considered a known incompatibility to Delphi and always will be. For compatibility with newer versions of Delphi it's suggested to use the RTTI unit (patches to improve/extend its functionality are welcome). To access the methods it's best to use the new types provided by the TypInfo unit with the starting point being TInterfaceData. The list of methods is available in the property MethodTable of type TIntfMethodTable. This contains two count fields, namely Count and RTTICount. The former *always* contains the number of methods contained in *this* interface, the latter is either $FFFF if $M- or the same as Count if $M+. Directly after that follow the message information in the form of TIntfMethodEntry and can be easily accessed using the Method[] property of TIntfMethodTable. Each method consists of its name, calling convention, method kind, return type (if any), needed stack size for the parameters, any parameters (which can be accessed using the Param[] property) and if the return type is not Nil then also the location of the return value. A parameter consists of its name, the parameter type (Note: open array parameters have their element type as type!), parameter flags and the location the parameter needs to reside in for invoking the method. These locations aren't restricted to single locations however as for example on 32-bit platforms 64-bit values might be passed using two registers. The parameters also contain hidden parameters not really visible in the methods declarations like the Self argument, an eventual Result parameter (for example AnsiString or UnicodeString is passed this way on some platforms) or the high parameter for open arrays. === example begin === program tintfrtti; {$mode objfpc}{$H+} uses typinfo; type {$push} {$M+} ITest = interface procedure Test; function Test2(aArg1: LongInt): Int64; function Test3(aArg1: array of String): String; end; {$pop} var id: PInterfaceData; imt: PIntfMethodTable; ime: PIntfMethodEntry; vmp: PVmtMethodParam; i, j: LongInt; begin id := PInterfaceData(GetTypeData(TypeInfo(ITest))); imt := id^.MethodTable; Writeln('Methods: ', imt^.Count, ' ', imt^.RTTICount); for i := 0 to imt^.Count - 1 do begin ime := imt^.Method[i]; Writeln('Method ', ime^.Name); Writeln(#9'CC: ', ime^.CC); Writeln(#9'Kind: ', ime^.Kind); Writeln(#9'StackSize: ', ime^.StackSize); if Assigned(ime^.ResultType) then begin Writeln(#9'Result Type: ', ime^.ResultType^^.Name); Writeln(#9'Result Locations: ', ime^.ResultLocs^.Count); end else begin Writeln(#9'Return Type: <none>'); Writeln(#9'Result Locations: <none>'); end; Writeln(#9'Params: ', ime^.ParamCount); for j := 0 to ime^.ParamCount - 1 do begin vmp := ime^.Param[j]; Writeln(#9'Param ', vmp^.Name); Writeln(#9#9'Type: ', vmp^.ParamType^^.Name); Writeln(#9#9'Flags: ', HexStr(Word(vmp^.Flags), 4)); Writeln(#9#9'Locations: ', vmp^.ParaLocs^.Count); end; end; end. === example end === On a x86_64-linux it will print the following: === output begin === Methods: 3 3 Method Test CC: ccReg Kind: mkProcedure StackSize: 0 Return Type: <none> Result Locations: <none> Params: 1 Param $self Type: ITest Flags: 0288 Locations: 1 Method Test2 CC: ccReg Kind: mkFunction StackSize: 0 Result Type: Int64 Result Locations: 1 Params: 2 Param $self Type: ITest Flags: 0288 Locations: 1 Param aArg1 Type: LongInt Flags: 0000 Locations: 1 Method Test3 CC: ccReg Kind: mkFunction StackSize: 0 Result Type: AnsiString Result Locations: 1 Params: 4 Param $self Type: ITest Flags: 0288 Locations: 1 Param $result Type: AnsiString Flags: 0881 Locations: 1 Param aArg1 Type: AnsiString Flags: 0014 Locations: 1 Param $highAARG1 Type: Int64 Flags: 0182 Locations: 1 === output end === A note regarding performance: The indexing properties of except the one in TParameterLocations have a complexity of O(n) as they always need to iterate from the 0th element. So if you have code that relies on performance it might be better to iterate them like this: === code begin === i := 0; ime := imt^.Method[0]; while i < imt^.Count do begin { do something with ime } ime := ime^.Next; Inc(i); end; === code end === The Next property correctly handles alignment on targets that requires them, so they are the recommended, platform independent way of accessing the following entry. Please note however that Next will *not* return Nil once the end is reached (because it has no knowledge about this; it simply returns a pointer to the location after itself). Maybe in the future for-in-iterators might be added. Similar functionality has been added to TPropData which can also be accessed from TInterfaceData.PropertyTable and TInterfaceRawData.PropertyTable. Further utility records to simplify navigation of the raw RTTI are planned to be added. Also the Delphi compatible RTTI unit will be extended accordingly. Regards, Sven _______________________________________________ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal