14

How do I get the window state(maximized, minimized) of another process that's running?

I'd tried by using this:

Process[] procs = Process.GetProcesses();

        foreach (Process proc in procs)
        {

            if (proc.ProcessName == "notepad")
            {
                MessageBox.Show(proc.StartInfo.WindowStyle.ToString());

            }
        }

But if process is Maximized or Minimized,it ever returns Normal.

How to fix this?

Jack
  • 16,276
  • 55
  • 159
  • 284

4 Answers4

31

You’ll need to use Win32 through P/Invoke for checking the state of another window. Here is some sample code:

static void Main(string[] args)
{
    Process[] procs = Process.GetProcesses();

    foreach (Process proc in procs)
    {
        if (proc.ProcessName == "notepad")
        {
            var placement = GetPlacement(proc.MainWindowHandle);
            MessageBox.Show(placement.showCmd.ToString());
        }
    }
}

private static WINDOWPLACEMENT GetPlacement(IntPtr hwnd)
{
    WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
    placement.length = Marshal.SizeOf(placement);
    GetWindowPlacement(hwnd, ref placement);
    return placement;
}

[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetWindowPlacement(
    IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);

[Serializable]
[StructLayout(LayoutKind.Sequential)]
internal struct WINDOWPLACEMENT
{
    public int length;
    public int flags;
    public ShowWindowCommands showCmd;
    public System.Drawing.Point ptMinPosition;
    public System.Drawing.Point ptMaxPosition;
    public System.Drawing.Rectangle rcNormalPosition;
}

internal enum ShowWindowCommands : int
{
    Hide = 0,
    Normal = 1,
    Minimized = 2,
    Maximized = 3,
}

Definition courtesy of pinvoke.net.

Douglas
  • 53,759
  • 13
  • 140
  • 188
  • 1
    In my case, `showCmd` is always the original value, and stays the same, even if `ShowWindow(showCmd != 1)` is called, `GetWindowPlacement` still returns `showCmd = 1` in the `WINDOWPLACEMENT` structure. So is it literally about the moment the window is 'placed'? – Mike de Klerk Aug 28 '13 at 05:02
  • 1
    Remember to add the reference to `System.Drawing` – LazerSharks Mar 13 '16 at 03:59
8

You're using proc.StartInfo, which is incorrect. It does not reflect the runtime window style of the target process. It is just startup info you can set and can then be passed on to the process when it starts up.

The C# signature is:

[DllImport("user32.dll", SetLastError=true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);

You need to use p/invoke and call GetWindowLong(hWnd, GWL_STYLE), and pass proc.MainWindowHandle as the hWnd parameter.

You can check if the window is minimized/maximized by doing something like:

int style = GetWindowLong(proc.MainWindowHandle,  GWL_STYLE);
if((style & WS_MAXIMIZE) == WS_MAXIMIZE) 
{
   //It's maximized
} 
else if((style & WS_MINIMIZE) == WS_MINIMIZE) 
{
  //It's minimized
}

NOTE: The values for the flags (WS_MINIMIZE, etc), can be found in this page: http://www.pinvoke.net/default.aspx/user32.getwindowlong

Thanks to Kakashi for pointing our the error in testing the result.

Marcel N.
  • 13,726
  • 5
  • 47
  • 72
  • 1
    Don't forget to that C#.NET accepts only boolean expressions in if/for/while-statements. If you want to check `WS_MAXIMIZE` sliced value from `style` is itself, by using `&` you should do `(style & WS_MAXIMIZE) == WS_MAXIMIZE`. – Kakashi Jun 16 '12 at 16:46
  • 1
    And also necessary `()` or you will get `Operator '&' cannot be applied to operands of type 'int' and 'bool'` – Kakashi Jun 16 '12 at 16:58
  • @marceln: see this picture: http://www.thoosje.com/Images/optimizer-screenshot-1.jpg how is called this window state? – Jack Jun 16 '12 at 18:17
  • I would say that is the normal state. What state do you get from winapi? – Marcel N. Jun 16 '12 at 18:19
  • I can't get name because it's an `int` not a `C# enum` type. Only the value of. That's `349110272`. But how is defined normal state in WS_* windows styles? – Jack Jun 16 '12 at 18:31
  • Then that would be WS_VISIBLE. And it's correct too. You have WS_VISIBLE=0x10000000 and your value in hex is 0x14CF0000. The result of WS_VISIBLE & 0x14CF0000 is WS_VISIBLE, so that's the state. – Marcel N. Jun 16 '12 at 18:45
  • Err, no. "Normal" state is the absence of either `WS_MAXIMIZED` or `WS_MINIMIZED`. `WS_VISIBLE` only means it is not hidden, it does not mean "normal". In particular `WS_VISIBLE` is also set for minimized and maximized windows. – Ben Voigt Sep 29 '20 at 15:08
5

In Windows PowerShell you can do this by following code:

Add-Type -AssemblyName UIAutomationClient
$prList = Get-Process -Name "<ProcessNamesWhichHaveWindow>"
$prList | % {
    try {
        $ae = [System.Windows.Automation.AutomationElement]::FromHandle($_.MainWindowHandle)
        $wp = $ae.GetCurrentPattern([System.Windows.Automation.WindowPatternIdentifiers]::Pattern)
        echo "Window title: $($_.MainWindowTitle)"
        echo "Window visual state: $($wp.Current.WindowVisualState)"
    }
    catch { }
}
Ladislav
  • 320
  • 3
  • 10
3

Two Window States (maximized / minimized) can be gotten by calling WinAPI IsIconic() / IsZoomed() like this:

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool IsIconic(IntPtr hWnd);

    [DllImport("user32.dll")]
    public static extern bool ShowWindowAsync(IntPtr hWnd, ShowWindowCommands cmdShow);

    if (IsIconic(_helpWindow.MainWindowHandle)) {
        ShowWindowAsync(_helpWindow.MainWindowHandle, ShowWindowCommands.SW_RESTORE);
    }

Definition of enum ShowWindowCommands and other functions were taken from www.PInvoke.net

Mic
  • 105
  • 1
  • 6