views:

82

answers:

3

I've recently been able to fetch a TRttiType for an interface using TRttiContext.FindType using Robert Loves "GetType"-workaround ("registering" the interface by an explicit call to ctx.GetType, e.g. RType := ctx.GetType(TypeInfo(IMyPrettyLittleInterface));).

One logical next step would be to iterate the methods of said interface. Consider

program rtti_sb_1;
{$APPTYPE CONSOLE}
uses
  SysUtils, Rtti, mynamespace in 'mynamespace.pas';
var
  ctx:      TRttiContext;
  RType:    TRttiType;
  Method:   TRttiMethod;
begin
  ctx := TRttiContext.Create;
  RType := ctx.GetType(TypeInfo(IMyPrettyLittleInterface));
  if RType <> nil then begin
    for Method in RType.GetMethods do
      WriteLn(Method.Name);
  end;
  ReadLn;
end.

This time, my mynamespace.pas looks like this:

IMyPrettyLittleInterface = interface
  ['{6F89487E-5BB7-42FC-A760-38DA2329E0C5}']
  procedure SomeProcedure;
end;

Unfortunately, RType.GetMethods returns a zero-length TArray-instance. Are there anyone able to reproduce my troubles? (Note that in my example I've explicitly fetched the TRttiType using TRttiContext.GetType, not the workaround; the introduction is included to warn readers that there might be some unresolved issues regarding rtti and interfaces.) Thanks!

+2  A: 

I just traced through what's going on, and in TRttiInterfaceType.Create, line 5774, it says:

hasRtti := ReadU16(P);
if hasRtti = $FFFF then
  Exit;

And in both your interface, and IInterface which it inherits from, HasRtti reads as $FFFF. So apparently no RTTI is being generated for the interface's methods, and this is even true for the base Interface type. I don't know why. Not sure who would know why, aside from Barry Kelly.

Mason Wheeler
Wow Mason; you are quite courageous to delve into the actual source. I guess I could've given it a go myself, if it hadn't been for my codeinsight. It's been broken since I updated from D2009... :| Thanks a lot! I suppose I better report it to QC.
conciliator
@Conciliator: Courageous? Nah. The RTL is actually quite beautiful, for the most part. Most of the truly scary stuff is in `system.pas`. :P
Mason Wheeler
:) I reported it as QC #85308; trying to hack around it as we speak.
conciliator
+1  A: 

There are certain compiler directives sometimes needed to generate RTTI, like M+. Perhaps you just have to set one of those?

Dave Novo
Apparently $M+ isn't needed in D2010 (which I guess I forgot to tell that I'm using).
conciliator
Dave: you are absolutely correct. (+1)
conciliator
A: 

Dave was right after all. As it turns out, the interface must be surrounded by a {$M+}/{$M-}-clause. Compiling with

{$M+}
IMyPrettyLittleInterface = interface
  ['{6F89487E-5BB7-42FC-A760-38DA2329E0C5}']
  procedure SomeProcedure;
end;
{$M-}

does it.

conciliator