Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Acceso a BPLs (https://www.clubdelphi.com/foros/showthread.php?t=38312)

ezindetgeio 11-12-2006 12:53:50

Acceso a BPLs
 
Hola a tod@s:

Soy nuevo aquí.

Seguramente este tema ya es recurrente y con un link me contestéis.

Tengo la típica aplicación que está disgregada en .bpl-s.

Hasta ahí bien.

Ahora bien, en distribución de la aplicación me llevo los .bpl y los .exe sólo.

Ahora, en esta distribución, quiero desarrollar otra aplicación basándome en los .bpl con el código típico de:

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
var
  Paquete: HModule;
  clase: TPersistentClass;

begin

  paquete := LoadPackage('C:\Archivos de programa\Simbad\paquete.bpl');
if Paquete <> 0 then
  begin
    clase := GetClass('TClase');
    if clase <> nil thenShowMessage('Bien')    elseShowMessage('TClase no está')    UnloadPackage(Paquete);
  end;

end.

Pero, se ve que cuando intento cargarlos así no están registradas las clases (ni nada) en el paquete. El paquete se carga, pero siempre me da que la clase no está...

El caso es que en el proyecto principal yo no digo nada especial para que esto funcione, que yo sepa.

Pero ahora mi idea es decirle desde código que cargue los paquetes. No sé si me explico.

¿Hay alguna manera de que se registren estas clases fuera del paquete y las pueda cargar?

¿Hay alguna manera mejor de hacer esto?

¿Hay alguna manera decente de ver todas las clases que contiene un paquete y sus métodos y sus firmas sin tener que volver a meterte en todo el código de los .dcus y todo?

La verdad que no lo entiendo ya que con una DLL no me pasa lo mismo.

¿Algún tutorial o manera adicional?

Este caso concreto está en Delphi 5.0, aunque también me pasa lo mismo con Delphi 7.0.

¡Muchas gracias!

Saludos.

Neftali [Germán.Estévez] 11-12-2006 14:43:20

¿Ya registras las clases que quieres utilizar?
Prueba a utilizar el procedimiento RegisterClass en la initialization del package, y el UnRegisterClass en la finalization del package.

Revisa este sencillo ejemplo, a ver si te aclara algo.

ezindetgeio 11-12-2006 16:17:22

Gracias Neftali.

El problema es en el caso de que los BPLs no sean míos y donde sospecho como bien observas que no están registradas las clases.

¿Hay alguna solución a esto?

¿O no queda más que ir a por el código y meterle el RegisterClass y el UnRegister... en initialization y finalization?

Dicho esto, ¿cuál es la mejor manera aún y todo de poder "explorar" la API de clases y métodos y firmas de las mismas que te provee un BPL?

Desde fuera digo.

Por ejemplo supongamos que yo no trabajo en Delphi y que al otro lado lo que quiero es invocar desde Java con JNI código Delphi. Mucho me temo que me lo tendré que encapsular en una DLL...

Gracias de nuevo.

ezindetgeio 11-12-2006 16:49:40

De hecho, a veces tampoco me va ni así.

Mejor dicho, YA no me va.

Adjunto un ejemplo tontísimo.

Unidad que luego empaqueto (como Run-Time):

Código Delphi [-]
unit UClasePrueba;

interface

uses

        Windows, Classes;

type
   TClasePrueba = Class (TPersistent)

     private
       sNombre         : String;
       sEdad    : Integer;

     published

       constructor Create(nombre: String; edad: Integer);
       function GetNombre : String;
       function GetEdad : Integer;
       procedure SetNombre(const nombre: String);
       procedure SetEdad(const edad: Integer);

   end;

var
   ClaseAitor : TClasePrueba;

implementation

 constructor TClasePrueba.Create(nombre: String; edad: Integer);
 begin
   sNombre         := nombre;
   sEdad := edad;
 end;

 procedure TClasePrueba.SetNombre(const nombre: String);
 begin
   sNombre         := nombre;
 end;

 procedure TClasePrueba.SetEdad(const edad: Integer);
 begin
   sEdad         := edad;
 end;

 function TClasePrueba.GetNombre() : String;
 begin
   result:= sNombre;
 end;

 function TClasePrueba.GetEdad() : Integer;
 begin
   result:= sEdad;
 end;

 initialization

        RegisterClass(TClasePrueba);

 finalization

        UnRegisterClass(TClasePrueba);
end.

Formulario que cargaría el .bpl y lo llamaría:

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);

var

Paquete: HModule;
clase: TPersistentClass;

begin

Paquete := LoadPackage('C:\Documents and Settings\aillarra\Desktop\Package2.bpl');

if Paquete <> 0 then


  begin


    clase := GetClass('TClasePrueba');


    if clase <> nil then
       ShowMessage('Bien')
    else
     ShowMessage('La clase no está');
 
    UnloadPackage(Paquete);


  end;


end;

end.
Me dice que no encuentra esa clase.

Así que estoy en las mismas.

El hecho de que haga un .exe que en los use tenga los accesos a esos .bpl que como trabajo en local tienen los .dcu y demás y sabe de qué van se me escapa a la hora de distribuir y llevarme sólo el .exe y sus bpl.

¿Cómo sabe ese .exe nada de esos .bpl si no están registrados en ninguna parte?

:eek:

Albano 11-12-2006 17:12:10

Hola ezindetgeio! Bienvenido al club! ;)
Te voy a dar un consejo para la redacción de los mensajes:
Cuando escribas código usa la etiqueta para código de delphi y tu código se verá de la siguiente manera:
Código Delphi [-]
procedure TClasePrueba.SetNombre(const nombre: String);
 begin
   sNombre         := nombre;
 end;
Ésto hace que sea mas facil de leer e identificar.
Para hacerlo solo haz lo siguiente:
  1. Selecciona el código que escribiste en tu mensaje.
  2. Presiona el botón que tiene el logo que relacionamos con delphi (3 pilares y un techo color café), si posicionas el mouse sobre él, va a aparecer su "hint", que dice "Resaltar sintaxis delphi".

Neftali [Germán.Estévez] 11-12-2006 17:16:08

Apoyo lo dicho por Albano.

Sobre el problema en cuestión, haz una prueba.
En el proyecto donde cargas el package (Form1), marca en las opciones del proywcto "Build with runtime packege" y prueba de nuevo. ;)

ezindetgeio 11-12-2006 17:35:00

Hola:

Corregido lo del código. Perdón, no estoy muy habituado a foros.

He probado lo que me dice Neftali (aunque en principio va un poco con la filosofía de lo que quiero hacer puesto que se supone que es desde código donde le digo que cargue el paquete).

Aún así, marcando el checkbox y añadiendo el .bpl a pelo, no me funciona. :(

Muchas gracias por la ayuda que me prestáis.

Neftali [Germán.Estévez] 11-12-2006 17:48:38

Cita:

Empezado por ezindetgeio
Aún así, marcando el checkbox y añadiendo el .bpl a pelo, no me funciona.

No lo entiendo; A mi me funciona perfectamente.
Me carga la clase sin problemas. El comentario era, porque para utilizar los packages dinámicos y las clases (GetClass) mediante RTTI, el programa desde el que haces la carga debe estar compilado con Runtime Packages; Vamos que no puedes mezclar un programa que compila "sin package en runtime" con la "carga dinámica de packages en runtime + Getclass".

ezindetgeio 11-12-2006 17:54:35

Pues nada Neftali.

Algo mal debo estar haciendo o bien al crear el BPL o bien luego.

Pruebo ahora.

Aún y todo, sigo sin comprender muy bien cómo va lo que comentas de la opción de lo de runtime en el proyecto que invoca al otro bpl.

Pero esto es debido a mi desconocimiento en Delphi. Que es cero patatero.

Sabiendo ya que funciona lo pruebo y te aviso.

¿Quizás esté creando mal el BPL?

Saludos y gracias.

ezindetgeio 11-12-2006 18:13:13

Soy un inútil.

Ya funciona.

Aunque sigo sin entender cómo sabe por debajo el exe que genero todo lo relativo a la bpl, cuando me puedo llevar de ahí los .dcu y demás.

¿Cómo podría hacer para averiguar las clases y métodos que tiene un .bpl sin eso?

No entiendo muy bien lo que se hace por dentro.

Muchas gracias Neftali ;)

Neftali [Germán.Estévez] 11-12-2006 18:37:46

Cita:

Empezado por ezindetgeio
Aunque sigo sin entender cómo sabe por debajo el exe que genero todo lo relativo a la bpl, cuando me puedo llevar de ahí los .dcu y demás.

Intento explicarlo de forma simple...
El package (BPL - Borland Package Library-) contiene dentro los DCU's. Es decir, cuando creas un package con un monton de Units/Forms, la BPL resultante es equivalente (por decirlo así) a juntar todos los DCU's de esas Units/Forms y meterlos dentro.
Además Borland guarda información complementaria (RTTI) que permite acceder en ejecución a métodos/clases...
Esta información es la que se usa cuando accedes utilizando GetClass.

Échale un vistazo a este artículo de Vino Rodrigues; Es muy aclaratorio.

ezindetgeio 11-12-2006 20:07:25

Muchas gracias Neftali
 
¡Muchas gracias! ;)

Ahora me lo leo.

Ahora el misterio es averiguar cómo hago el "casting" a esa clase y cómo uso sus métodos públicos y demás.

En ello estoy :D

ezindetgeio 12-12-2006 00:10:50

Una cosa más
 
Teniendo ya esto...

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);

var

Paquete: HModule;
clase: TPersistentClass;
claseFinal : TObject;

begin

Paquete := LoadPackage('C:\Documents and Settings\aillarra\Desktop\Package2.bpl');

if Paquete <> 0 then


  begin


    clase := GetClass('TClasePrueba');


    if clase <> nil then
       ShowMessage('Bien')
    else
     ShowMessage('La clase no está');
 
    UnloadPackage(Paquete);


  end;


end;

¿cómo hago para acceder a los métodos de la clase?

un WITH claseFinal AS clase

¿Donde claseFinal es TObject y clase es TClasePrueba?

¿Cómo inicializo la clase?

Estoy algo liado con esto ya que sólo veo ejemplos con Forms... :confused:

Gracias.

ezindetgeio 12-12-2006 10:26:10

No sé si he explicado bien mi duda.

Quizás es que sigo sin entender bien para qué valen los famosos BPLs.

En los ejemplos que siempre leo un BPL siempre lleva consigo especializaciones de objetos típicos como Forms o así.

Pero... cuando la clase o clases que van en el BPL son mías y son de lógica de negocio como la que explico arriba...

Una vez cargado el BPL en ejecución, ¿cómo hago para crear una instancia de esa clase y que el compilador me reconozca que es de ese tipo y que sepa de los símbolos de la misma (sus métodos, etc.)?

No encuentro manera.

En cambio, si hago uno uses UClasePrueba y añado el .bpl como componente a lo bestia en la opción del proyecto, ya sí que me lo ve.

La cuestión es, ¿cómo hacer esto programáticamente en el código?

¿No es igual hacer un LoadPackage de un paquete que registra sus clases a poner la opción del .bpl en el proyecto y poner el uses?

¿Qué más me falta?

Leo libros sobre Deplhi y tutoriales y sólo veo que siempre que se usa LoadPackage es para recoger una clase que especializa a una que ya se tiene en la aplicación (un formulario específico por ejemplo) y que por lo tanto, con hacer una instancia sobre un tipo base que conozco y al cuál hace override a sus métodos le vale.

¿Es ese el alcance del uso de los .bpl?

No puede ser así puesto que evidentemente hemos quedado que el .exe se lleva sólo el .bpl y se lleva toda la compilación y linkado de símbolos y demás del paquete.

¿Dónde puedo leer más sobre RTTI?

ezindetgeio 12-12-2006 11:26:18

Más del mismo pesado... :D

Si sigo algunas indicaciones de RTTI hay una manera que sí em funciona, pero, ¿es la única?

Si hago que la clase sea así:

Código Delphi [-]
unit  UClasePrueba;
 
 interface
 
 uses
     Windows, Messages,  SysUtils, Classes;
 
 type
     TClasePrueba =  class(TPersistent)
          private
             sNombre:  String;
             sEdad:  Integer;
             //procedure  CreatePrueba(nombre: String; edad: Integer);
             function  GetNombre : String;
             procedure  SetNombre(const nombre: String);
             function GetEdad  : Integer;
             procedure  SetEdad(const edad: Integer);
          public
 
          published
             property Nombre:  String read GetNombre write SetNombre;
             property Edad:  Integer read GetEdad write SetEdad;
      end;
 
 implementation
 
 {procedure  TClasePrueba.CreatePrueba(nombre: String; edad:  Integer);
 begin
     sNombre :=  nombre;
     sEdad :=  edad;
 end;  }
 
 procedure  TClasePrueba.SetNombre(const nombre: String);
 begin
     sNombre :=  nombre;
 end;
 
 procedure  TClasePrueba.SetEdad(const edad: Integer);
 begin
     sEdad :=  edad;
 end;
 
 function  TClasePrueba.GetNombre() : String;
 begin
     result :=  sNombre;
 end;
 
 function  TClasePrueba.GetEdad() : Integer;
 begin
     result :=  sEdad;
 end;
 
 initialization
 
      RegisterClass(TClasePrueba);
 
 finalization
 
      UnRegisterClass(TClasePrueba);
 
 end.

Y lo llamo como:

Código Delphi [-]
unit  Paquetes;
 
 interface
 
 uses
   Windows, Messages, SysUtils,  Classes, Graphics, Controls, Forms, Dialogs,
   StdCtrls,  TypInfo;
 
 type
   TForm1 =  class(TForm)
     Button1:  TButton;
     procedure Button1Click(Sender:  TObject);
    private
     { Private declarations  }
    public
     { Public declarations  }
   end;
 
 var
   Form1:  TForm1;
 
 implementation
 
 {$R  *.DFM}
 
 procedure  TForm1.Button1Click(Sender: TObject);
 var
     Paquete:  HModule;
     PruebaClass:  TPersistentClass;
     Prueba:  TPersistent;
     nombre:  String;
 begin
     Paquete :=  LoadPackage('PaquetePrueba.bpl');
 
     if (Paquete <> 0)  then
      begin
         Showmessage('Paquete  Cargado');
 
         PruebaClass :=  TPersistentClass(GetClass('TClasePrueba'));
 
         if (Assigned (PruebaClass))  then
          begin
             Showmessage('Clase  cargada');
 
             Prueba :=  PruebaClass.Create;
              try
                 SetPropValue (Prueba,  'Nombre', 'Benjamin');
                 nombre :=  getPropValue(Prueba, 'Nombre');
 
                  ShowMessage(nombre);
              finally
                 Prueba.Free;
              end;
 
          end;
 
          UnloadPackage(Paquete);
 end;
 end;
 
 end.

¿Y si quién diseño los .bpl no utilizó este metodología?

¿Es la única posible? Seguimos leyendo.

Muchas gracias.

Saludos.

Neftali [Germán.Estévez] 12-12-2006 11:55:39

Cita:

Empezado por ezindetgeio
¿cómo hago para acceder a los métodos de la clase?
un WITH claseFinal AS clase

Por ahí va la cosa, aunque creo que te has liado con el WITH (que es otra cosa).
Hay que realizar un CAST de la clase para acceder a los métodos vía RTTI.
Aquí te envío un ejemplo para que veas cómo acceder a los métodos de la clase TClasePrueba.

Cita:

Empezado por ezindetgeio
¿Dónde puedo leer más sobre RTTI?

Aquí tienbes algo para leer.
Puedes encontrar cosas en CodeCentral de Borland:
http://cc.borland.com/Item.aspx?id=15565
Aquí tienes una serie de 5 artículos:
http://www.suite101.com/article.cfm/...gramming/60117
http://www.suite101.com/article.cfm/...gramming/60799
http://www.suite101.com/article.cfm/...gramming/62001
http://www.suite101.com/article.cfm/...gramming/63526
http://www.suite101.com/article.cfm/...gramming/64922
Este bastante esquemático:
http://www8.pair.com/rmorris/rtti.htm
Este tiene códigos de ejemplo:
http://www.blong.com/Conferences/Bor...RTTI/CB140.htm
Este es sencillo (revisa tb los comentarios):
http://hallvards.blogspot.com/2006/0...lass-rtti.html

Bueno aquí tienes algunos; Si buscas por internet seguro que encuentras más...

Neftali [Germán.Estévez] 12-12-2006 12:06:46

Cita:

Empezado por ezindetgeio
¿Y si quién diseño los .bpl no utilizó este metodología?
¿Es la única posible?

Bueno, esa sería la más correcta (utilizando propiedades Public/published y procedures/funciones de acceso private) .
Te lo quería comentar, porque en tu ejemplo no estabas utilizando propiedades, pero tal y como estaba me servía para mostrarte la forma de acceder a procedimientos y funciones. Para acceder a las propiedades es mucho más fácil tal y como has hecho tú, ya que delphi provee de la unit TypInfo que posee mátodos para ello (revísala si todavía no lo has hecho).

El único inconveniente que te puedes encontrar es que, si quien diseñó los BPL's utilizó propiedades/métodos Public en lugar de Published (que en muchos casos son suficientes); En ese caso no podrás acceder a ellos, ya que para RTTI necesitas obligatoriamente que sean Published.

ezindetgeio 12-12-2006 12:42:30

Muchas gracias Neftali! ;)

Te debo más de una.

Ahora mismo me miro la opción sin properties, a ver que tal me va.

Saludos.

Neftali [Germán.Estévez] 12-12-2006 14:51:05

Cita:

Empezado por ezindetgeio
Ahora mismo me miro la opción sin properties, a ver que tal me va.

Que conste que no son excluyentes; Normalmente los objetos tienen propiedades y métodos; A cada cosa lo suyo y estos son los dos métodos que debes utilizar.
En el caso de Nombre y Edad yo los veo como propiedades.

ezindetgeio 12-12-2006 15:02:22

No si ya. la opción d elos properties a mí me gusta. Pero no me hago yo todos los BPLs, ahí está el problema.

Así que más me vale aprender otras opciones ;)

Muchas gracias de nuevo.

¡Un saludo!


La franja horaria es GMT +2. Ahora son las 07:18:46.

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