Как я могу получить количество записей (виртуальных методов) в VMT?
При положительном смещении VMT хранит указатели на все пользовательские виртуальные методы.
Мне нужно написать код, чтобы подключить VMT. Я делаю это, чтобы получить указатель на виртуальный метод в классе предка.
Скажем так: TCustomForm.ShowModal
, Затем я смотрю смещение в VMT TCustomForm
, С этим смещением в руке я иду к TMyForm
и измените его VMT, чтобы указать на нужную мне функцию.
Я хотел бы обобщить подход, и для этого я хотел бы знать общее количество записей, которые содержит VMT, чтобы я не искал до конца.
Как получить размер (определяемой пользователем части) VMT?
2 ответа
Копаясь в источнике 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;
Не стесняйтесь поправлять меня, если это необходимо.
Способ сделать это без особых фактических знаний о структуре 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;
И: при использовании джедая есть функция в JclSysUtils
называется GetVirtualMethodCount
, Хотя я не уверен, что это актуально и правильно.