2010-11-09 19 views
11

en Delphi 2009 tengo una referencia a un IInterface que quiero lanzar al subyacente TObjectCómo echar una interfaz a un objeto en Delphi

Usando TObject(IInterface), obviamente, no funciona en Delphi 2009 (que se supone que trabajan en Delphi 2010, aunque)

Mis búsquedas me llevan a a function that should do the trick, pero no funciona para mí, me sale de AV cuando trato de llamar a métodos en el objeto devuelto.

Realmente no puede modificar las clases y sé que esto rompe truco POO

Respuesta

18

En lugar de confiar en el diseño interno del objeto de Delphi, también podría hacer que sus objetos implementen otra interfaz que simplemente devolvería el objeto. Esto, por supuesto, sólo funciona si tiene acceso al código fuente de los objetos, para empezar, pero es probable que ni siquiera debería utilizar estos hacks si usted no tiene acceso al código fuente de los objetos.

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; 
+1

De hecho, ya terminé usando esta solución, pero no pude publicar mi propia respuesta todavía. ¡Felicitaciones a usted! – Yona

2

de Hallvard es muy específico a la forma en que el compilador genera código Delphi. Esa ha sido notablemente estable en el pasado, pero parece que cambiado algo significativo en Delphi 2009. Sólo tengo 2007 instalado aquí, y en el que, el código de Hallvard funciona bien.

¿El GetImplementingObject NIL cambio?

Si es así, si depura y establece un punto de interrupción en la sentencia case en la rutina GetImplementingObject, ¿a qué se aplica el valor de QueryInterfaceThunk.AddInstruction en el depurador?

+0

No devuelve nada, parece que devuelve una dirección de memoria incorrecta, porque puedo ver algunos datos del objeto, pero otros datos son solo un galimatías – Yona

+1

2009 introdujo un nuevo campo de puntero oculto (para soporte de monitor). Debe ajustar el método para dar cuenta de eso. – alex

+0

Gracias alex, pero ese método está más allá de mi experiencia en Delphi. ¿Puedes elaborar lo que debo ajustar? – Yona

3

En resumen: no se debe añadir o una interfaz con un método que devuelve el puntero para usted. Cualquier otra cosa es piratería.

Tenga en cuenta que una interfaz de "ejemplo" se puede implementar en otro idioma (que son compatibles COM) y/o puede ser un trozo de algo fuera de proceso, etc, etc

En definitiva: una instancia de interfaz única acepta la interfaz y nada más, ciertamente no se implementa como una instancia Delphi TObject

+0

Sé que es un truco y puede romper las cosas. Pregunté cómo no si debería. – Yona

-1
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; 
+0

Esto puede funcionar para algunos códigos generados por el compilador, pero no para otros. Siempre es mejor obtener la constante de $ 0C del código generado. –

15

tiene usted razón. A partir de Delphi 2010, puede utilizar el operador as, p. a través de aObject := aInterface as TObject o incluso aObject := TObject(aInterface).

Este operador as utilizan una interfaz GUID oculta especial (ObjCastGUID) para recuperar la instancia del objeto, llamando a una versión mejorada de TObject.GetInterface, que no existía antes de Delphi 2010. Ver código fuente de System.pas unidad para ver cómo funciona.

He publicado un código de trabajo para Delphi 6 hasta XE2, including Delphi 2009.

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

+0

Gracias por su solución Delphi6. Funciona !!! – geekobi

3

Hay una buena alternativa cuando se conoce el objeto de aplicación es un descendiente TComponent.

Puede utilizar la interfaz IInterfaceComponentReference, que se define en Classes unidad:

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

Y luego se ha declarado en TComponent (e implementado para volver self):

TComponent = class(TPersistent, IInterface, IInterfaceComponentReference) 

Así que si saber el objeto de implementación es un TComponent entonces usted puede hacer esto:

Cuestiones relacionadas