Restaurar una ventana minimizada de otra aplicación

Estoy agregando un código a una aplicación que lanzará otra aplicación si aún no se está ejecutando, o si lo está, llévela al frente. Esto requiere una pequeña cantidad de código de interoperabilidad / WinAPI, del que he obtenido ejemplos de otros sitios, pero parece que no puedo ponerme a trabajar en Win7.

Si la ventana está en algún estado visible, entonces el método SetForegroundWindow de la API funciona como un lujo (y este sería el caso principal, según la política de la compañía si la aplicación externa no se debe minimizar). Sin embargo, si se minimiza (excepcional pero importante, ya que parece que mi aplicación no hará nada en este caso), ni este método ni ShowWindow / ShowWindowAsync realmente recuperarán la ventana desde la barra de tareas; todos los métodos simplemente resaltan el botón de la barra de tareas.

Aquí está el código; la mayor parte funciona bien, pero la llamada a ShowWindow () (también probé ShowWindowAsync) nunca hace lo que yo quiero, sin importar qué comando envíe:

[DllImport("user32.dll")] private static extern int SetForegroundWindow(IntPtr hWnd); private const int SW_SHOWNORMAL = 1; private const int SW_SHOWMAXIMIZED = 3; private const int SW_RESTORE = 9; [DllImport("user32.dll")] private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); ... //The app is named uniquely enough that it can't be anything else, //and is not normally launched except by this one. //so this should normally return zero or one instance var processes = Process.GetProcessesByName("ExternalApp.exe"); if (processes.Any()) //a copy is already running { //I can't currently tell the window's state, //so I both restre and activate it var handle = processes.First().MainWindowHandle; ShowWindow(handle, SW_RESTORE); //GRR!!! SetForegroundWindow(handle); return true; } try { //If a copy is not running, start one. Process.Start(@"C:\Program Files (x86)\ExternalApp\ExternalApp.exe"); return true; } catch (Exception) { //fallback for 32-bit OSes Process.Start(@"C:\Program Files\ExternalApp\ExternalApp.exe"); return true; } 

Intenté con SHOWNORMAL (1), SHOWMAXIMIZED (3), RESTORE (9) y un par de otros comandos de tamaño, pero nada parece funcionar. ¿Pensamientos?

EDIT: encontré un problema con el otro código que creía que estaba funcionando. La llamada a GetProcessesByName () no encontraba el proceso porque estaba buscando el nombre del ejecutable, que no era el nombre del proceso. Eso causó que el código que yo pensaba que se estaba ejecutando fallara y no se ejecutara en absoluto. Pensé que estaba funcionando porque la aplicación externa también detectará aparentemente que ya se está ejecutando una copia e intentará activar esa instancia actual. Dejé caer el “.exe” del nombre del proceso que busco y ahora el código se ejecuta; sin embargo, eso parece ser un paso atrás, ya que ahora el botón de la barra de tareas ni siquiera se resalta cuando llamo a ShowWindow [Async]. Entonces, ahora sé que ni mi aplicación, ni la aplicación externa a la que estoy recurriendo, pueden cambiar el estado de la ventana de una instancia diferente programáticamente en Win7. ¿Qué está pasando aquí?

Código de trabajo utilizando el método FindWindow :

 [DllImport("user32.dll")] public static extern IntPtr FindWindow(string className, string windowTitle); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool ShowWindow(IntPtr hWnd, ShowWindowEnum flags); [DllImport("user32.dll")] private static extern int SetForegroundWindow(IntPtr hwnd); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool GetWindowPlacement(IntPtr hWnd, ref Windowplacement lpwndpl); private enum ShowWindowEnum { Hide = 0, ShowNormal = 1, ShowMinimized = 2, ShowMaximized = 3, Maximize = 3, ShowNormalNoActivate = 4, Show = 5, Minimize = 6, ShowMinNoActivate = 7, ShowNoActivate = 8, Restore = 9, ShowDefault = 10, ForceMinimized = 11 }; private struct Windowplacement { public int length; public int flags; public int showCmd; public System.Drawing.Point ptMinPosition; public System.Drawing.Point ptMaxPosition; public System.Drawing.Rectangle rcNormalPosition; } private void BringWindowToFront() { IntPtr wdwIntPtr = FindWindow(null, "Put_your_window_title_here"); //get the hWnd of the process Windowplacement placement = new Windowplacement(); GetWindowPlacement(wdwIntPtr, ref placement); // Check if window is minimized if (placement.showCmd == 2) { //the window is hidden so we restre it ShowWindow(wdwIntPtr, ShowWindowEnum.Restore); } //set user's focus to the window SetForegroundWindow(wdwIntPtr); } 

Puede usarlo llamando a BringWindowToFront() .

Siempre tengo una instancia de la aplicación en ejecución, así que si puede tener varias instancias abiertas simultáneamente, es posible que desee cambiar ligeramente la lógica.

… Al parecer, no puede confiar en la información que le proporciona un Proceso.

Process.MainWindowHandle devuelve el identificador de ventana de la primera ventana creada por la aplicación, que normalmente es la ventana principal de nivel superior de esa aplicación. Sin embargo, en mi caso, una llamada a FindWindow () muestra que el manejador de la ventana real que quiero restaurar no es a lo que MainWindowHandle apunta. Parece que el identificador de ventana del Proceso, en este caso, es el de la pantalla de bienvenida que se muestra cuando el progtwig carga el formulario principal.

Si llamo a ShowWindow en el manejador que FindWindow devolvió, funciona perfectamente.

Lo que es aún más inusual es que cuando la ventana está abierta, la llamada a SetForegroundWindow (), cuando se le da MainWindowHandle del proceso (que debería ser inválida cuando esa ventana se cerró), funciona bien. Entonces, obviamente, ese mango tiene ALGUNA validez, pero no cuando la ventana está minimizada.

En resumen, si se encuentra en una situación difícil, llame a FindWindow, pasándole el nombre conocido de la ventana principal de su aplicación externa, para obtener el identificador que necesita.

Yo tuve el mismo problema. La mejor solución que he encontrado es llamar a ShowWindow con el indicador SW_MINIMIZE , y luego con SW_RESTORE . :RE

Otra posible solución:

 // Code to display a window regardless of its current state ShowWindow(hWnd, SW_SHOW); // Make the window visible if it was hidden ShowWindow(hWnd, SW_RESTORE); // Next, restre it if it was minimized SetForegroundWindow(hWnd); // Finally, activate the window 

de los comentarios en: http://msdn.microsoft.com/en-us/library/ms633548%28VS.85%29.aspx

Bandeja llamando a ShowWindow (handle, SW_RESTORE); después de SetForegroundWindow (handle);

Esto podría resolver su problema.