3

In the debate about the closing of the class helper loophole that allowed easy access to private members (fields and methods) of a class in Delphi 10.1 Berlin, it is often claimed that

  • extended RTTI allows access to the private members of a class that was compiled with (extended) RTTI enabled, and
  • all VCL/RTL/FMX classes have this enabled.

However, if I run this simple unit (a simple form with one TListBox, nothing else):

unit RttiAccessTest;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Rtti, Vcl.StdCtrls;

type
  TForm16 = class(TForm)
    ListBox1: TListBox;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form16: TForm16;

implementation

{$R *.dfm}

function GetMethodString(const MethodName: string): string;
var
  M: TRTTIMethod;
  I: Integer;
begin
  M := TRttiContext.Create.GetType(TCustomForm).GetMethod(MethodName);
  if Assigned(M) then
    Result := 'Method ' + MethodName + ': ''' + M.ToString + ';'''
  else
    Result := 'Method ' + MethodName + ' cannot be found';
end;

procedure TForm16.FormCreate(Sender: TObject);
begin
  Listbox1.Items.Add(GetMethodString('SetWindowState'));
  Listbox1.Items.Add(GetMethodString('ShowModal'));
end;

end.

The text in the list box is:

Method SetWindowState cannot be found 
Method ShowModal: 'function ShowModal: Integer;'

This means I cannot get access to this private method SetWindowState of TCustomForm. Is this because not all classes in the RTL/VCL/FMX have extended RTTI, or am I doing something wrong?

If I am doing something wrong or forgetting something, then what? In other words, what do I have to do to get RTTI access to, say, SetWindowState of TCustomForm? I cannot get this access in Seattle or earlier either.

Note

I know how to get access to the method anyway, using the fact that class helpers can still get the address of private methods, but that is not my question. I am particularly asking about how to do this with RTTI.

Community
  • 1
  • 1
Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
  • There was an identical question a couple of days ago, searching... – LU RD Jun 19 '16 at 08:50
  • Found it: [How to access the private method TStreamReader.FillBuffer in Delphi 10.1 Berlin?](http://stackoverflow.com/q/37874351/576719). Conclusion was that {$MethodInfo} is OFF by default in the RTL. – LU RD Jun 19 '16 at 08:59
  • The `METHODINFO` was not enough, see my answer. – LU RD Jun 19 '16 at 09:58
  • But there, the answer mentioned the class helper addres/method trick. Not how to od it with RTTI. Obviously, it is not possible with RTTI. – Rudy Velthuis Jun 19 '16 at 11:19
  • private is private... see http://blog.marcocantu.com/blog/2016-june-closing-class-helpers-loophole.html – cydo Jun 19 '16 at 16:47
  • I know that private is private and I fully agree with the fix of the bug -- closing the loophole -- (as you can see in the discussions in which I took part on the Embarcadero forums). But the argument was made that you can always resort to RTTI if the need REALLY arises. I even made that argument, but apparently it was bogus. For RTL/VCL/FMX, it doesn't seem to be so. – Rudy Velthuis Jun 20 '16 at 15:42

2 Answers2

3

The obvious conclusion is that whilst this type is compiled with extended RTTI, that RTTI is not included for private methods.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • IOW, the claim that we can easily access VCL, etc. private members with RTTI is not true. – Rudy Velthuis Jun 19 '16 at 11:16
  • If anyone is making that claim, then they are wrong. I really can't think that there could be anything more to say on this topic than what I already said. – David Heffernan Jun 19 '16 at 11:56
  • 1
    The closest you can get is to say that you can choose to *provide* access to private members by including RTTI. But the VCL chooses *not* to do that (presumably due to the massive impact that would have in terms of RTTI baggage that would have to be pre-compiled in, whether you intended using it or not). This could be solved (or at least addressed) with a *Compile with RTTI units* option, similar to the existing *Compile with DEBUG dcu's* one (so *two* new sets of DCU's: that is, +RTTI both with and without debug) to give people the ability to choose. – Deltics Jun 20 '16 at 05:53
  • I agree about the *compile with RTTI DCUs* idea. I had actually hoped that perhaps the debug DCUs would contain RTTI as well, but no, they don't. – Rudy Velthuis Jun 20 '16 at 15:46
  • @RudyVelthuis It would be poor form for the debug DCUs to differ in that regard. It would mean code that behaved differently at runtime depending on whether or not you used debug DCUs. – David Heffernan Jun 20 '16 at 15:47
  • @David: yes, you are right. I thought of that too, but much later. Separate RTTI dcus would be cool, though, if explained well. – Rudy Velthuis Jun 20 '16 at 16:04
  • I agree with that. I don't use extended RTTI at all and would be very happy not to be shipping it. – David Heffernan Jun 20 '16 at 16:06
1

In order to access strict private/private methods with RTTI, use the compiler directive {$RTTI}.

Syntax

The general syntax of the $RTTI directive can be split into three parts. The basic form of $RTTI is as follows:

{$RTTI INHERIT|EXPLICIT [visibility-clause]}

visibility-clause:

METHODS|PROPERTIES|FIELDS (visibility-expression)

visibility-expression:

[vcPrivate],[vcProtected], [vcPublic], [vcPublished];

Example:

{$RTTI EXPLICIT METHODS([vcPublic, vcProtected, vcPrivate])}

Sets the visibility for public,protected and private methods

Note: The scope is local for this directive and the RTL/VCL/FMX have these options off, which means that access to protected/private methods with RTTI are not possible.

Community
  • 1
  • 1
LU RD
  • 34,438
  • 5
  • 88
  • 296