我将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;
为什么我不能这样做?
答案 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
未被分配的原因?