为什么不能将Marshaled接口作为整数(或指针)传递

时间:2010-03-18 11:18:36

标签: delphi com marshalling delphi-7 marshalbyrefobject

我将Visio外接程序的参数传递给MyCOMServer(Interface Marshalling in Delphi必须在MyCOMServer的internals方法中将接口作为指针传递。我尝试将接口传递给内部方法作为接口的指针,但是在后面转换后当我尝试调用接口的方法时,我得到异常。简单的例子(Fisrt块执行没有错误,但在第二个块我在发送到IVApplication接口的属性后得到Exception):

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;

为什么我不能这样做?

2 个答案:

答案 0 :(得分:1)

当你有一个实现多个接口的对象并且你在它们之间进行转换时,你会得到不同的地址。它必须对如何找到这些接口的方法做些什么。

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

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变量中然后调用方法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);

答案 1 :(得分:0)

我只是猜测,因为我对COM知之甚少,但是将接口转换为整数或指针会搞乱内部引用计数。您的界面可能会被释放,这可以解释访问冲突。

编辑:我不知道Pointer(Vis) := Pointer(i)无论如何都有效。演员不应该创建一个临时对象。也许这就是Vis未被分配的原因?