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

发布于 2024-08-25 14:09:35 字数 919 浏览 10 评论 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;

为什么我不能这样做?

I passed ref of interface from Visio Add-ins to MyCOMServer (Interface Marshalling in Delphi have to pass interface as pointer in internals method of MyCOMServer. I try to pass interface to internal method as pointer of interface, but after back cast when i try call method of interface I get exception. Simple example(Fisrt block execute without error, but At Second block I get Exception after addressed to property of IVApplication interface):

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;

Why I can't do like this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

红ご颜醉 2024-09-01 14:09:35

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

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

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);

When you have an object that implements multiple interfaces and you cast between them you will get different addresses. It has to do something with how to find the methods of those interfaces.

Let's say that you have two interfaces and a class that implements them, the methods show just a message with the 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;

When you tell the compiler to call A from IMyIntfA, it knows that A is located at the address of IMyIntfA plus an offset. The same applies to calling method B from IMyIntfB.
But what you are doing is putting the reference to IMyIntfB in a var of IMyIntfA and then call method A. The result is that the address of the method the compiler calculates is totally wrong.

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: I'am not a guru and I don't know the technical details about how everything is implemented. This is only a rough explanation which should give you an idea of why your code goes wrong. If you want your code to succeed do this:

Vis := Interface_ as IVApplication;
Str := (Vis.Path);
妄想挽回 2024-09-01 14:09:35

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

编辑:我想知道Pointer(Vis) := Pointer(i)是否有效。强制转换不应该创建一个临时对象吗?也许这就是为什么 Vis 没有被分配的原因?

I'm only guessing since I don't know much about COM, but casting an interface to an integer or pointer does mess up the internal reference counting. Your interface is likely to be released, which would explain the access violation.

EDIT: I wonder that Pointer(Vis) := Pointer(i) works anyway. Shouldn't the cast create a temporary object. Maybe that's why Vis does not get assigned?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文