Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Componentes en librerias DLL (https://www.clubdelphi.com/foros/showthread.php?t=72301)

adonias 09-02-2011 17:10:41

Componentes en librerias DLL
 
Hola.

Una consulta basica.

Cuando creo un Form, luego puedo llamar sus componentes

Ejemplo:

Código Delphi [-]
 
...  

uses Componentes;
 
...    

Componentes.UniConnection1.Server  := ComboBox1.Text;   
Componentes.UniConnection1.UserName:= Usuario.Text;   
Componentes.UniConnection1.Password:= Pass.Text;   
Componentes.UniConnection1.ProviderName:='Oracle';   
Componentes.UniConnection1.Connect; 

...

Ahora. Cuando creo una libreria DLL, llamo funciones asi:


Código Delphi [-]
  
...  

Procedure ShowAbout(Atitle:string);stdcall;external 'Function.dll';  

...  

ShowAbout('Acerca de Funciones en DLL externas');  

...

¿Podria llamar a UniConnection1 desde la dll?


Algo asi como

Código Delphi [-]
  
  Dll.UniConnection1.Server  := ComboBox1.Text;
  Dll.UniConnection1.UserName:= Usuario.Text;
  Dll.UniConnection1.Password:= Pass.Text;
  Dll.UniConnection1.ProviderName:='Oracle';
  Dll.UniConnection1.Connect;

Gracias!

Neftali [Germán.Estévez] 09-02-2011 17:43:53

Creo que lo correcto es que le pases a la DLL los valores y en todo caso que desde la DLL se asignen los valore a los componentes.

De todas maneras no accedes a la DLL como variable, sino que dentro tendrás un Form (me imagino) con componentes dentro, así que en cualquier caso seguirás accediendo al form.

adonias 09-02-2011 17:55:41

Estube buscando en el foro, y lei que hay componentes BPL.

Una vez que los cargo con LoadPackage, puedo llamar alguno de los componentes?

adonias 09-02-2011 19:11:41

Ok.

Hasta aqui voy bien.

Cargo el paquete en el form1
Código Delphi [-]
procedure TFrm.FormCreate(Sender: TObject);
var
  PackageModule: HModule;
  AClass: TPersistentClass;
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
        ShowModal;
        labelForm2.Caption := 'hola';   <---- No llego al form2
        Free;
      end;

    UnloadPackage(PackageModule);
  end;

end;

El problema es cuando intento llegar al label del form2

Neftali [Germán.Estévez] 10-02-2011 10:53:57

Lo primero que veo es que si utilizas ShowModal, no accederás a la línea que comentas hasta que no cierres el formulario,por lo tanto en este caso debería utilizar Show.

Por otro lado, como estás accediendo al formulario de forma genérica, para acceder al label puedes utilizar FindComponent, por ejemplo.

Cambia el código por este:

Código Delphi [-]
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;

Además en el package debes registrar la clase del formulario para poder encontrarla posteriormente con GetClass.

Al final de la Unit del Form2 coloca este código:


Código Delphi [-]
initialization
  RegisterClass(TForm2);

finalization
  UnregisterClass(TForm2);

Por último asegurate de que estás compilando el proyecto con la opción "Build with runtime Packages".

Descarga este ejemplo y revisa el código, creo que te puede ser de utiidad (Sistema de plug-ins utilizando packages dinámicos).

Un saludo.

adonias 10-02-2011 13:39:18

Tu lo haces ver tan facil neftalí!!!


Funciono perfecto...

Muchisimas gracias Master!

rgstuamigo 10-02-2011 14:27:41

Bueno ..nada más agregar otra alternativa..(aunque no la he probado)... es decir que para poder obtener el label se podría hacer un casting del formulario directamente a clase del formulario en cuestion;ésto en la siguiente linea:
Código Delphi [-]
...
 with TComponentClass(AClass).Create(Application)
        as TCustomForm do //<-- aquí en ves de hacer casting hacia TCustomForm deberiamos hacerlo directamente hacia la 
               //Clase descendiente que nos interesa, es decir hacia nuestro formulario ;) 
      begin
        ShowModal;
        labelForm2.Caption := 'hola';   <---- No llego al form2
        Free;
      end;
...
Saludos...:)

Neftali [Germán.Estévez] 10-02-2011 15:58:36

Cita:

Empezado por rgstuamigo (Mensaje 390564)
... es decir que para poder obtener el label se podría hacer un casting del formulario directamente a clase del formulario en cuestion

El problema es que si pusieras ahí la clase del formulario en cuestión (TForm2, por ejemplo, en lugar de TCustomForm) eso te obligaría (el compilador en realidad) a añadir la unit donde se encuentra definido TForm2, al USES. :(

rgstuamigo 11-02-2011 17:46:44

A caray.. entonces no se permite poner ningun Uses en la unidad en cuestion?:confused:
Bueno... no soy bueno para trabajar con Paquetes y el manejo RTTI en Delphi pero mi pregunta es entonces:
Neftalí, se puede hacer un casting en delphi hacia una clase específica teniendo el nombre de clase específica en una variable?:confused:
Por que si se lograse hace eso, se podría utilizarlo en éste caso ¿verdad? o no es posible hacer eso? :)
Saludos...:)

roman 11-02-2011 18:09:37

Cita:

Empezado por rgstuamigo (Mensaje 390718)
Neftalí, se puede hacer un casting en delphi hacia una clase específica teniendo el nombre de clase específica en una variable?

Lo que puedes es obtener la clase a partir de su nombre con GetClass, tal como lo hace adonias. Pero el moldeo (casting) ¿qué sentido tendría? Si moldeas es porque vas a usar un método o propiedad específica de dicha clase, pero entonces tendrías que tener la definición de la clase, o sea, en un uses, con lo cual ya no estarías cargando dinámicamente el paquete.

// Saludos

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

Cita:

Empezado por rgstuamigo (Mensaje 390718)
A caray.. entonces no se permite poner ningun Uses en la unidad en cuestion?

Justo en este caso es en el que no se puede hacer.
La gracia de cargar los paquetes de forma dinámica con LoadPackages, es que el ejecutable en el momento de compilarse y de ejecutarse no debe tener ninguna referencia a lo que hay en ese package (imagina plugIns que puedes estar o no).

Si en este caso añadimos al USES una unit del TForm2, cuando Delphi compile el proyecto pedirá esa unit y la incluirá en el EXE o si estubiera con packages se asegurará de "linkar ese package de foma estática" para que ese package exista al ejecutar (y eso es justo lo que no queremos -que lo linke de forma estática-).


Cita:

Empezado por rgstuamigo (Mensaje 390718)
Bueno... no soy bueno para trabajar con Paquetes y el manejo RTTI en Delphi pero mi pregunta es entonces:
Neftalí, se puede hacer un casting en delphi hacia una clase específica teniendo el nombre de clase específica en una variable?
Por que si se lograse hace eso, se podría utilizarlo en éste caso ¿verdad? o no es posible hacer eso?

Justo para solventar eso es para lo que utilizamos la RTTI.
Teniendo el nombre de una clase no puedes "castear por ella", pero con RTTI puedes acceder a la Clase, acceder a sus métodos, ejecutarlos, acceder a las propiedades, modificarlas,...

En principio teniendo el string 'TForm2' podemos hacer casi todo, pero no llegaremos a:
Código Delphi [-]
Form2 := TForm2.Create();
Form2.Label.Caption := 'hola';

Podemos llegar a hacer lo mismo por RTTI, pero no al menos de esta forma. :o

AÑADO: Se me ha adelantado Román y lo ha explicado perfecto y conciso... ;-)

roman 11-02-2011 18:21:52

Aunque usar RTTI no es, en mi opinión, lo más adecuado. Siempre es preferible tener una interfaz entre la aplicación y los paquetes para que ambos se comuniquen.

// Saludos

rgstuamigo 11-02-2011 18:24:54

Ajaá..:rolleyes: ya voy entendiendo mejor la cuestion esa de "cargar dinámicamente paquetes":D aunque en RTTI estoy verde aún.:o:D

Cita:

Empezado por roman (Mensaje 390720)
Lo que puedes es obtener la clase a partir de su nombre con GetClass, tal como lo hace adonias. Pero el moldeo (casting) ¿qué sentido tendría?

Ok.. ya no tiene sentido dicho moldeo en el caso de cargar dinamicamente:o, pero si no estoy trabajando con carga dinámica, es posible hacer dicho moldeo(casting) teniendo la clase con GetClass?:confused: de ser así me podrias dar un ejemplo si no es mucha molestia?
Saludos..:)

roman 11-02-2011 18:31:24

¡Polimorfismo!

Con GetClass obtienes una referencia de clase. En el caso que nos ocupa, como al menos se sabe que la clase referenciada es un descendiente de TForm, puedes hacer el moldeo con TForm y así llamar al constructor.

El polimorfismo es entonces, lo que permite que la instancia construida sea de la clase derivada y no de TForm.

Así pues, no puedes hacer el moldeo, pero sí construir los objetos de la clase adecuada.

// Saludos

rgstuamigo 11-02-2011 18:46:12

Disculpame pero estoy un poco perdido :o, " estoy más perdido que Evo en Nueva York":D:D.
Hasta aquí>
Cita:

Empezado por roman (Mensaje 390727)
...
Con GetClass obtienes una referencia de clase.

Todo bien pero...
Cita:

Empezado por roman (Mensaje 390727)
..En el caso que nos ocupa, como al menos se sabe que la clase referenciada es un descendiente de TForm, puedes hacer el moldeo con TForm y así llamar al constructor.

El polimorfismo es entonces, lo que permite que la instancia construida sea de la clase derivada y no de TForm.

Así pues, no puedes hacer el moldeo, pero sí construir los objetos de la clase adecuada.

Es decir que puedo hacer el casting siempre y cuando tenga Pre-conocimiento de que se trata de un objeto específico?:confused:
Yo estaba pensando :rolleyes: que talves podría haber la posibilidad de que tal casting sea más abstracto., pero talves sea puras ideas mías,no me hagan caso:D,en fin supongo que talves delphi llega hasta por ahí nomas...;)
Saludos y la verdad que me parece un tema muy interesante...;)

roman 11-02-2011 18:56:12

¿Más abstracto? Bueno, puedes usar TComponent -como, de hecho, lo hace adonias. Más no puedes porque el constructor de TObject no es virtual.

Pero, lo que debes preguntarte es, ¿qué ganas con eso?

Si tienes una aplicación que requiere crear formularios que no conoce de antemano, el poder hacerlo a partir de TForm, o incluso a partir de algún TBaseForm que sea más específico a tu aplicación, es algo sumamente poderoso.

El "preconocimiento" que mencionas sólo se refiere a que se trata de un formulario, pero no requiere saber qué formulario en específico es. Es la potencia del polimorfismo.

Y esto es así en cualquier lenguaje OOP. De hecho, no todos los lenguajes las clases tienen un ancestro común como el TObject de Delphi.

// Saludos

rgstuamigo 11-02-2011 19:19:58

Bueno básicamente a lo que yo me refería es que si delphi permite hacer ésto:
Código Delphi [-]
...
with TComponentClass(AClass).Create(Application)...
...
Osea estoy instanciando un objeto atraves de su clase(algo muy pero muy bueno por cierto;) ) entonces quizas debería poder hacer algo similar para hacer casting hacia la misma clase(AClass)
algo como
Código Delphi [-]
...
with TComponentClass(AClass).Create(Application) as AClass do// ;)
...
o algo por el estilo, pero como dije es solo un pensamiento y la verdad me falta mucho por aprender...:o
Saludos...:)

roman 11-02-2011 19:31:54

Ok. Vamos a suponer que puedes. Entonces, ya tendrías, con

Código Delphi [-]
TComponentClass(AClass).Create(Application) as AClass

una referencia de TForm2. ¿Cuál sería tu siguiente línea de código? ¿Algo asi?

Código Delphi [-]
(TComponentClass(AClass).Create(Application) as AClass).labelForm2.Caption := 'hola';

Pero, para que el compilador sepa quién es labelForm2, necesita la definición de TForm2, que es lo que no tienes.

La única manera sería usar RTTI. Pero, como dije, eso no siempre es del todo una buena idea. Se supone que en OOP, con una referencia a un objeto debes poder hacer sólo lo que la clase de ese objeto marque.

Claro que el IDE de delphi no podría existir sin RTTI, pero un IDE es un tipo muy especial de aplicación, es algo así como una meta-aplicación :)

// Saludos


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

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