Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Restore a minimized window of another application

Tags:

I'm adding some code to an app that will launch another app if it isn't already running, or if it is, bring it to the front. This requires a small amount of interop/WinAPI code, which I've gotten examples for from other sites but can't seem to get to work in Win7.

If the window is in some visible state, then the API's SetForegroundWindow method works like a treat (and this would be the main case, as per company policy if the external app is running it should not be minimized). However, if it is minimized (exceptional but important as my app will appear to do nothing in this case), neither this method nor ShowWindow/ShowWindowAsync will actually bring the window back up from the taskbar; all of the methods simply highlight the taskbar button.

Here's the code; most of it works just fine, but the call to ShowWindow() (I've also tried ShowWindowAsync) just never does what I want it to no matter what the command I send is:

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

I've tried SHOWNORMAL (1), SHOWMAXIMIZED (3), RESTORE (9), and a couple other sizing commands, but nothing seems to do the trick. Thoughts?

EDIT: I found an issue with some of the other code I had thought was working. The call to GetProcessesByName() was not finding the process because I was looking for the executable name, which was not the process name. That caused the code I thought was running and failing to actually not execute at all. I thought it was working because the external app will apparently also detect that a copy is already running and try to activate that current instance. I dropped the ".exe" from the process name I search for and now the code executes; however that seems to be a step backwards, as now the taskbar button isn't even highlighted when I call ShowWindow[Async]. So, I now know that neither my app, nor the external app I'm invoking, can change the window state of a different instance programmatically in Win7. What's goin' on here?

like image 768
KeithS Avatar asked Feb 01 '12 16:02

KeithS


People also ask

How do I get a minimized window back?

5. And use Windows logo key + Shift + M to restore all minimized windows.

How do you bring up a program that has been minimized?

Press WinKey+Up/Down arrow key and see. Press Alt+Space and see if the Maximize/Restore/Minimize, etc, box appears. If it does, use it.

Where does the window go when it is minimized?

In recent versions of Microsoft Windows, the minimize button is represented by an underscore or dash in the top-right corner of the window. When minimized, the program remains on the taskbar, but not visible.


2 Answers

Working code using FindWindow method:

[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 restore it         ShowWindow(wdwIntPtr, ShowWindowEnum.Restore);     }      //set user's focus to the window     SetForegroundWindow(wdwIntPtr); } 

You can use it by calling BringWindowToFront().

I always have one instance of the application running so if you can have several open instances simultaneously you might want to slightly change the logic.

like image 88
Ivan Yurchenko Avatar answered Oct 18 '22 15:10

Ivan Yurchenko


... Apparently you cannot trust the information a Process gives you.

Process.MainWindowHandle returns the window handle of the first window created by the application, which is USUALLY that app's main top-level window. However, in my case, a call to FindWindow() shows that the handle of the actual window I want to restore is not what MainWindowHandle is pointing to. It appears that the window handle from the Process, in this case, is that of the splash screen shown as the program loads the main form.

If I call ShowWindow on the handle that FindWindow returned, it works perfectly.

What's even more unusual is that when the window's open, the call to SetForegroundWindow(), when given the process's MainWindowHandle (which should be invalid as that window has closed), works fine. So obviously that handle has SOME validity, just not when the window's minimized.

In summary, if you find yourself in my predicament, call FindWindow, passing it the known name of your external app's main window, to get the handle you need.

like image 35
KeithS Avatar answered Oct 18 '22 14:10

KeithS