0

我将接口的引用从 Visio 加载项传递给 MyCOMServer(Delphi 中的接口编组必须将接口作为指针传递给 MyCOMServer 的内部方法。我尝试将接口作为接口的指针传递给内部方法,但是当我尝试调用时返回转换后接口的方法我得到异常。简单的例子(第一个块执行没有错误,但在第二个块我在寻址到 IVApplication 接口的属性后得到异常):

procedure TMyCOMServer.test(const Interface_:IDispatch); stdcall;
var 
  IMy:_IMyInterface;
  V: Variant;
  Str: String;
  I: integer;
  Vis: IVApplication;
begin 

  ......
  {First code Block}
  Self.QuaryInterface(_IMyInterface,IMy);
  str := IMy.ApplicationName;
  V := Integer(IMy);
  i := V;
  Pointer(IMy) :=  Pointer(i);
  str := IMy.SomeProperty; // normal completion

  {Second code Block}
  str := (Interface_ as IVApplication).Path;
  V := Interface_;
  I := V;
  Pointer(Vis) :=  Pointer(i);
  str := Vis.Path;  // 'access violation at 0x76358e29: read of address 0xfeeefeee' 

end;

为什么我不能这样做?

4

2 回答 2

1

当您有一个实现多个接口的对象并在它们之间进行转换时,您将获得不同的地址。它必须与如何找到这些接口的方法有关。

假设您有两个接口和一个实现它们的类,这些方法只显示一条带有方法名的消息:

type
  IMyIntfA = interface
    ['{21ADE2EF-55BB-4B78-A23F-9BB92BE55683}']
    procedure A;
    procedure X;
  end;

  IMyIntfB = interface
    ['{7E1B90CF-569B-4DD1-8E46-7E7255D2373A}']
    procedure B;
  end;

  TMyObject = class(TInterfacedObject, IMyIntfA, IMyIntfB, IUnknown)
  public
    procedure A;
    procedure X;
    procedure B;
  end;

当您告诉编译器从 IMyIntfA 调用 A 时,它知道 A 位于 IMyIntfA 的地址加上一个偏移量。这同样适用于从 IMyIntfB 调用方法 B。但是您所做的是将IMyIntfB的引用放在IMyIntfA的var中,然后调用方法A。结果是编译器计算的方法的地址完全错误。

var
  lIntfA: IMyInterfaceA;
  lIntfB: IMyInterfaceB;
begin
  lIntfA := TMyObject.Create; //TMyObject implements IMyInterfA, IMyInterfB
  lInfB := lIntfA as IMyInterfaceB;

  if Integer(lIntfA) <> Integer(lIntfB) then
    ShowMessage('I told you so');

  Pointer(lIntfA) := Pointer(lIntfB);

  lIntfA.A; //procedure B is called, because B is at "Offset 1", like A
  lIntfA.X; //total mayhem, X is at "Offset 2", but there is nothing at IMyIntfB + offset 2
end;

PS:我不是大师,我不知道有关如何实现一切的技术细节。这只是一个粗略的解释,应该让您了解代码出错的原因。如果您希望您的代码成功,请执行以下操作:

Vis := Interface_ as IVApplication;
Str := (Vis.Path);
于 2010-03-18T12:55:03.980 回答
0

我只是猜测,因为我对 COM 了解不多,但是将接口转换为整数或指针确实会弄乱内部引用计数。您的界面可能会被释放,这将解释访问冲突。

编辑:我想知道这Pointer(Vis) := Pointer(i)仍然有效。演员不应该创建一个临时对象。也许这就是为什么Vis没有被分配?

于 2010-03-18T11:33:33.270 回答