¿Alguna vez ha usado Adobe Photoshop? Para los laicos, los complementos son solo bloques de código proporcionados a la aplicación desde el exterior (por ejemplo, en una DLL). La diferencia entre un complemento y una DLL normal es que el complemento tiene la capacidad de extender la funcionalidad de la aplicación principal. Por ejemplo, Photoshop en sí no tiene una gran cantidad de funciones de procesamiento de imágenes. La adición de complementos le da un efecto increíble como Blur, Spot y todos los demás estilos, y ninguno de ellos tiene la aplicación principal.
Esto es muy bueno para los programas de procesamiento de imágenes, pero ¿por qué necesita gastar mucho esfuerzo para completar aplicaciones comerciales que admiten complementos? Supongamos, damos un ejemplo, su aplicación generará algunos informes. Sus clientes definitivamente seguirán solicitando actualizaciones o agregando nuevos informes. Puede usar un generador de informes externos como Report Smith, que es una solución no tan similar, requiere publicar archivos adicionales, capacitación adicional para usuarios, etc. También puede usar QuickReport, pero esto lo colocará en una pesadilla de control de versiones, si desea reconstruir su aplicación cada vez que cambie la fuente.
Sin embargo, siempre que realice el informe en el complemento, puede usarlo. ¿Necesita un nuevo informe? No hay problema, solo instale una DLL y la verá la próxima vez que comience la aplicación. Otro ejemplo es una aplicación que procesa datos de dispositivos externos (como escáneres de código de barras). Al escribir cada rutina de procesamiento de interfaz de dispositivo como un complemento, puede lograr la máxima escalabilidad sin hacer ningún cambio en la aplicación principal.
empezando
Lo más importante antes de comenzar a escribir código es descubrir qué características necesita extender su aplicación. Esto se debe a que el complemento interactúa con la aplicación principal a través de una interfaz específica, que se definirá de acuerdo con sus necesidades. En este artículo, construiremos 3 complementos para mostrar varias formas en que el complemento interactúa con la aplicación principal.
Haremos el complemento en una DLL. Sin embargo, antes de hacer esto, tenemos que hacer un caparazón para cargarlos y probarlos. La Figura 1 muestra el programa de prueba después de cargar el primer complemento. El primer complemento no logra nada grande, y de hecho, todo lo que hace es devolver una cadena que se describe a sí misma. Sin embargo, confirma un punto importante: funcionará correctamente con o sin aplicaciones complementarias. Si no hay complemento, no aparecerá en la lista de complementos instalados, pero la aplicación aún puede realizar funciones normalmente.
La única diferencia entre nuestro shell de complemento y las aplicaciones normales es la unidad Sharemem en el archivo de origen del proyecto que aparece en la cláusula de usos y el código que carga el archivo de complemento. ¿Se requiere alguna aplicación que pase los parámetros de cadena entre sí y la unidad de DLL infantil? Para probar este shell, debe copiar el archivo delphimm.dll desde el directorio Delphi/bin a la ruta contenida en la variable de entorno de ruta o el directorio donde se encuentra la aplicación. El archivo también debe distribuirse al mismo tiempo cuando se lanza la versión final.
El complemento se carga en este shell de prueba a través del proceso LoadPlugins, que se llama en el evento FormCreate en la ventana principal, ver Figura 2. Este proceso utiliza funciones FindFirst y FindNext para encontrar archivos de complemento en el directorio donde se encuentra la aplicación. Después de encontrar un archivo, use el proceso LoadPlugins que se muestra en la Figura 3 para cargarlo.
{Buscar archivos de complemento en el directorio de aplicaciones}
Procedimiento TFRMMain.LoadPlugins;
varilla
SR: TSearchRec;
ruta: cadena;
Encontrado: entero;
Comenzar
ruta: = ExtractFilePath (Application.exename);
intentar
Encontrado: = findFirst (ruta + cplugin_mask, 0, sr);
mientras que se encuentra = 0 haz comienza
LoadPlugin (SR);
Encontrado: = findNext (sr);
fin;
Finalmente
FindClose (SR);
fin;
fin;
{Cargue el complemento especificado DLL.
procedimiento tFRMMAIN.LOADPLUGIN (SR: TSearchRec);
varilla
Descripción: cadena;
Libhandle: entero;
DescribeProc: tpluginDescribe;
Comenzar
Libhandle: = LoadLibrary (PChar (Sr.name));
Si Libhandle $#@60; $#@62;
Comenzar
DescribeProc: = getProcAddress (libhandle, cplugin_describe);
Si se asigna (describe aProc) entonces
DescripciónProc (Descripción);
memplugins.lines.add (descripción);
fin
demás
Comenzar
Messagedlg ('file "' + sr.name + '" no es un complemento válido'.
mtInformation, [mbok], 0);
fin;
fin
demás
Messagedlg ('Se produjo un error cargando el complemento "' +
Sr.name + '".', Mterror, [mbok], 0);
fin;
El método LoadPlugin demuestra el núcleo del mecanismo de complemento. Primero, el complemento está escrito como DLL. En segundo lugar, se carga dinámicamente a través de la API LoadLibrary. Una vez que se carga la DLL, necesitamos una forma de acceder a los procedimientos y las funciones que contiene. Las llamadas de API getProcaddress proporcionan este mecanismo, que devuelve un puntero a la rutina requerida. En nuestra simple demostración, el complemento solo contiene un procedimiento llamado DescribePlugin, especificado por la constante Cplugin_Describe (el caso del nombre del procedimiento es muy importante, y el nombre pasado para GetProcaddress debe ser exactamente el mismo que el nombre de rutina incluido en el DLL) . Si no se encuentra ninguna rutina solicitada en el DLL, GetProcadDree devolverá nulo, por lo que aceptará usar la función asignada para determinar el valor de retorno.
Para almacenar punteros a una función de una manera fácil de usar, es necesario crear un tipo específico para las variables utilizadas. Tenga en cuenta que el valor de retorno de GetProcaddress se almacena en una variable, DescribeProc, pertenece al tipo TPlugIndescribe. Aquí está su declaración:
tipo
TpluginDescribe = procedimiento (var descarg: string);
Dado que el procedimiento existe dentro de la DLL, compila todas las rutinas de exportación a través de conversiones de llamadas estándar, por lo que se requiere el indicador STDCall. Este proceso utiliza un parámetro VAR, que contiene la descripción del complemento cuando el proceso regresa.
Para llamar al proceso que acaba de obtener, solo use la variable que guarde la dirección como nombre del proceso, seguido de cualquier parámetro. En nuestro caso, la declaración:
DescripciónProc (Descripción)
Se llamará al proceso de descripción obtenido en el complemento y la variable de descripción se pobla con una cadena que describe la funcionalidad del complemento.
Enchufe de construcción
Hemos creado la aplicación principal, y es hora de crear el complemento que queremos cargar. El archivo de complemento es una DLL Delphi estándar, por lo que creamos un nuevo proyecto DLL desde el IDE Delphi y lo guardamos. Dado que la función de complemento exportado utilizará los parámetros de cadena, la unidad Sharemen debe colocarse primero en la cláusula de uso del proyecto. La Figura 4 enumera el archivo fuente del proyecto de nuestro simple complemento.
usos
Sharemem, Sysutils, clases,
principal en 'main.pas';
{$ E plg.}
exportaciones
DescribePlugin;
Comenzar
fin.
Aunque el complemento es un archivo DLL, no hay necesidad de darle una extensión .dll. De hecho, una razón es suficiente para darnos una razón para cambiar la extensión: cuando la aplicación principal busca que se cargue el archivo, la nueva extensión puede servir como una máscara de archivo específica. Al usar otra extensión (nuestro ejemplo usa *.plg), puede estar seguro de que la aplicación solo cargará los archivos correspondientes. El indicador de compilación $ X puede lograr este cambio, o puede establecer la extensión a través de la página de aplicación del cuadro de diálogo Opciones de proyecto.
El código para el primer complemento de ejemplo es muy simple. La Figura 5 muestra el código contenido en una nueva unidad. Tenga en cuenta que el prototipo DescribePlugin es consistente con el tipo TPLUGIndescribe en la aplicación Shell, y utiliza la palabra reservada de exportación adicional para especificar que el proceso se exportará. El nombre del proceso exportado también aparecerá en la sección de exportaciones del código fuente principal del proyecto (enumerado en la Figura 4).
unidad principal;
interfaz
procedimiento describePlugin (var desc: string);
exportación;
Implementación
procedimiento describePlugin (var desc: string);
Comenzar
Desc: = 'Test Plugin v1.00';
fin;
fin.
Antes de probar este complemento, cópielo a la ruta de la aplicación principal. La forma más fácil es crear un complemento en el subdirectorio del directorio de inicio, y luego establecer la ruta de salida en la ruta principal (los directorios/condicionales del cuadro de diálogo Opciones de proyecto también se pueden usar para esta configuración).
depurar
Ahora permítanme presentar una característica mejor en Delphi 3: La capacidad de depurar DLL del IDE. En un proyecto DLL, puede especificar un programa como la aplicación de host a través del cuadro de diálogo Ejecutar Paramates. Luego puede establecer puntos de interrupción en su código DLL y presionar F9 para ejecutarlo, al igual que lo haría en una aplicación normal. Delphi ejecutará el programa host especificado y, compilando la DLL con información de depuración, lo dirigirá al punto de interrupción en el código DLL.