Cómo pasar a primer plano una aplicación instanciada por segunda vez

6168 vistas

Vamos a ver dos métodos para este propósito:

1er método: utilizando el método de la clase
La idea es buscar una ventana de la misma clase que TApplication con el mismo título y ponerla en primer plano si existe.
El código del proyecto ( .DPR ) tiene que ser el siguiente:



delphi
  1. begin
  2.   if IsPrevInstance = 0 then
  3.   begin
  4.     Application.Initialize;
  5.     Application.CreateForm(TMDIForm, MDIForm);
  6. [...]
  7.     Application.Run;
  8.   end
  9.   else
  10.     ShowInstance(IsPrevInstance);
  11. end.



Las dos funciones (IsPrevInstance y ShowInstance) pueden ser codificadas directamente en el proyecto o bien en una unidad aparte. Su implementación será la siguiente:



delphi
  1. function IsPrevInstance: HWND;
  2. var
  3.   ClassName: array[0..255] of char;
  4.   Title: string;
  5. begin
  6.   Title := Application.Title;
  7.   Application.Title := '';
  8.   { Cambiamos el título porque sino encontrarÃamos siempre una aplicación en marcha, la nuestra }
  9.   try
  10.     GetClassName(Application.Handle, ClassName, 255);
  11.     { Ponemos en ClassName el nombre de la clase de la aplicación }
  12.     Result := FindWindow(ClassName, PChar(Title));
  13.     { Devuelve el Handle de la 1era ventana de Class (Type) ClassName y con el mismo título }
  14.   finally
  15.     Application.Title := Title; { Restauramos el verdadero título }
  16.   end;
  17. end;
  18.  
  19. procedure ShowInstance(InstHandle: HWND);
  20. begin
  21.   { Restauramos aplicación si está minimizada }
  22.   ShowWindow(InstHandle, SW_RESTORE);
  23.   { Poner la 1era instancia en 1er plano }
  24.   SetForegroundWindow(InstHandle);
  25.   { Finalizamos la 2da instancia }
  26.   Application.Terminate;
  27. end;



2ndo método: utilizando el Registro de Windows
La primera cosa a hacer es mirar si la aplicación está ya en ejecución. Para hacerlo, vamos a usar los Mutex [iurl=85&fs=38#40]descritos anteriormente[/iurl]. Esta prueba conlleva a dos situaciones posibles:

La aplicación no está en ejecución. Si la aplicación no está instanciada, tendremos que hacerlo, para ello, el lanzamiento clásico de una aplicación es suficiente. Tendremos que recuperar alguna información de la aplicación. Esta información servirá para pasar a primer plano la aplicación en el caso de un segundo lanzamiento. Para ello necesitamos 2 handles: el del propio programa y el del formulario principal.
Estos 2 valores, que tienen que ser accesibles desde fuera de la aplicación, se almacenarán en el Registro de Windows dentro de la clave HKEY_CLASSES_ROOT\software\nombre_de_la_llave y bajo los nombres FirstApplicationHandle y FirstFormHandle.



delphi
  1. Application.Initialize;
  2. Application.CreateForm(TForm1, Form1);
  3.  
  4. Registre := TRegistry.Create;
  5. try
  6.   Registre.RootKey := HKEY_CLASSES_ROOT;
  7.   Registre.OpenKey('\Software\nombre_de_la_llave', True);
  8.   Registre.WriteInteger('FirstApplicationHandle', Application.Handle);
  9.   Registre.WriteInteger('FirstFormHandle', Form1.Handle);
  10.   Registre.CloseKey;
  11.   Registre.Free;
  12. except
  13.   MessageDlg('Se ha producido un error al escribir en el Registro de Windows.',
  14.     mtError, [mbOk], 0);
  15.   Registre.Free;
  16. end;
  17.  
  18. Application.Run;



La aplicación ya se encuentra en ejecución. Si la aplicación ya está en ejecución, no sirve de nada lanzarla de nuevo, es decir, tenemos que parar la carga de ésta. Pero antes de terminarla, tendremos que mostrar la primera instancia. Es ahora cuando los datos almacenados en el Registro de Windows servirán para su identificación.
Lo primero que tenemos que hacer es buscar los 2 handles dentro del Registro. Una vez conseguidos estos valores, se podrá dar el foco al formulario de la primera instancia. Esto lo lograremos gracias a 2 funciones del API de Windows, ShowWindow(hWnd: HWND; nCmdShow: Integer): BOOL y SetForegroundWindow(hWnd: HWND): BOOL.



delphi
  1. Registre := TRegistry.Create;
  2. try
  3.   Registre.RootKey := HKEY_CLASSES_ROOT;
  4.   Registre.OpenKey('\Software\nombre_de_la_llave', True);
  5.   FirstApplicationHandle := Registre.ReadInteger('FirstApplicationHandle');
  6.   FirstFormHandle := Registre.ReadInteger('FirstFormHandle');
  7.   ShowWindow(FirstApplicationHandle, SW_NORMAL);
  8.   SetForegroundWindow(FirstFormHandle);
  9.   Registre.CloseKey;
  10.   Registre.Free;
  11. except
  12.   MessageDlg('Se ha producido un error al leer el Registro de Windows.',
  13.     mtError, [mbOk], 0);
  14.   Registre.Free;
  15. end;



Nota: se aconseja limpiar el Registro de Windows al terminar la ejecución del programa