在正偏移处,VMT 存储指向所有用户定义的虚拟方法的指针。
我需要编写一些代码来挂钩 VMT。我这样做的方法是获取指向祖先类中的虚拟方法的指针。
比方说:TCustomForm.ShowModal
。然后我在 VMT 中查找偏移量TCustomForm
。有了这个偏移量,我去TMyForm
更改它的 VMT 以指向我需要的功能。
我想概括一下这种方法,为了做到这一点,我想知道 VMT 拥有的条目总数,所以我不会搜索到最后。
如何获取 VMT(用户可定义部分)的大小?
在正偏移处,VMT 存储指向所有用户定义的虚拟方法的指针。
我需要编写一些代码来挂钩 VMT。我这样做的方法是获取指向祖先类中的虚拟方法的指针。
比方说:TCustomForm.ShowModal
。然后我在 VMT 中查找偏移量TCustomForm
。有了这个偏移量,我去TMyForm
更改它的 VMT 以指向我需要的功能。
我想概括一下这种方法,为了做到这一点,我想知道 VMT 拥有的条目总数,所以我不会搜索到最后。
如何获取 VMT(用户可定义部分)的大小?
一种在没有太多实际 VMT 结构知识的情况下执行此操作的方法,因此当 VMT 结构再次更改时不太容易中断,为此使用 Rtti。TRttiInstanceType
知道VmtSize
相关类的。
所以使用VmtSize
和 VMT 条目是Pointer
function GetVirtualMethodCount(AClass: TClass): Integer;
var
AContext: TRttiContext;
AType: TRttiType;
begin
AType := AContext.GetType(AClass);
Result := (AType as TRttiInstanceType).VmtSize div SizeOf(Pointer);
end;
然而,这也将包括从基类继承的所有条目。包括来TObject
自负偏移量的那些。但是可以从给定的基类中减去所有条目,例如TObject
. 这是一种提供可变基类的方法:
function GetVirtualMethodCountMinusBase(AClass: TClass; ABaseClass: TClass): Integer;
var
AContext: TRttiContext;
AType, ABaseType: TRttiType;
begin
AType := AContext.GetType(AClass);
ABaseType := AContext.GetType(ABaseClass);
Result := ((AType as TRttiInstanceType).VmtSize - (ABaseType as TRttiInstanceType).VmtSize) div SizeOf(Pointer);
end;
并且:当使用JediJclSysUtils
时,调用了一个函数GetVirtualMethodCount
。虽然我不确定这是否是最新的和正确的。
挖掘 RTL 源代码,我认为这是获得计数的方法:
function GetVMTCount(AClass: TClass): integer;
var
p: pointer;
VirtualMethodCount: word;
begin
p := PPointer(PByte(AClass) + vmtMethodTable)^;
VirtualMethodCount:= PWord(p)^;
//Size of the VMT in bytes
Result:= VirtualMethodCount * SizeOf(Pointer) - vmtSelfPtr;
//Number of entries in the VMT
Result:= Result div SizeOf(Pointer);
end;
如果需要,请随时纠正我。