Restaurer une fenêtre réduite d’une autre application

J’ajoute du code à une application qui lancera une autre application si elle n’est pas déjà lancée ou si c’est le cas, amenez-la au premier plan. Cela nécessite une petite quantité de code interop / WinAPI, pour lequel j’ai obtenu des exemples d’autres sites, mais qui ne semblent pas fonctionner correctement sous Win7.

Si la fenêtre est dans un état visible, la méthode SetForegroundWindow de l’API fonctionne comme un traitement (et ce serait le cas principal. Selon la stratégie de la société, si l’application externe est en cours d’exécution, elle ne doit pas être minimisée). Cependant, si elle est réduite au minimum (exceptionnelle mais importante car mon application semblera ne rien faire dans ce cas), ni cette méthode, ni ShowWindow / ShowWindowAsync ne permettront en réalité de faire remonter la fenêtre de la barre des tâches. toutes les méthodes mettent simplement en surbrillance le bouton de la barre des tâches.

Voici le code; la plupart fonctionnent parfaitement, mais l’appel à ShowWindow () (j’ai également essayé ShowWindowAsync) ne fait jamais ce que je veux, peu importe la commande que j’envoie:

[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 restore 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; } 

J’ai essayé SHOWNORMAL (1), SHOWMAXIMIZED (3), RESTORE (9) et quelques autres commandes de dimensionnement, mais rien ne semble pouvoir faire l’affaire. Pensées?

EDIT: J’ai trouvé un problème avec certains des autres codes que je croyais efficaces. L’appel à GetProcessesByName () n’a pas trouvé le processus car je cherchais le nom de l’exécutable, qui n’était pas le nom du processus. Cela a provoqué le code que je pensais être en cours d’exécution et en échec pour ne pas exécuter du tout. Je pensais que cela fonctionnait, car l’application externe détectera apparemment aussi qu’une copie est déjà en cours d’exécution et tente d’activer cette instance actuelle. J’ai supprimé le fichier “.exe” du nom du processus que je recherche et le code est maintenant exécuté; cependant, cela semble être un retour en arrière, car le bouton de la barre des tâches n’est même pas mis en surbrillance lorsque j’appelle ShowWindow [Async]. Donc, je sais maintenant que ni mon application, ni l’application externe que j’appelle, ne peut modifier l’état de la fenêtre d’une instance différente par programme dans Win7. Qu’est-ce qui se passe ici?

Code de travail utilisant la méthode FindWindow :

 [DllImport("user32.dll")] public static extern IntPtr FindWindow(ssortingng className, ssortingng 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 restore it ShowWindow(wdwIntPtr, ShowWindowEnum.Restore); } //set user's focus to the window SetForegroundWindow(wdwIntPtr); } 

Vous pouvez l’utiliser en appelant BringWindowToFront() .

J’ai toujours une instance de l’application en cours d’exécution, donc si vous pouvez avoir plusieurs instances ouvertes simultanément, vous voudrez peut-être légèrement modifier la logique.

… Apparemment, vous ne pouvez pas faire confiance aux informations fournies par un processus.

Process.MainWindowHandle renvoie le descripteur de fenêtre de la première fenêtre créée par l’application, qui est généralement la fenêtre principale de niveau supérieur de cette application. Cependant, dans mon cas, un appel à FindWindow () indique que le descripteur de la fenêtre que je souhaite restaurer n’est pas celui sur lequel MainWindowHandle pointe. Il semble que le handle de fenêtre du processus, dans ce cas, soit celui de l’écran de démarrage affiché lorsque le programme charge le formulaire principal.

Si j’appelle ShowWindow sur la poignée renvoyée par FindWindow, cela fonctionne parfaitement.

Ce qui est encore plus inhabituel, c’est que, lorsque la fenêtre est ouverte, l’appel de SetForegroundWindow (), lorsqu’il reçoit le processus MainWindowHandle (qui devrait être invalide car cette fenêtre s’est fermée), fonctionne correctement. Donc, évidemment, cette poignée a une certaine validité, mais pas lorsque la fenêtre est réduite.

En résumé, si vous vous trouvez dans une situation difficile, appelez FindWindow en lui transmettant le nom connu de la fenêtre principale de votre application externe, pour obtenir le descripteur dont vous avez besoin.

J’ai eu le même problème. La meilleure solution que j’ai trouvée consiste à appeler ShowWindow avec l’indicateur SW_MINIMIZE , puis avec SW_RESTORE . :RÉ

Une autre solution possible:

 // 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, restore it if it was minimized SetForegroundWindow(hWnd); // Finally, activate the window 

à partir de commentaires sur: http://msdn.microsoft.com/en-us/library/ms633548%28VS.85%29.aspx

Plateau appelant ShowWindow (descripteur, SW_RESTORE); après SetForegroundWindow (handle);

Cela pourrait résoudre votre problème.