RTTI 访问 VCL 的私有方法,例如TCustomForm.SetWindowState

RTTI access to private methods of VCL, e.g. TCustomForm.SetWindowState

在 Delphi 10.1 Berlin 中关于关闭允许轻松访问 class 的私有成员(字段和方法)的 class helper 漏洞的辩论中,它是经常声称

但是,如果我 运行 这个简单的单元(一个简单的表格,只有一个 TListBox,没有别的):

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.

列表框中的文字为:

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

这意味着我无法访问 TCustomForm 的私有方法 SetWindowState。这是因为并非 RTL/VCL/FMX 中的所有 class 都扩展了 RTTI,还是我做错了什么?

如果我做错了什么或忘记了什么,那怎么办?换句话说,我需要做什么才能让 RTTI 访问 SetWindowStateTCustomForm?我在西雅图或更早的时候也无法获得此访问权限。

备注

我知道如何访问该方法,利用 class 助手仍然可以获得私有方法的 地址 的事实,但这不是我的题。 我特别想问一下如何使用 RTTI

显而易见的结论是,虽然此类型是使用扩展 RTTI 编译的,但私有方法不包括 RTTI。

为了使用 RTTI 访问 严格的 private/private 方法,请使用编译器指令 {$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];

示例:

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

设置 public、受保护和私有方法的可见性

注意:这个指令的作用域是本地RTL/VCL/FMX关闭了这些选项,这意味着访问protected/private 无法使用 RTTI 方法。