Как передать интерфейс в объект в Delphi

В delphi 2009 у меня есть ссылка на IInterface, которую я хочу передать в базовый TObject

Использование TObject(IInterface), очевидно, не работает в Delphi 2009 (предполагается, что он работает в Delphi 2010)

Мои поисковые запросы приводят меня к функции, которая должна делать трюк, но это не работает для меня, я получаю AV, когда пытаюсь для вызова методов на возвращаемом объекте.

Я не могу модифицировать классы, и я знаю, что это нарушает OOP

Ответ 1

Вместо того, чтобы полагаться на внутреннюю структуру объекта Delphi, вы также можете реализовать свои объекты с помощью другого интерфейса, который просто возвращает объект. Это, конечно, работает только в том случае, если у вас есть доступ к исходному коду объектов для начала, но вы, вероятно, даже не должны использовать эти хаки, если у вас нет доступа к исходному коду объектов.

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;

Ответ 2

Вы правы. Начиная с Delphi 2010, вы можете использовать оператор as, например. через aObject := aInterface as TObject или даже aObject := TObject(aInterface).

Этот оператор as использует специальный GUID скрытого интерфейса (ObjCastGUID) для извлечения экземпляра объекта, вызывая расширенную версию TObject.GetInterface, которая не существует до Delphi 2010. См. исходный код System.pas чтобы увидеть, как это работает.

Я опубликовал некоторый код для Delphi 6 до XE2, включая Delphi 2009.

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

Ответ 3

Вкратце: вы не должны или добавлять интерфейс с помощью метода, который возвращает указатель для вас. Все остальное - хакерство.

Обратите внимание, что интерфейс "экземпляр" может быть реализован на другом языке (они совместимы с COM) и/или может быть заглушкой для чего-то из процесса и т.д. и т.д.

В целом: экземпляр интерфейса согласуется только с интерфейсом и ничего другого, конечно, не реализуется как экземпляр Delphi TObject

Ответ 4

Существует хорошая альтернатива, когда вы знаете, что реализующий объект является потомком TComponent.

Вы можете использовать интерфейс IInterfaceComponentReference, который определен в Classes:

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

И затем он объявлен в TComponent (и реализован для возврата self):

  TComponent = class(TPersistent, IInterface, IInterfaceComponentReference)

Итак, если вы знаете, объект реализации является TComponent, тогда вы можете сделать это:

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

Ответ 5

Hallvard hack очень специфичен для того, как компилятор Delphi генерирует код. Это было замечательно стабильно в прошлом, но похоже, что они изменили что-то существенное в Delphi 2009. У меня установлен только 2007 год, и в этом случае код Hallvard отлично работает.

Возвращает ли GetImplementingObject NIL?

Если это так, то если вы отлаживаете и устанавливаете точку прерывания в аргументе case в процедуре GetImplementingObject, что оценивает значение QueryInterfaceThunk.AddInstruction в отладчике?

Ответ 6

var
  N, F: NativeInt; // NativeInt is Integer(in delphi 32bit ) 
  S: TObject;
begin
  N := NativeInt(Args[0].AsInterface) - 12; 
  {subtract 12 byte to get object address(in x86 ,1 interface on class) }
  S := TObject(N);    
  writeln(S.ToString);

end;