Как привести интерфейс к объекту в Delphi - PullRequest
12 голосов
/ 09 ноября 2010

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

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

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

Я не могу изменить классы, и я знаю, что это нарушает ООП

Ответы [ 6 ]

18 голосов
/ 10 ноября 2010

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

17 голосов
/ 23 июня 2012

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

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

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

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

3 голосов
/ 16 марта 2013

Есть хорошая альтернатива, когда вы знаете, что реализующий объект - 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;
3 голосов
/ 10 ноября 2010

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

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

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

2 голосов
/ 10 ноября 2010

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

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

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

0 голосов
/ 28 апреля 2012
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;
...