Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Comunicacion entre BPL (https://www.clubdelphi.com/foros/showthread.php?t=72309)

adonias 09-02-2011 22:20:17

Comunicacion entre BPL
 
Una pregunta Basica.

Estoy experimentando con los archivos BPL, cargandolos con LoadPackage.

Mi pregunta es si puede haber comunicacion entre el MainForm y el BplForm.

Ejemplo:

MainForm carga al BplForm, y luego el BplForm llama una funcion del MainForm.

MainForm carga al BplForm, y el MainForm modifica elementos del BplForm (Labels, Input, etc)

Gracias

droguerman 09-02-2011 23:11:39

Creo que sólo tienes dos opciones o crear herencia de formularios de manera de que la clase del formulario sea común tanto a la aplicación como al bpl (no sé me ocurre claramente como) o que crees una función en tu bpl que tenga como parámetro un TForm y manejar los controles mediante FindComponent

ContraVeneno 10-02-2011 01:20:56

Puedes crear un BPL intermedio, para que te sirva de comunicación entre tu formulario principal y tu BPL cargado con LoadPackages, es decir, cargado de forma dinámica.

El punto clave es que tu BPL intermedio, deberá ser cargado de manera estática en tu formulario principal y en tu BPL lo debes de cargar utilizando el archivo DCP que se genera, igual de forma estática.

Con esto puedes tener acceso a este BPL desde tu formulario principal y hacerle cambios a las variables o a los objetos que contenga, estos cambios se verán reflejados desde tu BPL dinámico. De igual forma, si haces cambios al BPL intermedio desde tu BPL dinámico, estos cambios los podrás ver desde tu formulario principal.

Yo por ejemplo, estoy utilizando un DataModule en mi BPL intermedio...

MiPrograma.exe <----> DataModule.bpl <------> UnModulo.bpl

Neftali [Germán.Estévez] 10-02-2011 11:32:29

Si quieres ejemplos de lo que te han dicho en mi web hay varios ejemplos y código sobre el tema:

Acceder a las propiedades de un componente vía RTTI
Modificar propiedades de controles en ejecución utilizando RTTI

DLL’s, BPL’s, Carga dinámica/Estática y “Packages en Runtime”

Sistema de PlugIns en Delphi – Parte 1
Sistema de PlugIns en Delphi – Parte 2

Sistema de Plug-ins utilizando packages dinámicos

adonias 10-02-2011 13:58:42

Gracias Neftali.

Con esto pude solucionar el ejemplo 2

MainForm carga al BplForm, y el MainForm modifica elementos del BplForm (Labels, Input, etc)

Código Delphi [-]

procedure TFrm.FormCreate(Sender: TObject);
var
  PackageModule: HModule;
  AClass: TPersistentClass;
  componentLabel: TComponent ;
begin
  PackageModule := LoadPackage('Package1.bpl');
  if PackageModule <> 0 then
  begin
    AClass := GetClass('TForm2');

    if AClass <> nil then
      with TComponentClass(AClass).Create(Application)
        as TCustomForm do
      begin
        Show;

        // Buscar el Label
        componentLabel := FindComponent('label1');
        // lo ha encontrado?
        if Assigned(componentLabel) then begin
          TLabel(componentLabel).Caption := 'hola';
          MessageDlg('¿Ves el cambio?  Pulsa para continuar y cerrar...', mtConfirmation, [mbOK], 0);
          TLabel(componentLabel).Caption := 'Adiós';
          MessageDlg('Lo he vuelto a cambia......', mtConfirmation, [mbOK], 0);
          //Free;
        end;
      end;
  end;


end;

Ahora, me interesa lo que dice ContraVeneno.

¿ContraVeneno tienes algun ejemplo?

¿Tu dices que en vez que cargue el archivo Package1.dcp en vez del Package1.bpl?

Neftali [Germán.Estévez] 10-02-2011 16:12:48

Cita:

Empezado por adonias (Mensaje 390559)
Ahora, me interesa lo que dice ContraVeneno.
¿ContraVeneno tienes algun ejemplo?
¿Tu dices que en vez que cargue el archivo Package1.dcp en vez del Package1.bpl?

Pues en uno de los ejemplos que te he pasado, si no me equivoco tienes justamente ese ejemplo (aunque ampliado).



Tu PlugIn Base corresponde al package PlugBasic.bpl, que hace de "package intermedio"; Se carga de forma estática y el resto de packages que se cargan con LoadPackage (dinámicamente) derivan de el.

De esta forma cuando cargas el Plugin3 (que deriva de plugBasic) puedes acceder a él con los métodos genericos de PLugBase.

ContraVeneno 10-02-2011 18:23:34

Es exactamente lo que comenta maese Neftalí... yo no podría explicarlo mejor. :D:D

adonias 10-02-2011 23:46:55

Muchas gracias a los 2.

Lo he logrado utilizar el PlugBase

Ahora, el problema que tengo es capturar el evento onClose, y onHide

Este es el codigo

Código Delphi [-]

unit Principal;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, ShellApi,
Graphics, Controls, Forms, Dialogs, StdCtrls;

Type
TEvnPro = class(TForm)
    procedure FormHide(Sender : TObject; var Action : TCloseAction);
end;

var
  EvnPro : TEvnPro;
  AClass: TPersistentClass;
  handle: HModule;
  Titulo, Version: TComponent ;
  FBase : Tform;
  Ver : Boolean;


implementation
{$R *.DFM}

Function VersionProg(*****):Boolean;stdcall;external 'lib/Version.dll';

Procedure TEvnPro.FormHide(Sender : TObject; var Action : TCloseAction);
begin
    showMessage('Te Pille');
end;

initialization

    {* verifico la version del programa *}
     Ver := VersionProg(***);

    if Ver then begin

      {* verifico que el modulo existe, junto con el archivo *}
      if FileExists('bin/PlugBase.bpl') then
      begin
          {* Cargo el modulo a memoria *}
          handle := LoadPackage('bin/PlugBase.bpl');

          {* si es un modulo válido *}
          if handle <> 0 then
            begin

            AClass := GetClass('TBase');
            if AClass <> nil then
            begin

              FBase := nil;
              FBase := TComponentClass(AClass).Create(Application) as TForm;
              FBase.Tag := handle;

              FBase.ShowModal;

              FBase.OnHide := TEvnPro.FormHide;    <-- No puedo Capturar el Evento (E2009 Incompatible types: 'Parameter lists differ')

            end;
          end;
      end;

    end
    else begin

      showmessage( 'Versión Incorrecta!' );

    end;


end.

Muchas gracias nuevamente por la ayuda

Neftali [Germán.Estévez] 11-02-2011 10:28:07

1 Archivos Adjunto(s)
Se puede hacer lo que quieres, pero tal y como lo tienes hecho hay algunos problemas:

(1) Los parámetros del evento OnHide, no coinciden con los de la rutina que estás colocando; Creo que te has hecho un lío con el OnClose.

Código Delphi [-]
    procedure myFormHide(Sender : TObject);

(2) Esta línea también tiene "cosas raras":
Código Delphi [-]
FBase.OnHide := TEvnPro.myFormHide;
Piensa que estás asignando el evento FormHide, no de ningun objeto, sino que pones directamente la referencia a una clase (TEnvPro....), además de lo comentado de que nocoinciden los parámetros.

(3) Si colocas el evento en el Initialization tendrás que acer referencia al evento como:

Código Delphi [-]
FBase.OnHide := EvnPro.myFormHide;

Te paso un ejemplo con algunos cambios.


adonias 14-02-2011 01:41:46

Muchas gracias Neftali...

La verdad es que estoy medio confundido.

He estado programando bastanbte tiempo en Extjs y PHP, y uno se acostumbra a clases y a programar de una manera mas flexible.

Siempre cuando empiezo un proyecto me gusta trabajar por modulos, ya que es mas facil detectar los problemas.

Ahora, este es el esquema de lo que estoy haciendo.



No se si sera el correcto desde tu punto de vista.

1.- El programa parte con la carga del unit Main.pas

2.- Luego que verifico que la version este ok, cargo el BPL Base, como tu lo recomendaste.

3.- El BPL Base tiene unas variables para verificar si estoy logueado o no. Si NO estoy logueado, llamo al Bpl login.

Una vez que el BPL login me responde true o false.

Retorno, la respuesta al Main, y comienzo a cargar los otros BPL a travez del BPL Base.

Neftali [Germán.Estévez] 14-02-2011 10:24:26

Hola Adonias.
Es tema que planteas es difícil.
Los packages no son la "panacea" y no creo que la solución sea utilizar packages para todo. Como ya has visto, trabajar con packages no es sencillo y además conlleva una complicaión adicional a la hora de programar.

Lo primero que hay que diferenciar a la hora de trabajar con packages es si estamos hablando de carga estática o dinámica.

(1) Carga estática.
Trabajar con carga estática, creo que es más una decisión de diseño. En este caso la complicación no es tanta y podemos programar de una forma "más normal". Seguramente la división por packages en este caso, está más enfocada a aplicaciones grandes o muy grandes, que requieren una organización conceptual en bloques o por temas de dicisión conceptual.

(2) Carga dinámica.
En este caso ya es un cambio radical y no debemos tomarlo a la ligera. La carga dinámica de packages tienes ventajas y algunas de las características que consigues utilizándola, no podrías obtenerlas de otra manera; Características como el trabajo con de Plugins o Addins, modilaridad total, independencia,... El problema es que el "precio a pagar" también es alto, pues debes trabajar utilizando RTTI; Esto no es lo más sencillo ni lo más óptimo (como ya se ha comentado aquí).

Lo que quiero decir con esto, es que es una decisión importante y no se debe tomar a la ligera. Se debe tener en cuenta que los packages "no son la mejor opción siempre", hay que pensar si para lo que vamos a realizar nos viene bien utilizar esta opción, o si para las necesidades que tiene nuestro proyecto nos va bien utilizar packages.

roman 14-02-2011 15:57:51

Cita:

Empezado por Neftali (Mensaje 390839)
El problema es que el "precio a pagar" también es alto, pues debes trabajar utilizando RTTI; Esto no es lo más sencillo ni lo más óptimo (como ya se ha comentado aquí).

Pero es que esto no es así, como ya lo han visto antes. Es más, yo diría que, por lo general, debería evitarse el uso de RTTI.

// Saludos

Neftali [Germán.Estévez] 14-02-2011 16:21:43

Cita:

Empezado por roman (Mensaje 390879)
Pero es que esto no es así, como ya lo han visto antes. Es más, yo diría que, por lo general, debería evitarse el uso de RTTI.

Pues eso es lo que intentaba decir yo, pero veo que no se me ha entendido.:(:(

Quería decir que si trabajas con packages dinámicos, deberás utilizar RTTI. Y que como esto (trabajar con RTTI) no es óptimo, sólo se debe trabajar con packages dinámicos cuando realmente lo necesites.

roman 14-02-2011 16:36:56

No, no. Es que lo que yo digo es que trabajar con paquetes dinámicos no hace obligatorio el uso de RTTI. Y tú mismo has dado ejemplos de que no es así.

Lo único que se requiere es estructurar bien los paquetes de manera que haya un lenguaje común entre la aplicación principal y los paquetes. Dicho lenguaje puede establecerse mediante clases abstractas o bien interfaces.

// Saludos

Neftali [Germán.Estévez] 14-02-2011 16:48:51

Cita:

Empezado por roman (Mensaje 390887)
Lo único que se requiere es estructurar bien los paquetes de manera que haya un lenguaje común entre la aplicación principal y los paquetes. Dicho lenguaje puede establecerse mediante clases abstractas o bien interfaces.

Vale, pero aun así el trabajo de esta forma se complica respecto a utilizar un simple USES en una Unit.
Si bien se puede trabajar sin RTTI con carga dinámica de packages, creo que para hacer cosas potentes o para conseguir una buena integración con la aplicación principal tienes antes o después echar mano de ella.
NOTA: No he trabajado con la opción de los Interfaces.

roman 14-02-2011 16:58:11

Cita:

Empezado por Neftali (Mensaje 390892)
Vale, pero aun así el trabajo de esta forma se complica respecto a utilizar un simple USES en una Unit.

No entendí esta parte. ¿Cuál sería la complicación de usar el USES?

// Saludos

Neftali [Germán.Estévez] 14-02-2011 17:19:56

Cita:

Empezado por roman (Mensaje 390895)
No entendí esta parte. ¿Cuál sería la complicación de usar el USES?

Perdona Román, pero es que como llevamos 2 hilos paralelos sobre los mismo y al final me he liado entre uno y el otro.

Comunicación entre BPL (este)
Componentes en librerías DLL (el otro)

En el otro hilo ya hemos explicado que si utilizamos packages (BPL's) con carga dinámica (LoadPackages) no podemos hacer referencia a los elementos que haya contenidos en el Package, utilizando la unit en el USES, porque eso implicaría la referencia estática a ese package.

A esa restricción me refiero cuando digo que no podemos incluir las units en el USES, como cuando trabajamos "normalmente" (sin carga dinámica de packages) y que el trabajo se hace más complejo cuando estamos trabajando de esta forma.

roman 14-02-2011 17:29:52

Sí, sí. También estoy al tanto del otroh hilo :).

Pero, me parece que tú mismo has dado el ejemplo de como hacer eso:

1. Defines la estructura de un plugin. Ésta puede ser una clase abstracta o una interfaz.

2. La unidad que define la estructura del plugin se carga estáticamente, tanto por la aplicación principal como por los plugins. Es decir, mediante la inclusión en USES de dicha unidad.

3. Los pluginslos cargas dinámicamente. Pero como serán clases derivadas de una clase abstracta (o implementarán una interfaz) que sí conocen, entonces no necesitan hacer uso de RTTI.

Edito:

De hecho, ¿que no es lo que expones en el mensaje #6? El paquete base hace de intermediario e interfaz común entre la aplicación principal y los paquetes, de manera que evitas el uso de RTTI.

// Saludos

Neftali [Germán.Estévez] 14-02-2011 17:44:59

Cita:

Empezado por roman (Mensaje 390899)
1. Defines la estructura de un plugin. Ésta puede ser una clase abstracta o una interfaz.

2. La unidad que define la estructura del plugin se carga estáticamente, tanto por la aplicación principal como por los plugins. Es decir, mediante la inclusión en USES de dicha unidad.

Correcto. Puedes incluir en el USES sólo la unit del plugIn Base, pero no las
de los plugins (plugin2, plugin3,...). A esas me refería.

Cita:

Empezado por roman (Mensaje 390899)
3. Los pluginslos cargas dinámicamente. Pero como serán clases derivadas de una clase abstracta (o implementarán una interfaz) que sí conocen, entonces no necesitan hacer uso de RTTI.

De hecho, ¿que no es lo que expones en el mensaje #6? El paquete base hace de intermediario e interfaz común entre la aplicación principal y los paquetes, de manera que evitas el uso de RTTI.

No para temas básicos; Con esta estructura puedes cargarlos y acceder a la clase del plugin sin RTTI, a través del PluginBase; Lo que ya no puedo asegurar es que si posteriormente, no la vayas a utilizar para otras cosas (si complicas la estructura de esos plugins -sus clases-).
Pero sí es cierto, que al menos para lo que muestra ese ejemplo básico, no la necesitarías.

roman 14-02-2011 17:59:58

Cita:

Empezado por Neftali (Mensaje 390901)
Lo que ya no puedo asegurar es que si posteriormente, no la vayas a utilizar para otras cosas (si complicas la estructura de esos plugins -sus clases-).

Lo mismo podría decirse de una jerarquía cualquiera de clases. Una clase es un compromiso ante los clientes (los usuarios de la clase) de que su interfaz no va a cambiar. Y aún así, da para cosas muy complejas.

Aunque un sistema de plugins puede no dar el ancho para todo, pienso que sí puede resolver muchos problemas de modularidad, más allá de sólo aplicaciones básicas. Y me refiero a hacerlo sin usar RTTI. Por otra parte, no hay porque restringirse a una sola jerarquía de plugins. Dependiendo de la aplicación, si ésta es muy compleja, puede trabajarse con distintas categorías; por ejemplo, una para acceso a base de datos, otra para improtación/expórtación de datos, etc.

// Saludos


La franja horaria es GMT +2. Ahora son las 14:09:55.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi