Me parece que las tres respuestas hasta ahora han perdido por completo el sentido de su pregunta. Eso, o yo tengo. ¿Estás preguntando por qué Win32 Delphi no tiene algo así como la función mágica Supports
de la que habla el artículo de Hallvard, verdad? A saber, una función que, dado el nombre de una DLL y la información de tipo de una interfaz, devuelve un objeto que implementa esa interfaz utilizando las funciones independientes exportadas desde la DLL.
Hydra parece ser todo sobre llamar al código .Net de un programa Win32, no sobre la importación de funciones desde una DLL. TJvPluginManager
requiere que los archivos DLL del complemento exporten una función especial de autorregistro que el administrador llamará cuando cargue el archivo DLL, y la función debe devolver una instancia de la clase TJvPlugin
, por lo que el archivo DLL debe escribirse en Delphi o C++ Builder. La función Supports
, por otro lado, funciona con cualquier archivo DLL escrito en cualquier idioma. Puede usarlo en kernel32, si lo desea.
No sé por qué Win32 Delphi no tiene una cosa así. Tal vez CodeGear no veía mucha demanda porque Delphi y Turbo Pascal ya habían pasado tanto tiempo sin él.
Es ciertamente posible escribir una función que funcione así, y no espero que sea más difícil de escribir que la versión .Net, a menos que las bibliotecas .Net de Microsoft ya proporcionen la mayoría de las piezas y Delphi simplemente los envuelve en una función conveniente para llamar que se parece a las otras varias versiones sobrecargadas de Supports
que Delphi ha tenido durante años.
Habría unos pocos pasos para implementar esa función en Win32. (Proporciono solo un boceto de lo que es necesario porque no tengo una copia actualizada de Delphi en este momento. Pregunte amablemente, y tal vez encuentre más detalles.) Primero, necesitaría asegurarse de que ese tipo la información para una interfaz contiene, como mínimo, los nombres no decorados de sus métodos. Entonces, Supports
necesitaría generar un stub de función para cada método en la interfaz (además de _AddRef, _Release y QueryInterface). El talón sería algo como esto, asumiendo la convención de llamada es stdcall
:
asm
// Pop the return address,
// discard the "this" pointer,
// and restore the return address
pop eax
pop ecx
push eax
jmp AddressOfFunction
end;
Como Supports
generan cada trozo, sería rellenar la dirección de función real, obtenido de llamar GetProcAddress
con el nombre del método de interfaz correspondiente. La convención de llamadas stdcall
es fácil de envolver así; cdecl
es un poco engorroso; register
es un dolor en el cuello.
Una vez que tenga todos los stubs generados, necesitaría generar un "objeto" que parece que implementa la interfaz dada. No tiene que ser una clase real. En tiempo de compilación, Supports
no conoce el diseño de la interfaz que se le pedirá que implemente, por lo que tener una clase no lograría mucho.
El paso final es proporcionar implementaciones de _AddRef
, _Release
y QueryInterface
. _AddRef
no sería notable; _Release
es donde llamarías al FreeLibrary
cuando el recuento de referencia llegó a cero; QueryInterface
no haría mucho en absoluto, excepto afirmar que admite IUnknown
y la interfaz dada a Supports
.
Delphi solía venir con un programa de ejemplo que demostraba la implementación de una interfaz sin ninguna clase en absoluto. Todo se hizo con registros y punteros a las funciones (que finalmente es una interfaz, después de todo). Delphi también vino con el código correspondiente para hacerlo con clases, en parte para mostrar cuánto más fácil puede hacer Delphi. No puedo encontrar el nombre del programa de demostración ahora, pero estoy seguro de que todavía está por aquí.
Me dirigí a eso brevemente en mi respuesta. Este es el material "feo de mierda con punteros" en el que no quería entrar. Ah, y como un bono adicional, también implica feo en el ensamblaje. ¡Me olvidé de esa parte! : P –
En realidad, no montaje. Codigo de maquina. El conjunto que escribí arriba es solo para fines ilustrativos. Tendrías que ingresar el código de la máquina directamente porque estarías generando código en tiempo de ejecución, y no hay un ensamblador en tiempo de ejecución disponible. –
+1, respuesta considerada y con una buena explicación de los detalles técnicos. Gracias por tomarse el tiempo de escribirlo. – mghie