Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > OOP
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 23-08-2005
adlfv adlfv is offline
Miembro
 
Registrado: may 2005
Posts: 39
Poder: 0
adlfv Va por buen camino
Ayuda con paquetes por favor!!

Hola a todos.

Estoy vuelto un 8 con los paquetes ...

Voy a intentar explicar de la forma más clara, y lo mejor posible lo que quiero hacer... Espero que me explique bien...

Estoy haciendo una aplicación muy grande... y quiero partirla en paquetes. Tengo un DataModule (DMDatosZeos) donde residen todas las tablas, algunos querys y los datasources. Tengo otro DataModule (DMGlobal) donde residen algunos componentes no visuales que uso de forma global al programa, por ejemplo para el aspecto visual de los formularios (efectos en botones y cosas así…).

Los mantenimientos de las tablas (listados con filtros, modificaciones, eliminaciones y algunas inserciones) los he programado en un formulario "general" y todos los mantenimientos heredan de éste. Cada formulario de mantenimiento tiene un formulario de edición asociado, y éste también hereda de un formulario de edición "general". Básicamente para “personalizar” un mantenimiento, tengo que decirle qué DataSource es el asociado, y qué campos tiene y el resto es más o menos automático.

En el programa tengo un objeto global, llamado _BD, de tipo TBD, que encapsula al DataModule (DMDatosZeos) y algunos métodos para tratado de datos. (No encapsula a DMGlobal… eso es aparte)

Hasta aquí todo bien... Espero que todo se entienda.

Ahora, lo que quiero hacer es... Hacer un paquete para la base de datos (BD.bpl). Dicho paquete contendría la clase TBD, y el DataModule (DMDatosZeos) que es un campo de la clase. Adicionalmente en la misma unit de TBD, tengo también algunas rutinas para trabajar con datos. Recordemos en este punto que en el programa tengo un objeto “global” _BD de tipo TBD.

La pregunta es… Cómo hago para desde el ejecutable “importar” el objeto _BD?

En el paquete BD.bpl creo el objeto _BD al cargarlo, osea… hago algo tal que así…

Código:
 initialization
    RegisterClass(TBD);
    _BD := TBD.Create;

Y tengo una función BD que me devuelve el objeto en cuestión:


Código:
 function BD: TBD;
 begin
   Result := _BD;
 end;

Esta función está en UBD (donde está definido TBD, y se encuentra en la clausula contains de BD.bpl, osea… está en el paquete BD.bpl).

Lo que se me ocurrió fue, cargar el paquete y llamar a esta función que me devuelve el objeto desde el programa de la siguiente manera:


Código:
 procedure CargarPaqueteBD;
 type
   TVarBD = function: TBD;
 var
   Lib: String;
   H: HModule;
   FuncBD: TVarBD;
 begin
   Lib := ExtractFilePath(ParamStr(0)) + 'BD.bpl';
   if not FileExists(Lib) then
 	ShowMessage('No existe');
 
   H := LoadPackage(PChar(Lib));
   if H <> 0 then
   begin
 	@FuncBD := GetProcAddress(H, 'BD');
 	if not Assigned(FuncBD) then
 	  ShowMessage('FuncBD NO ASIGNADA!!!');
 	_BD := FuncBD;
   end
   else begin
 	ShowMessage('Error cargando');
   end;
   UnloadPackage(H);
 end;

El problema es que no funciona, siempre me dice “FuncBD NO ASIGNADA!!!”, pero sí logra cargar el paquete correctamente.

No se si me expliqué lo suficiente, tal vez confundí en lugar de aclarar…

En general, necesito desde el principal recibir el objeto _BD de BD.bpl, y luego enviárselo a todos los paquetes que dependan de la base de datos. Igual pasaría con el modulo de datos Global.

Por favor, realmente necesito ayuda con esto… Llevo semanas pensando y probando y todavía no logro dar con la solución…

Muchas gracias de antemano.

Un cordial saludo a todos, y disculpen si el post es muy grande.
Responder Con Cita
  #2  
Antiguo 23-08-2005
Avatar de jmariano
jmariano jmariano is offline
Miembro
 
Registrado: jul 2005
Posts: 376
Poder: 19
jmariano Va por buen camino
Solo por curiosidad... ¿Te acordaste de exportar la función "BD"? Es decir, fíjate si tienes la siguiente sentencia después de la implementación de la función:

Código Delphi [-]
function BD: TBD;
begin
  Result := _BD;
end;
 
exports
  BD;

(Te lo comento porque la función de Windows "GetProcAddress" solo carga funciones que han sido "exportadas", ya sea que éstas se encuentren en una .bpl o .dll).

Edito: Como había dado una explicación que se me quedó algo liosa (no se si alguien llegó a leerla) prefiero adjuntarte un ejemplo de como podrías hacer lo que quieres de una forma más sencilla. Para ver el ejemplo haz lo siguiente:

- Descomprime el contenido del archivo en alguna carpeta del disco duro (por ejemplo: "C:\EjemploBPL")
- Y, por último, abre el archivo de proyecto "pgPrueba.bpg" para ver todas las fuentes y la aplicación de ejemplo.

(Si quieres ver la aplicación funcionar compila todos los paquetes, del primero al último. Cuando compiles, los paquetes .bpl se almacenarán en la carpeta por defecto de Delphi, que suele ser: "C:\Archivos de programa\Borland\Delphi7\Projects\Bpl").

Para ver una pequeña descripción del ejemplo lee el archivo "Leeme.txt" que encontrarás en la carpeta donde descomprimiste el archivo.

Espero que te sirva!

Saludos!
Archivos Adjuntos
Tipo de Archivo: zip EjemploBPL.zip (18,4 KB, 64 visitas)

Última edición por jmariano fecha: 24-08-2005 a las 05:15:22.
Responder Con Cita
  #3  
Antiguo 24-08-2005
adlfv adlfv is offline
Miembro
 
Registrado: may 2005
Posts: 39
Poder: 0
adlfv Va por buen camino
Gracias, pero sigo teniendo problemas :(

Muchas gracias por tu ayuda.

Efectivamente, me faltaba exportar la función BD, pero sigo teniendo problemas... Te cuento...

El DataModule de datos (DMDatosZeos) lo utilizo en:

· Los paquetes (pero al ponerlo en la cláusula requires, no hay problema y lo puedo ver).
· El programa principal. Esto es lo que me está volviendo loco . Como el programa principal utiliza _BD, tengo que agregar al proyecto UBD, pero es sólo para "engañar" al compilador y para que logre compilar, pues el objeto como tal reside en el paquete... Pero que pasa, que la referencia de _BD del programa tengo que hacer que apunte a la referencia de _BD del paquete, pero no logro hacerlo... Es raro que los ejecutables no tengan una clausula requires o algo así cuando trabajan con paquetes... Eso me evitaría todos estos problemas.

Para hacer la asignación de _BD del principal a _BD del paquete he probado con :=, con Assign, incluso haciendome un metodo de asignación que asigne también las otras propiedades como el DataModule, y la conexión, y nada de nada... Depuro mostrando mensajes con las direcciones de los punteros Format('@_BD=%p', [@_BD]) y cosas así, y hay referencias que no me salen iguales en el principal y en el paquete...

Extrapolando mi problema a tu código fuente, sería algo así: en mi caso tengo que agregar CPrueba.pas al proyecto prueba.exe pues en ese se utiliza la base de datos, con lo cual tengo 2 objetos _Prueba, uno en el paquete y otro en el programa, el del paquete es el que se crea en realidad, pero el del programa debe apuntar (incluidos todos los campos métodos y todo) al del paquete (es decir debe ser como una copia exacta, pero sin ser copia, pero sin ser copia, pues la base de datos es común). Cómo puedo hacer esto?

Tal vez deba distinguir si el código de UBD es el del ejecutable o el del paquete mediante alguna directiva IFDEF (o algo así) pues dicha unidad es compartida a los paquetes y al ejecutable algo así como:
Código:
  {$IFDEF PROJECT=BD.BPL}
    ShowMessage('Estoy en el paquete');
  {$ELSEIF PROJECT=PRINCIPAL.EXE}
    ShowMessage('Estoy en el ejecutable');
  {$ELSE}
    ShowMessage('Estoy PERDIDO!!!');
  {$IFEND}
La verdad no tengo de cómo hacerlo, no he podido conseguir nada sobre esta directiva (o si existe algo similar) ni en la ayuda, ni en internet...

Muchas gracias por tu ayuda, te lo agradezco de verdad.

Y gracias a todos los que se han molestado en leer todo este rollo...

Un cordial saludo a todos.
Responder Con Cita
  #4  
Antiguo 24-08-2005
Avatar de jmariano
jmariano jmariano is offline
Miembro
 
Registrado: jul 2005
Posts: 376
Poder: 19
jmariano Va por buen camino
Saludos otra vez!

No entiendo el porqué duplicas ambos objetos (es decir, porqué has de tener el objeto _BD en el principal y en el paquete) si desde el principal puedes usar el objeto _BD del paquete (sin tener que pasar la referencia de un objeto a otro).

Seguramente tu problema sea que quieres usar el objeto _BD del paquete desde el mismo archivo de proyecto .dpr. Para hacer esto lo único que tienes que hacer es especificar el unit "UBD" (donde se encuentra declarado el objeto _BD) en la cláusula "uses" del .dpr pero sin añadir "UBD" al proyecto (porque si lo añades, entonces, no usará el del paquete).

Siguiendo con el ejemplo que te mandé, el .dpr quedaría así para usar _Prueba desde el principal:

Código Delphi [-]
program Prueba;
uses
  Forms, CPrueba {especificamos sólo el unit donde se declara el objeto},
  FPrincipal in 'FPrincipal.pas' {frmPrincipal};
 
{$R *.res}
 
begin
  Application.Initialize;
  
  { Para probar añade el método "Mensaje(Msj: string)" a la clase TPrueba
    que se encuentra en el paquete "BDPRueba" }
  _Prueba.Mensaje('Hola');
 
  Application.CreateForm(TfrmPrincipal, frmPrincipal);
  Application.Run;
end.

(El ejemplo mostraría el mensaje "Hola" antes de mostrar el formulario principal).

Como te comenté antes, no añadas "CPrueba" al proyecto Prueba.exe para que utilice el objeto _Prueba del paquete "BDPrueba". Y acuerdate también que has de añadir, en las opciones del proyecto Prueba.exe (pestaña "Packages", sección "Runtime Packages"), el paquete "BDPrueba" (más el del formulario "FormPrueba", y en realidad cualquier paquete que necesitemos usar).

Edito: Me faltó aclarar (por si aún no has entendido bien como va todo este tema de paquetes) que para que un paquete use las clases u objetos definidos en otro paquete tendremos que añadir a su cláusula "Requires" aquellos paquetes donde se encuentren dichas clases u objetos (después, para hacer uso de la clase u objeto, sólo es necerio especificar, en las cláusulas "uses" correspondientes, aquellas units que contengan el objeto).

Además, será necesario especificar en las opciones del archivo de proyecto .dpr (pestaña "Packages", sección "Runtime Packages") aquellos paquetes utilizados de forma dinámica. Y para utilizar una clase u objeto desde el mismo .dpr sólo es necesario (al igual que antes) especificar en la cláusula "uses" las units necesarias.


Cualquier duda vuelveme a preguntar!

Chao!

Última edición por jmariano fecha: 24-08-2005 a las 20:21:27.
Responder Con Cita
  #5  
Antiguo 25-08-2005
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Hola, voy a hablar un poco en el aire porque no he revisado esto con detenimiento.

A mi me parece que hay una confusión de conceptos.

Cita:
Empezado por adlfv
Como el programa principal utiliza _BD, tengo que agregar al proyecto UBD, pero es sólo para "engañar" al compilador y para que logre compilar, pues el objeto como tal reside en el paquete...
Realmente no estás engañando al compilador, simplemente estás enlazando el paquete a tu aplicación estáticamente. Esto quiere decir que tu ejecutable sabe desde un principio qué bpl buscar y por ende es innecesario cargarlo dinámicamente con LoadPackage.

Al hacer esto (carga estática de paquetes), sigues teniendo la ventaja de la modularidad que proporcionan los paquetes: puedes hacer cambios en el paquete sin tener que recompilar ni redistribuir toda la aplicación porque el paquete como tal no está en el ejecutable, únicamente el enlace a él.

Así que, antes de proseguir te conviene preguntarte si no te es suficiente esto. Posiblemente lo sea y ya no has de darle más vueltas al asunto.

El uso de paquetes dinámicos- aquellos cargados dinámicamente con LoadPackage -tiene otra finalidad, una ventaja extra sobre los paquetes estáticos.

Veamos un ejemplo.

Tienes una aplicación que exporta datos a una base. Para ello tienes una rutina en tu aplicación principal que recibe un DataSet:


Código Delphi [-]
procedure Exportar(DataSet: TDataSet);
begin
  DataSet.Open;
  while condicion do
  begin
    DataSet.Append;

    DataSet.FieldByName(...) := valor;
    DataSet.FieldByName(...) := valor;

    ...

    DataSet.Post;
  end;
end;

Supón ahora que la aplicación debe poder exportar los datos bien sea a MySql, Firebird o cualquier otro motor que el cliente desee en un futuro.

Para ello debes proporcionar a la rutina de exportación el DataSet adecuado al motor (TZTable, TIBTable, etc...).

Claro que lo más fácil sería:


Código Delphi [-]
if ExportarAMySql then
  Exportar(ZTable)
else if ExportarAFirebird then
  Exportar(IBTable);

pero esto condena tu aplicación a usar sólo esos dos motores. Para cualquier otro tendrás que agregar la condición correspondiente, recompilar y redistribuir toda la aplicación.

Claro que puedes obtener el DataSet de un paquete; pero si el enlace es estático el cliente tendría que cambiar uno por otro cada vez y reiniciar la aplicación.

Aquí es donde la carga dinámica adquiere sentido. El cliente proporciona, desde la aplicación, el nombre del paquete, lo cargas con LoadPackage y obtienes el DataSet que proporcione ese paquete.


Si una necesidad similar es la que realmente requieres entonces sí tendrás que estudiar como obtener el objeto BD del cuál hablas.

Regresando al principio; incluir la unidad en tu aplicación no sirve porque fuerzas un enlace estático.

La solución

Cita:
Empezado por jmariano
Para hacer esto lo único que tienes que hacer es especificar el unit "UBD" (donde se encuentra declarado el objeto _BD) en la cláusula "uses" del .dpr pero sin añadir "UBD" al proyecto (porque si lo añades, entonces, no usará el del paquete).
hasta donde yo entiendo no es correcta. Si quitas el paquete del proyecto pero dejas la referencia en la cláusula uses lo que sucederá es que tu aplicación ya no sólo se enlazará estáticamente al paquete, sino que de hecho lo integrará al ejecutable. Aun cuando logres apuntar al objeto que está en el paquete cargado dinámicamente, la realidad es que tendrás dos copias del objeto, con lo cual pierde sentido el cargarlo dinámicamente.

Para usar paquetes dinámicos- evitando el enlace estático, tu aplicación no puede contener ninguna referencia al paquete, ni en la lista de run time packages ni en las cláusulas uses.

Si no hay ninguna referencia entonces ¿cómo puedes usar los objetos de los paquetes?

Una posible solución es mediante el uso de clases abstractas. Defines una clase base que declare los métodos que requiera tu aplicación pero que no los implemente:


Código Delphi [-]
// DB_Base.pas

type
  TBDBase = class
    procedure HazAlgo; virtual; abstract;
  end;

Esta clase la colocas o bien directamente en tu aplicación o bien en un paquete enlazado estáticamente. Con esto tu aplicación compila sin problemas y al ejecutable sólo le estás agregando, por así decirlo, la definición de los métodos.

La implementación real de la clase (una clase descendiente) la colocarías en un paquete que, éste sí, cargarás dinámicamente:


Código Delphi [-]
// DB_Zeos.pas

interface

function CrearObjetoDB: TDBBase;

exports CrearObjetoDB;

implementation

uses DB_Base;

type
  TDBZeos = class(TDBBase)
    procedure HazAlgo; override;
  end;

procedure TDBZeos.HazAlgo;
begin
  {
    Aquí toda la implementación para Zeos
  }
end;

function CrearObjetoDB: TDBBase;
begin
  Result := TDBZeos.Create;
end;

Como ves, el paquete también enlaza estáticamente la clase base. Pero esto no es una carga ya ésta clase sólo define pero no implementa.

Nota que la clase descendiente TDBZeos ni siquiera tiene que estar en la sección interface.

En tu aplicación principal cargas el paquete con LoadPackage tal como lo has hecho y obtienes la dirección de la función CrearObjetoDB que exporta el paquete:

Código Delphi [-]
var
  PackModule: HModule;
  CrearObjetoBd: function: TBDBase;
  BD: TBDBase;

begin
  PackModule := LoadPackage('bdzeos.bpl');
  @CrearObjetoBD := GetProcAddress(PackModule, 'CrearObjetoBD');
  BD := CrearObjetoBD;
  BD.HazAlgo;

Como la aplicación sí usa la unidad DB_Base que define la clase base, el compilador no protesta ni en la declaración de la variable BD ni en la llamada al método HazAlgo.

Pero el polimorfismo hace que el objeto real sea de tipo TDBZeos.

En cualquier momento puedes programar otro paquete para otro motor de datos y tu aplicación estará lista para usarlo tan sólo especificando el nombre del paquete.

Nota además, que ni siquiera se requiere el uso de RegisterClass ni GetClass con lo cual no estás restringido a usar descendientes de TPersistent.

Espero no estar equivocado en los conceptos y que esto te aclare las cosas.

// Saludos
Responder Con Cita
  #6  
Antiguo 25-08-2005
Avatar de jmariano
jmariano jmariano is offline
Miembro
 
Registrado: jul 2005
Posts: 376
Poder: 19
jmariano Va por buen camino
Cita:
Empezado por roman
Regresando al principio; incluir la unidad en tu aplicación no sirve porque fuerzas un enlace estático.

La solución

Citar:
Originalmente publicado por jmariano

Para hacer esto lo único que tienes que hacer es especificar el unit "UBD" (donde se encuentra declarado el objeto _BD) en la cláusula "uses" del .dpr pero sin añadir "UBD" al proyecto (porque si lo añades, entonces, no usará el del paquete).




hasta donde yo entiendo no es correcta. Si quitas el paquete del proyecto pero dejas la referencia en la cláusula uses lo que sucederá es que tu aplicación ya no sólo se enlazará estáticamente al paquete, sino que de hecho lo integrará al ejecutable. Aun cuando logres apuntar al objeto que está en el paquete cargado dinámicamente, la realidad es que tendrás dos copias del objeto, con lo cual pierde sentido el cargarlo dinámicamente.

Para usar paquetes dinámicos- evitando el enlace estático, tu aplicación no puede contener ninguna referencia al paquete, ni en la lista de run time packages ni en las cláusulas uses.
Eso no es correcto, el hecho de añadir a la cláusulas "uses" el unit donde se encuentra declarado el objeto no significa que haya un enlace estático y lo integre en el ejecutable o en un paquete (de hecho, la aplicación cargará el paquete automáticamente cuando se haga referencia al objeto, y no necesitaremos usar "LoadPackage"). Pero para que esto sea así es necesario añadir a la cláusula "Requires", de todos los paquetes que usen un objeto, el paquete donde se encuentra implementado dicho objeto. Precisamente, la cláusula "Requires" sirve para indicar que no sean enlazadas estáticamente en un paquete aquellas clases u objetos utilizados que se encuentran en otras units dentro de otros paquetes. Por último, para conseguir que nuestras clases u objetos no sean enlazadas estáticamente dentro del ejecutable, es necesario especificar en la lista "Runtime packages" (sería el equivalente a la cláusula "Requires" de los paquetes), del archivo de proyecto, todos los paquetes donde se encuentren dichas clases u objetos.

Tened en cuenta que cuando se compila un paquete se genera, a parte del .bpl, un archivo de extensión .dcp (que equivaldría a los .dcu de las unit). Este archivo es el que especificamos en la cláusula "Requires" de los paquetes y en la lista "Runtime packages" del archivo de proyecto, y realizar esto sirve precisamente para indicar a la aplicación que paquetes han de ser cargargados dinámicamente (y no enlazarlos estáticamente), evitándonos así todo el proceso que representa la carga manual de paquetes. (Para verlo más fácilmente, imaginemos que cada vez que especificamos un archivo .dcp se está añadiendo a una "lista", dentro del ejecutable o .bpl, aquellos paquetes que han de ser cargados dinámicamente).

Por último, aclarar nuevamente que es necesario especificar en la lista "Runtime packages" del archivo de proyecto aquellos paquetes que se desean usar de forma dinámica (porque sino, entonces, sí que se enlazaran estáticamente). (Esta es una de las razones del porqué los ejecutables son tan grandes en Delphi, y cuando hacemos uso de los paquetes de ejecución se "encogen").

Última edición por jmariano fecha: 25-08-2005 a las 14:51:13.
Responder Con Cita
  #7  
Antiguo 25-08-2005
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Cita:
Empezado por jmariano
es necesario especificar en la lista "Runtime packages" del archivo de proyecto aquellos paquetes que se desean usar de forma dinámica
Vamos a aclarar una cosa:

El que un paquete esté dentro de esta lista no significa que el paquete sea dinámico.

El colocar un paquete en esta lista significa simplemente que el paquete residirá fuera del ejecutable (razón por la cual el tamaño del ejecutable decrece).

Sin embargo, cualquier referencia al paquete dentro de la aplicación (no me estoy metiendo aquí con otros paquetes y su lista de paquetes requeridos), hará que el enlace sea estático, aún estando fuera del ejecutable.

Si se quita el archivo bpl la aplicación marcará un error al iniciar ya que, al ser un enlace estático, el ejecutable busca este bpl desde el inicio.

Es similar a las bibliotecas dll (los bpl son a fin de cuentas un tipo especial de dlls).

Si existe una sóla referencia a la biblioteca dentro de la aplicación, el ejecutable la buscará desde el inicio (enlace estático) por lo que fallará si no está presente el dll.

Si se desea un enlace dinámico a la biblioteca entonces debe omitirse cualquier referencia a ella y cargarla con LoadLibrary.

La conclusión entonces es: si el paquete está en la lista de run time packages y por otro lado se usa LoadPackage para cargarlo, entonces se habrá cargado dos veces el paquete; una vez al inicio de la aplicación y otra al usar LoadPackage.

En resumen, la calidad de estático o dinámico se refiere a la forma en que se enlaza el paquete, no a si éste reside o no dentro del ejecutable.

Puede leerse el conocido artículo Dynamic packages in Delphi de Vino Rodrigues donde específicamente señala los siguientes puntos para enlazar dinámicamente un paquete:

Cita:
...
4.Remove "Package1" from the "Runtime packages" edit-box section and OK the options.
5. On Delphi's toolbar, click on the "Remove file from project" button.
6. Select "Unit2 | Form2" from the list and then "OK."
7. Now go to the "Unit1.pas" source and remove Unit2 from its uses clause. (These steps are required to remove any link to Unit2 and the package we wish to load dynamically.)
// Saludos

Última edición por roman fecha: 25-08-2005 a las 14:40:48.
Responder Con Cita
  #8  
Antiguo 25-08-2005
Avatar de jmariano
jmariano jmariano is offline
Miembro
 
Registrado: jul 2005
Posts: 376
Poder: 19
jmariano Va por buen camino
Edito: (Edité porque te leí mal y la explicación que di carece, por tanto, de sentido)

Tienes razón (y me equivoqué yo, o más bien me lié con todo este tema de paquetes, je!) en que los paquetes cargados dinámicamente con "LoadPackage" no hay que especificarlos en la lista "Runtimes packages" (como es lógico, sólo es necesario especificar aquí los que queremos que cargue la aplicación de forma automática). (A parte, el significado que yo lo estaba dando a la palabra "estático" era a la "integración" dentro del ejecutable o .bpl).

De todas formas, si miráis el ejemplo que subí, sólo el paquete "BDPrueba.bpl" es cargado por la aplicación al inicio (ya que se usa un objeto en el principal), pero el formulario mostrado si es cargado dinámicamente a través de la función "LoadPackage". Mi intención con el ejemplo era mostrar una forma más sencilla de hacer uso de un objeto (implementado en otro paquete) que es utilizado tanto desde el mismo programa principal como desde los demás paquetes relacionados con el programa (los cuales si se cargarían dinámicamente con "LoadPackage"), ya que, por el uso que tiene, resulta innecesario complicarse con la carga manual del objeto.

Saludos!

Última edición por jmariano fecha: 25-08-2005 a las 16:21:14.
Responder Con Cita
  #9  
Antiguo 25-08-2005
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Releyendo el mesaje original y para concretar ideas, lo que yo le recomendaría a adlfv es olvidarse de los paquetes dinámicos.

En la unidad UBD colocaría una función así:

Código Delphi [-]
unit UBD;

interface

function ObtenerBD: TBD;

implementation

var
  _BD: TBD;

function ObtenerBD: TBD;
begin
  if not Assigned(_BD) then _BD := TBD.Create;
  Result := _BD;
end;

initialization

  { nada aquí }

finalization
  _BD.Free;
end.

Es decir, en lugar de crear el objeto en la inicialización, se crea hasta la primera vez que se use.

Cualquier otro paquete que requiera de éste lo agregará (valga la redundancia) en su lista de paquetes requeridos.

La aplicación principal incluye UBD (cláusula uses) con lo cual puede usar libremente ObtenerBD (y por tanto _BD) sin necesidad de cargar explícitamente el paquete ni importar la función.

Y claro, usar la opción "Build with RunTime Packages" y agregar el paquete BD en la lista.

Con esto, la aplicación queda modularizada: se pueden hacer cambios a BD, recompilarlo y, sin necesidad de recompilar la aplicación, la nueva funcionalidad estará lista.

// Saludos
Responder Con Cita
  #10  
Antiguo 29-08-2005
adlfv adlfv is offline
Miembro
 
Registrado: may 2005
Posts: 39
Poder: 0
adlfv Va por buen camino
Gracias

Muchas gracias a los dos por responder.

Sus respuestas me han encaminado respecto a el tema de los paquetes para el caso de la BD, pero ahora tengo otra duda.

He estado viendo una web (bastante antigua) que habla de paquetes y conseguí algo que me pareció bastante interesante que plantea el siguiente código:

Código:
 var
   ThisInterface: TAddinModuleInterface;
 initialization
   ThisInterface := InitAddinModuleInterface(HInstance);
   with ThisInterface do
   begin
 	Caption := 'Module &1';
 	AddMaintenanceForm('&Customers', 'TfrmCustMaint');
 	AddMaintenanceForm('&Employees', 'TfrmEmpMaint');
 	AddEnquiryForm('&Sales Orders', 'TfrmOrderEnquiry');
 	AddReportForm('&Phone List', 'TfrmCustomerPhoneList');
 	MergeUserInterface;
   end;
La idea es meter los formularios independientes como formularios de mantenimientos, listados, reportes y cosas así en paquetes. Cada formulario puede tener su propio menú y se mezcla al cargarlo (como si fuese un plugin). Este código lo conseguí en: http://www.obsof.com/delphi_tips/DL613.html

La versión del ejemplo es antigua, utiliza D4 y QuickReports, mientras que yo no dispongo de QuickReports y utilizo D2005. Estoy intentando migrar dicho código, para obtener una funcionalidad similar pero desgraciadamente no comprendo aún bien el código. Por ejemplo, el autor de esto lo hace mediante el uso del registro, y no logro comprender el por qué lo hace así.

Si alguien conoce un código similar, o me puede orientar sobre cómo hacerlo le estaría muy agradecido. La idea es en cada paquete "registrar" el formulario en la seccion de inicialización y que salga automáticamente la opción para acceder a dicho formulario en el menú del programa.

Muchas gracias de antemano.

Ahh, se me olvidaba... Estoy intentando hacer la aplicación con arquitectura de plugins, osea que habran varios módulos que el usuario final podrá decidir si quiere o no. Para estos módulos sí debería hacerlo con paquetes dinámicos, no? Pues si no existen, el programa debe funcionar igual (sin fallos) pero sin la funcionalidad encapsulada en dicho paquete...

Muchas gracias de nuevo.

Un cordial saludo.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro


La franja horaria es GMT +2. Ahora son las 12:37:11.


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
Copyright 1996-2007 Club Delphi