How to cast a Interface to a Object in Delphi

15,170

Solution 1

Instead of relying on Delphi's internal object layout you could also have your objects implement another interface which would simply return the object. This, of course, only works if you have access to the source code of the objects to begin with, but you probably shouldn't even use these hacks if you don't have access the source code of the objects.

interface 

type
  IGetObject = interface
    function GetObject: TObject;
  end;

  TSomeClass = class(TInterfacedObject, IGetObject)
  public
    function GetObject: TObject;
  end;

implementation

function TSomeClass.GetObject: TObject;
begin
  Result := Self;
end;

Solution 2

You are right. Beginning with Delphi 2010, you are able to use the as operator, e.g. via aObject := aInterface as TObject or even aObject := TObject(aInterface).

This as operator use a special hidden interface GUID (ObjCastGUID) to retrieve the object instance, calling an enhanced version of TObject.GetInterface, which does not exist prior to Delphi 2010. See source code of System.pas unit to see how it works.

I've published some code working for Delphi 6 up to XE2, including Delphi 2009.

See http://blog.synopse.info/post/2012/06/13/Retrieve-the-object-instance-from-an-interface

Solution 3

There is a nice alternative when you know the implementing object is a TComponent descendant.

You can use the IInterfaceComponentReference interface, which is defined up in Classes unit:

IInterfaceComponentReference = interface
  ['{E28B1858-EC86-4559-8FCD-6B4F824151ED}']
  function GetComponent: TComponent;
end;

And then it's declared in TComponent (and implemented to return self):

  TComponent = class(TPersistent, IInterface, IInterfaceComponentReference)

So if you know the implementing object is a TComponent then you can do this:

function InterfaceToComponent(const AInterface: IInterface): TComponent;
var
  vReference: IInterfaceComponentReference;
begin
  if Supports(AInterface, IInterfaceComponentReference, vReference) then
    result := vReference.GetComponent
  else
    result := nil;
end;

Solution 4

In short: you shouldn't or add an interface with a method that returns the pointer for you. Anything else is hackery.

Note that an interface "instance" may be implemented in another language (they are COM compatible) and / or may be a stub for something out of process etc etc.

All in all: an interface instance only agrees to the interface and nothing else, certainly not being implemented as a Delphi TObject instance

Solution 5

Hallvard's hack is very specific to how the Delphi compiler generates code. That has been remarkably stable in the past, but it sounds like they changed something significant in Delphi 2009. I only have 2007 installed here, and in that, Hallvard's code works fine.

Does GetImplementingObject return NIL?

If so, then if you debug and set a break-point on the case statement in the GetImplementingObject routine, what does the value of QueryInterfaceThunk.AddInstruction evaluate to in the debugger?

Share:
15,170
Yona
Author by

Yona

Updated on June 05, 2022

Comments

  • Yona
    Yona almost 2 years

    In delphi 2009 I have a reference to a IInterface which I want to cast to the underlying TObject

    Using TObject(IInterface) obviously doesn't work in Delphi 2009 (it's supposed to work in Delphi 2010 though)

    My searches lead me to a function that should do the trick, but it doesn't work for me, I get AV's when I try to call methods on the returned object.

    I can't really modify the Classes and I know that this breaks OOP