0

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?

Community
  • 1
  • 1
Semyon.Khmelev
  • 197
  • 1
  • 14
  • Is MyCOMServer an .exe or .dll ? – Dan Byström Mar 18 '10 at 11:23
  • You cannot pass a pointer from one process into another process. – Dan Byström Mar 18 '10 at 11:33
  • @dandybystrom i Can.See http://stackoverflow.com/questions/2455183/interface-marshalling-in-delphi. But I Can't in one process ((. – Semyon.Khmelev Mar 18 '10 at 11:36
  • Is there any need for all the interim casting? What's wrong with Vis := Interface_ – James Mar 18 '10 at 11:37
  • @JamesB It's simply example. At actual I can pass interface just as variant parameters. – Semyon.Khmelev Mar 18 '10 at 11:49
  • 1
    @cemick When providing examples your code should be as accurate to the real thing as possible, and preferably compilable. If the problem is that you can't call Vis.Path after assigning Interface_ to Vis then it's probably the assignment that is the problem, so it should be as simple as possible to eliminate side issues. – James Mar 18 '10 at 12:03
  • @JamesB assigment at first block have't problem(Pointer(IMy) := Pointer(i);). – Semyon.Khmelev Mar 18 '10 at 12:46

2 Answers2

1

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
  • 6,992
  • 2
  • 43
  • 69
0

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?

jpfollenius
  • 16,456
  • 10
  • 90
  • 156
  • No, I have inserted line "str := (Interface_ as IVApplication).Path;" after " str := Vis.Path;" for check this. But exception have kept. – Semyon.Khmelev Mar 18 '10 at 11:43