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.