Jump to content
Der schöne Günther

Undocumented "Interface flag" for IInvokable?

Recommended Posts

Posted (edited)

You can use the RTTI to evaluate certain properties of interace types. Please see the following snippet:

 

program Project1;
uses System.Rtti;

var
	context: TRttiContext;
	rttiInterface: TRttiInterfaceType;
begin
	context := TRttiContext.Create();
	rttiInterface := context.GetType( TypeInfo(IInterface) ) as TRttiInterfaceType;
	rttiInterface.IntfFlags; // is [ifHasGuid]

	rttiInterface := context.GetType( TypeInfo(IInvokable) ) as TRttiInterfaceType;
	rttiInterface.IntfFlags; // is [3]. 3 is not a valid enum value
end.

You can put a breakpoint on both lines with a comment for evaluating the value of IntfFlags yourself. IInvokable (and every interface that derives from it) has an undocumented value of "3". What does it mean? I have not been able to find anything in the source code. Clearly, System.TypInfo.TIntfFlag is declared as

TIntfFlag = (ifHasGuid, ifDispInterface, ifDispatch);

 

Edited by Der schöne Günther

Share this post


Link to post
Posted (edited)

Are you saying the returned IntfFlags *contains* a bit that *represents* an enum value of 3?  Or that the IntfFlags *itself* is a numeric value of 3?

 

In the former case, I have seen something similar before:

 

https://stackoverflow.com/questions/49950534/strange-behaviour-of-typeinfo-by-anonymous-methods

 

In the latter case, the TRttiInterfaceType.IntfFlags property returns a TIntfFlags Set, and a Set is implemented as a bitmask, where each bit represents a specific enum value.  A bitmask value of 3 means the 1st 2 bits in the bitmask are set.  And since TIntfFlags contains all of the TIntfFlag values, that would mean a bitmask value of 3 has the ifHasGuid and ifDispInterface flags enabled.

 

Which, I guess the latter does not make sense in this situation, because IInvokable is not a dispinterface.  So, it must be the former.

Edited by Remy Lebeau

Share this post


Link to post
Posted (edited)

It seems indeed as if the TIntfFlag enum was never extended since Delphi6 (I think that was when interface RTTI was introduced) - I can confirm that at least since XE an interface type with $M+ gets a fourth flag (lets call it ifHasMethodInfo) set.

If the type is an anonymous method type (see https://stackoverflow.com/q/49950534/587106) then there is a 7th enum value in the set. The situations where bit 5 and 6 are set are unknown to me.

 

You might want to file an issue in QP about this.

 

@Remy Lebeau Your diagnosis is still wrong - if the debugger shows

Quote

[(out of bound) 3]

then that means it has the 4th bit set.

 

I can confirm my findings with this code:

 

uses
  SysUtils,
  Rtti;

type
  TIntfFlagEx = (ifHasGuid, ifDispInterface, ifDispatch, ifMethodInfo, ifUnknown, ifUnknown2, ifAnonymousMethod);
  TIntfFlagsEx = set of TIntfFlagEx;

  {$M+}
  IFoo = interface
    ['{35CFB4E2-4A13-48E9-8026-C1558001F4B7}']
    procedure Main;
  end;
  {$M-}

  {$M+}
  IBar = interface(TProc)
    ['{AB2FEC1A-339F-4E58-B3DB-EC7B734F461B}']
  end;
  {$M-}

  {$M+}
  TMyProc = reference to procedure;
  {$M-}

procedure PrintIntf(typeInfo: Pointer);
var
  context: TRttiContext;
  rttiInterface: TRttiInterfaceType;
  flags: TIntfFlagsEx;
begin
  rttiInterface := context.GetType(typeInfo) as TRttiInterfaceType;
  flags := TIntfFlagsEx(rttiInterface.IntfFlags);
  Writeln(rttiInterface.Name, ' ', TValue.From(flags).ToString);
end;

begin
  PrintIntf(TypeInfo(IInterface));
  PrintIntf(TypeInfo(IInvokable));
  PrintIntf(TypeInfo(IFoo));
  PrintIntf(TypeInfo(TProc));
  PrintIntf(TypeInfo(TFunc<Integer>));
  PrintIntf(TypeInfo(TMyProc));
  PrintIntf(TypeInfo(IBar));
  Readln;
end.

prints this:

 

IInterface [ifHasGuid]
IInvokable [ifMethodInfo]
IFoo [ifHasGuid,ifMethodInfo]
TProc [ifAnonymousMethod]
TFunc<System.Integer> [ifAnonymousMethod]
TMyProc [ifMethodInfo,ifAnonymousMethod]
IBar [ifHasGuid,ifMethodInfo,ifAnonymousMethod]

 

Edited by Stefan Glienke

Share this post


Link to post
3 minutes ago, Der schöne Günther said:

I wonder where this value actually comes from. I guess not from RTL code that exists as a .pas file?

The compiler is responsible for writing typeInfo into the binary.

  • Thanks 1

Share this post


Link to post
Posted (edited)
49 minutes ago, Stefan Glienke said:

It seems indeed as if the TIntfFlag enum was never extended since Delphi6 (I think that was when interface RTTI was introduced) - I can confirm that at least since XE an interface type with $M+ gets a fourth flag (lets call it ifHasMethodInfo) set.

If the type is an anonymous method type (see https://stackoverflow.com/q/49950534/587106) then there is a 7th enum value in the set. The situations where bit 5 and 6 are set are unknown to me.

OK.

Quote

You might want to file an issue in QP about this.

https://quality.embarcadero.com/browse/RSP-24631

Quote

 

@Remy Lebeau Your diagnosis is still wrong - if the debugger shows [(out of bound) 3] then that means it has the 4th bit set.

I'm aware of that.  But that is not the exact text you originally showed, which is why I questioned it.

 

Edited by Remy Lebeau

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×