在Delphi中,如何找到COM方法的地址? 我可以对偏移进行硬编码
//0 is the offset of the QueryInterface method
p := TPonterArray(pointer(SomeInterface)^)[0];
但我更喜欢使用符号名称。以下显然不起作用:
var M : TMethod;
...
M := TMethod(SomeInterface.QueryInterface);
谢谢!
答案 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获得。
这里是获取所需方法指针的代码
function GetMethodPointer(const IntRef: IInterface): Pointer; assembler;
asm
mov eax, [IntRef]
add eax, vmtoffset ISomeInterface.MemberMethod
mov eax, [eax]
end;