代码之家  ›  专栏  ›  技术社区  ›  Dmitry Streblechenko

Delphi中的COM方法

  •  9
  • Dmitry Streblechenko  · 技术社区  · 16 年前

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

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

    但我更喜欢用象征性的名字。下面的说法显然行不通:

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

    谢谢

    4 回复  |  直到 16 年前
        1
  •  6
  •   Rob Kennedy    16 年前

    你可以使用 vmtoffset 汇编程序指令,用于获取接口方法相对于接口方法表开头的字节偏移量。请看一下 _IntfCast 在里面 系统pas ,例如:

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

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

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

    你们所有人 真正地 需要钩住的是 QueryInterface 一旦你有了它,你可以返回你想要的任何代理对象,它可以拦截对所有其他方法的调用。

        2
  •  3
  •   Mason Wheeler    16 年前

    我认为德尔福不支持这一点。硬编码偏移量可能是唯一可行的方法,因为编译器不会像对象方法或独立函数那样,将接口方法计算为可以将值分配给函数指针的符号。

    顺便说一句,你为什么要这么做?

        3
  •  2
  •   Rob Kennedy    16 年前

    您的代码是错误的,因为接口引用不是指向接口方法表的指针,而是 指向接口方法表指针的指针 .这就是如何在二进制级别实现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的符号名,你最好自己把它们声明为偏移量常量

        4
  •  1
  •   Pax Beach    9 年前

    另外两条指令允许汇编代码访问动态和 虚拟方法:VMTOFFSET和DMTINDEX。

    VMTOFFSET检索虚拟方法指针的偏移量(字节) 虚拟方法参数的表项,从 虚拟方法表(VMT)。该指令需要一个完全指定的 以方法名作为参数的类名(例如, TExample。VirtualMethod),或接口名称和接口方法 名称

    DMTINDEX检索所传递数据的动态方法表索引 动态方法。该指令还需要完全指定的类名 例如,使用方法名作为参数, TExample。动态方法。要调用动态方法,请调用 系统@使用包含该值的(E)SI寄存器调用DYNAINST 从DMTINDEX获得。

    docwiki.embarcadero.com

    下面是获取所需方法指针的代码

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