Cómo pasar a primer plano una aplicación instanciada por segunda vez
Artículo por Club Developers · 31 diciembre 2005
6163 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:
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:
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.
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.
Nota: se aconseja limpiar el Registro de Windows al terminar la ejecución del programa
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
begin  if IsPrevInstance = 0 then  begin   Application.Initialize;   Application.CreateForm(TMDIForm, MDIForm); [...]   Application.Run;  end  else   ShowInstance(IsPrevInstance); 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
function IsPrevInstance: HWND; var  ClassName: array[0..255] of char;  Title: string; begin  Title := Application.Title;  Application.Title := '';  { Cambiamos el tÃtulo porque sino encontrarÃamos siempre una aplicación en marcha, la nuestra }  try   GetClassName(Application.Handle, ClassName, 255);   { Ponemos en ClassName el nombre de la clase de la aplicación }   Result := FindWindow(ClassName, PChar(Title));   { Devuelve el Handle de la 1era ventana de Class (Type) ClassName y con el mismo tÃtulo }  finally   Application.Title := Title; { Restauramos el verdadero tÃtulo }  end; end; procedure ShowInstance(InstHandle: HWND); begin  { Restauramos aplicación si está minimizada }  ShowWindow(InstHandle, SW_RESTORE);  { Poner la 1era instancia en 1er plano }  SetForegroundWindow(InstHandle);  { Finalizamos la 2da instancia }  Application.Terminate; 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
Application.Initialize; Application.CreateForm(TForm1, Form1); Registre := TRegistry.Create; try  Registre.RootKey := HKEY_CLASSES_ROOT;  Registre.OpenKey('\Software\nombre_de_la_llave', True);  Registre.WriteInteger('FirstApplicationHandle', Application.Handle);  Registre.WriteInteger('FirstFormHandle', Form1.Handle);  Registre.CloseKey;  Registre.Free; except  MessageDlg('Se ha producido un error al escribir en el Registro de Windows.',   mtError, [mbOk], 0);  Registre.Free; end; 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
Registre := TRegistry.Create; try  Registre.RootKey := HKEY_CLASSES_ROOT;  Registre.OpenKey('\Software\nombre_de_la_llave', True);  FirstApplicationHandle := Registre.ReadInteger('FirstApplicationHandle');  FirstFormHandle := Registre.ReadInteger('FirstFormHandle');  ShowWindow(FirstApplicationHandle, SW_NORMAL);  SetForegroundWindow(FirstFormHandle);  Registre.CloseKey;  Registre.Free; except  MessageDlg('Se ha producido un error al leer el Registro de Windows.',   mtError, [mbOk], 0);  Registre.Free; end;
Nota: se aconseja limpiar el Registro de Windows al terminar la ejecución del programa