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开发者_StackOverflow 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?
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);
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?
精彩评论