Как я могу получить количество записей (виртуальных методов) в 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, Хотя я не уверен, что это актуально и правильно.

Другие вопросы по тегам