Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Evitar cerrar formulario principal si hay librerías cargadas dinámicamente (https://www.clubdelphi.com/foros/showthread.php?t=57914)

ContraVeneno 01-07-2008 22:03:27

Evitar cerrar formulario principal si hay librerías cargadas dinámicamente
 
Tengo un formulario contenedor (MDI) en el cuál cargo una librería externa de la siguiente manera:

Código Delphi [-]
TCrear = procedure (ParentApplication: TApplication; ParentForm: TForm); stdcall;
......
Procedure TMain.Cargar.....
var
   DllHandle: THandle;
   ProcAddr: FarProc;
   CrearForma: TCrear;
....
   DllHandle := LoadLibrary(PAnsiChar('UnArchivo.Dll'));
   ProcAddr := GetProcAddress(DllHandle, 'CrearForma');
   if ProcAddr <> nil then begin
      CrearForma := ProcAddr;
      CrearForma(Application,Self);
   end;
....
En el archivo .dll tengo lo siguiente:
Código Delphi [-]
procedure CrearForma(ParentApplication: TApplication; ParentForm: TForm); export; stdcall;
begin
   Application:=ParentApplication;
    with TForm1.Create(Application) as TCustomForm do begin
      MyParentForm:=ParentForm;
      MyParentApplication:=Application;
      FormStyle := fsMDIChild;
      Show;
    end;
end;

exports
   CrearForma;

Con esto puedo cargar el DLL sin ningún problema y me lo muestra como hijo (MDIChild) de mi formulario principal (MDI).

Pero en mi formulario principal (MDI), la variable MDIChildCount siempre me da 0. Aún y cuando yo veo que está el formulario de la DLL creado como hijo (Mdichild).

¿cómo puedo hacer que mi DLL se considere en el formulario principal?
Es decir, ¿como puedo hacer que MDIChilCount realmente me cuente mi
DLL?

Lo que al final quiero lograr, es evitar que se cierre el formulario principal (MDI) si existen DLL cargadas:
Código Delphi [-]
procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  if MDIChildCount <> 0 then begin
   showmessage('No cierras');
   CanClose := False;
  end;
end;

Y aprovechando, ¿como puedo hacer para cargar una DLL solo una vez?


P.D. Se me olvidó cuál era la correcta definición de una DLL: ¿librería o biblioteca?

cHackAll 01-07-2008 23:11:16

MAIN;

Código Delphi [-]
//...
 
var Count: PCardinal;
 
procedure TMain.FormCreate(Sender: TObject);
begin
 Count := MapViewOfFile(CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, 4, 'SHARED'), FILE_MAP_READ, 0, 0, 0);
end;
 
//...
 
procedure TMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
 CanClose := not LongBool(Count^);
 if not CanClose then
  ShowMessage('No cierras!');
end;
 
//...

DLLs;

Código Delphi [-]
//...
 
var Count: PCardinal;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
 Count := MapViewOfFile(OpenFileMapping(FILE_MAP_WRITE, False, 'SHARED'), FILE_MAP_WRITE, 0, 0, 0);
 Inc(Count^);
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
 Dec(Count^);
end;
 
//...

Básicamente el proceso/aplicación principal crea un espacio de memoria compartida en el que residirá nuestro contador, así mismo las DLLs acceden a dicho contador y lo incrementan en uno cuando el formulario que contiene dicha librería es creado. Al momento de ser destruido el formulario NO es liberada la librería del proceso que la ha cargado anteriormente, sin embargo en este caso tan particular su razón de existir termina y decrementamos el contador en uno.

Obviamente al intentar cerrar el formulario principal revisará si dicho contador esta en 0, en caso contrario significa que algún formulario no ha sido cerrado, y por ende no es "aconsejable" cerrarlo.

Espero te sea de utilidad.

Saludos

cHackAll 02-07-2008 01:17:31

Bueno, con respecto al título del hilo;

Código Delphi [-]
//...
 
uses PsAPI;
 
var Count: Cardinal;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
 EnumProcessModules(GetCurrentProcess, nil, 0, Count);
end;
 
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
var Last: Cardinal;
begin
 EnumProcessModules(GetCurrentProcess, nil, 0, Last);
 CanClose := not LongBool(Last - Count);
 if not CanClose then
  ShowMessage(IntToStr((Last - Count) div 2) + ' librerias cargadas dinamicamente. USE: FreeLibrary');
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
 LoadLibrary('3ivx.dll');
end;

PD; pues lo pongo porque me he aburrido un poquito :rolleyes:.

Saludos

ContraVeneno 02-07-2008 15:40:05

Cita:

Empezado por cHackAll (Mensaje 297636)
Bueno, con respecto al título del hilo;

Código Delphi [-]//... uses PsAPI; ... EnumProcessModules(GetCurrentProcess, nil, 0, Count); end; ....
EnumProcessModules(GetCurrentProcess, nil, 0, Last); CanClose := not LongBool(Last - Count);


Muy interesante propuesta, el problema que tengo es que no se como detectar cuando se ha cerrado un dll. O mas bien, no se en que punto colocar el FreeLibrary.

cHackAll 03-07-2008 02:39:53

Cita:

Empezado por ContraVeneno (Mensaje 297737)
Muy interesante propuesta, el problema que tengo es que no se como detectar cuando se ha cerrado un dll. O mas bien, no se en que punto colocar el FreeLibrary.

Y probaste ésta "propuesta" ?

ContraVeneno 03-07-2008 16:21:14

Cierto, se me olvidó comentar que la primer propuesta que haces, funciona a la perfección. :D


La franja horaria es GMT +2. Ahora son las 04:11:08.

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