简体   繁体   English

如何获取VMT中的条目数(虚拟方法)?

[英]How do I get the number of entries (virtual methods) in the VMT?

At positive offsets the VMT stores pointers to all user defined virtual methods. VMT以正偏移量存储指向所有用户定义的虚拟方法的指针。
I need to write some code to hook the VMT. 我需要编写一些代码来挂接VMT。 The way I do this is to get a pointer to a virtual method in an ancestor class. 我这样做的方法是获得一个指向祖先类中的虚拟方法的指针。
Let's say: TCustomForm.ShowModal . 假设: TCustomForm.ShowModal I then look up the offset in the VMT of TCustomForm . 然后,我在TCustomForm的VMT中TCustomForm偏移量。 With this offset in hand I go to TMyForm and alter its VMT to point to the function I need. 有了这个偏移量后,我转到TMyForm并更改其VMT以指向我需要的功能。

I would like to generalize the approach and in order to do so I would like to know the total number of entries the VMT holds so I don't search past the end. 我想归纳一下这种方法,为了做到这一点,我想知道VMT持有的条目总数,所以我不会在最后搜索。

How do I obtain the size of the (user definable part of) the VMT? 如何获得VMT(用户可定义的部分)的尺寸?

Digging through the RTL source I think this is the way to get the count: 挖掘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;

Feel free to correct me if needed. 如有需要,请随时纠正我。

A way to do this without much actual knowledge of the VMT structure, and hence less prone to breaking when the VMT structure changes again, is using the Rtti for this. 一种在没有太多VMT结构实际知识的情况下执行此操作的方法,因此在VMT结构再次更改时不太容易发生损坏,为此使用了Rtti。 TRttiInstanceType knows the VmtSize of the associated class. TRttiInstanceType知道关联类的VmtSize

So using VmtSize and a VMT entry being a Pointer 因此,使用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;

This will however include all entries inherited from the base class(es) too. 但是,这也将包括所有从基类继承的条目。 Including the ones from TObject at negative offsets. 包括来自TObject的负偏移量的对象。 But it is possible to subtract all entries from a given base class, eg TObject . 但是可以从给定的基类(例如TObject减去所有条目。 Here is an approach with a variable base class provided: 这是提供可变基类的一种方法:

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;

And : When using Jedi there is a function in JclSysUtils called GetVirtualMethodCount . 并且 :使用Jedi时JclSysUtils有一个名为GetVirtualMethodCount的函数。 Although I'm not sure if this is up-to-date and correct. 尽管我不确定这是否是最新和正确的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM