You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Lazarus(FPC)中如何获取类或记录方法的指针?

FPC中不依赖RTTI获取方法地址并调用的正确方式

需求:需要在不使用RTTI的前提下获取方法地址(尤其是FPC中记录类型的方法,RTTI经常无法使用),之后通过Rtti.Invoke调用方法,但现有代码均触发访问冲突。

错误示例1:直接取对象方法地址导致崩溃

procedure TForm1.Button1Click(Sender: TObject);
var
  tm: TMethod;
begin
  tm := TMethod(@Button2.Click); // Access Violation
  Rtti.Invoke(tm.Code, [Button2], ccReg, nil, False, False);
end; 

错误示例2:Delphi可行但FPC崩溃的写法

procedure TForm1.Button1Click(Sender: TObject);
var
  tm: TMethod;
begin
  tm.Code := @TButton.Click;
  tm.Data := Button2;
  Rtti.Invoke(tm.Code, [Button2], ccReg, nil); // Access Violation
end; 

核心问题分析

访问冲突的根源是参数传递重复:实例方法的第一个隐式参数是Self,TMethod.Data已经承担了传递Self的作用,再在Rtti.Invoke的参数数组中传入Button2,会导致参数栈结构错误,触发内存访问异常。

正确实现方式

1. 类实例方法的调用

修改代码,移除参数数组中的实例对象:

procedure TForm1.Button1Click(Sender: TObject);
var
  tm: TMethod;
begin
  tm.Code := @TButton.Click;
  tm.Data := Button2;
  // 无需在参数数组中传入Button2,Self已通过tm.Data传递
  Rtti.Invoke(tm.Code, [], ccReg, nil);
end; 

2. 记录类型方法的调用

记录是值类型,需要传递其地址作为Self:

type
  TMyRecord = record
    procedure Test;
  end;

procedure TMyRecord.Test;
begin
  ShowMessage('Record method called');
end;

// 调用示例
var
  Rec: TMyRecord;
  tm: TMethod;
begin
  tm.Code := @TMyRecord.Test;
  tm.Data := @Rec; // 值类型记录需传递地址作为Self
  Rtti.Invoke(tm.Code, [], ccReg, nil);
end;

3. 注意事项

  • 避免直接通过对象实例取方法地址(如@Button2.Click),这种写法在FPC中会直接访问虚拟表,容易引发内存错误;
  • 确保TMethod.Code指向类的方法地址(如@TButton.Click),TMethod.Data绑定实例或记录的地址;
  • 调用时不要在参数数组中重复传入Self对应的对象/记录。

内容的提问来源于stack exchange,提问作者Antinet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 04:42:41