Delphi中的COM方法偏移

时间:2010-07-01 17:11:50

标签: delphi com vtable

在Delphi中,如何找到COM方法的地址? 我可以对偏移进行硬编码

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

但我更喜欢使用符号名称。以下显然不起作用:

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

谢谢!

4 个答案:

答案 0 :(得分:6)

您可以使用vmtoffset汇编程序指令获取接口方法相对于接口方法表开头的字节偏移量。看一下 System.pas _IntfCast的实现,例如:

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

第一个表达式加0;第二,8。

但是,您无法对这些表达式进行参数化。它们是编译时常量,因此您无法在运行时选择所需的方法。您需要提前表示所有可能的方法名称。

所有真正需要挂钩的是QueryInterface。完成后,您可以返回所需的任何代理对象,可以拦截对所有其他方法的调用。

答案 1 :(得分:3)

我不认为Delphi支持这一点。对偏移量进行硬编码可能是唯一可行的,因为编译器不会将接口方法计数为可将其值分配给函数指针的符号,即对象方法或独立函数的方式。

你为什么要这样做,BTW?

答案 2 :(得分:2)

您的代码错误,因为接口引用不是指向接口方法表的指针,而是指向接口方法表指针的指针。这就是Delphi接口在二进制级别上实现的方式。很难说更多,并指出代码中的错误,因为您没有给出可编译的代码示例。使用以下代码将接口引用正确转换为方法指针,这个想法取自Barry Kelly's demonstration of creating a method pointer from a method reference

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的符号名称,最好将它们自己声明为偏移常量

答案 3 :(得分:1)

  

另外两个指令允许汇编代码访问动态和   虚方法: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;