Смещения метода COM в Delphi - PullRequest
9 голосов
/ 01 июля 2010

В Delphi как узнать адрес COM-метода?Я могу жестко закодировать смещения

//0 is the offset of the QueryInterface method
p := TPonterArray(pointer(SomeInterface)^)[0];

, но я бы предпочел использовать символические имена.Следующее явно не работает:

var M : TMethod;
...
M := TMethod(SomeInterface.QueryInterface);

Спасибо!

Ответы [ 4 ]

6 голосов
/ 02 июля 2010

Вы можете использовать директиву ассемблера vmtoffset, чтобы получить байтовое смещение метода интерфейса относительно начала таблицы методов интерфейса.Взгляните на реализацию _IntfCast в System.pas , например:

call dword ptr [eax] + vmtoffset IInterface.QueryInterface
...
call dword ptr [eax] + vmtoffset IInterface._Release

Первое выражение добавляет 0;второе, 8.

Вы не можете параметризовать эти выражения.Они являются константами времени компиляции, поэтому вы не можете выбрать, какой метод вы хотите во время выполнения.Вам необходимо заранее указать все возможные имена методов.

Все, что вам действительно нужно перехватить - это QueryInterface.После этого вы можете вернуть любой прокси-объект, который вы хотите, который может перехватывать вызовы для всех других методов.

3 голосов
/ 01 июля 2010

Я не думаю, что Delphi это поддерживает.Жесткое кодирование смещений, вероятно, единственное, что будет работать, так как компилятор не считает методы интерфейса как символы, значение которых может быть назначено указателю функции, как методы объекта или автономные функции.

Почемуты пытаешься сделать это, кстати?

2 голосов
/ 04 июля 2010

Ваш код неверен, поскольку ссылка на интерфейс - это не указатель на таблицу методов интерфейса, а указатель на указатель на таблицу методов интерфейса .Именно так интерфейсы Delphi реализованы на двоичном уровне.Трудно сказать больше и указать на ошибку в вашем коде, потому что вы не дали пример кода, который можно скомпилировать.Используйте следующий код для правильного преобразования ссылки на интерфейс в указатель метода, идея была взята из демонстрации Барри Келли создания указателя метода из ссылки на метод :

procedure IntRefToMethPtr(const IntRef; var MethPtr; MethNo: Integer);
type
  TVtable = array[0..999] of Pointer;
  PVtable = ^TVtable;
  PPVtable = ^PVtable;
begin
  // QI=0, AddRef=1, Release=2, etc
  TMethod(MethPtr).Code := PPVtable(IntRef)^^[MethNo];
  TMethod(MethPtr).Data := Pointer(IntRef);
end;

Если вы предпочитаете символьнуюимена для MethNo, вам лучше объявить их как константы смещения

1 голос
/ 30 апреля 2017

Две дополнительные директивы позволяют сборочному коду получать доступ к динамическим и виртуальные методы: VMTOFFSET и DMTINDEX.

VMTOFFSET извлекает смещение в байтах указателя виртуального метода запись в таблице аргумента виртуального метода с начала таблица виртуальных методов (VMT). Эта директива нуждается в полностью указанном имя класса с именем метода в качестве параметра (например, TExample.VirtualMethod), или имя интерфейса и метод интерфейса имя.

DMTINDEX извлекает индекс таблицы динамических методов переданного динамический метод. Эта директива также нуждается в полностью указанном имени класса с именем метода в качестве параметра, например, TExample.DynamicMethod. Чтобы вызвать динамический метод, вызовите System. @ CallDynaInst с регистром (E) SI, содержащим значение получено от DMTINDEX.

docwiki.embarcadero.com

Здесь код для получения нужного указателя метода

function GetMethodPointer(const IntRef: IInterface): Pointer; assembler;
asm
  mov eax, [IntRef] 
  add eax, vmtoffset ISomeInterface.MemberMethod
  mov eax, [eax]
end;
...