1

At positive offsets the VMT stores pointers to all user defined virtual methods.
I need to write some code to hook the VMT. The way I do this is to get a pointer to a virtual method in an ancestor class.
Let's say: TCustomForm.ShowModal. I then look up the offset in the VMT of TCustomForm. With this offset in hand I go to TMyForm and alter its VMT to point to the function I need.

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.

How do I obtain the size of the (user definable part of) the VMT?

Johan
  • 74,508
  • 24
  • 191
  • 319
  • 1
    [Where can I find information on the structure of the Delphi VMT?](https://stackoverflow.com/q/760513/576719) – LU RD Aug 20 '17 at 15:32
  • I might misremember, but in System.Rtti there is TVirtualMethodInterceptor class. There is the creation of the ProxyClass, this might help you, as it creates a VMT copy, some of the code there might help you. I remember aomething like vmtSize. – nil Aug 20 '17 at 15:32
  • @LURD, that question has only incorrect answers to this question as Stephan points out in his comment to this answer: https://stackoverflow.com/a/761101/650492 – Johan Aug 20 '17 at 15:55
  • 2
    In the built-in assembler, it is pretty easy to find the actual index. There is a VMTOFFSET "macro" that returns the offset of a virtual method into the VMT. But there is none that telsl you the size of the VMT. I guess this is not stored anywhere (well, except in the internal data of the compiler). The compiler simply only uses the correct offsets (or indices) and never accesses past the VMT. – Rudy Velthuis Aug 20 '17 at 20:31
  • 2
    Did you already take a look at the code of MethodAddress in System.pas? It shows you that the number of methods is stored as the first word (16 bit) of the VMT, to which a pointer is stored at offset vmtMethodTable in the TClass structure, to which the first DWORD of every object points. – Rudy Velthuis Aug 20 '17 at 20:49

2 Answers2

0

Digging through the RTL source I think this is the way to get the count:

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.

Johan
  • 74,508
  • 24
  • 191
  • 319
0

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. TRttiInstanceType knows the VmtSize of the associated class.

So using VmtSize and a VMT entry being a 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. But it is possible to subtract all entries from a given base class, e.g. 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. Although I'm not sure if this is up-to-date and correct.

nil
  • 1,320
  • 1
  • 10
  • 21