views:

109

answers:

2

I passed ref of interface from Visio Add-ins to MyCOMServer (http://stackoverflow.com/questions/2455183/interface-marshalling-in-delphi).I 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?

A: 

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?

Smasher
No, I have inserted line "str := (Interface_ as IVApplication).Path;" after " str := Vis.Path;" for check this. But exception have kept.
cemick
A: 

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