Get Window State of Another Process

Get window state of another process

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.

How to detect is a window of another process minimized or maximized?

It's only a part of the solution. If you know the title of the other window:

Process process = Process.GetProcesses().Where(p => p.MainWindowTitle == "Title of window").SingleOrDefault();
if (process != null) {
IntPtr wHnd = process.MainWindowHandle;
Console.WriteLine("Minimized: " + IsIconic(wHnd));
}

and:

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

Get window state change notifications from another pocess

Here's a sample that should get you started:

AutomationElement windowElement = AutomationElement.FromHandle(WindowHandle);
if(windowElement != null)
{
System.Windows.Automation.Automation.AddAutomationPropertyChangedEventHandler(
windowElement,
System.Windows.Automation.TreeScope.Element, this.handlePropertyChange,
System.Windows.Automation.AutomationElement.BoundingRectangleProperty);
}

private void handlePropertyChange(object src, System.Windows.Automation.AutomationPropertyChangedEventArgs e)
{
if(e.Property == System.Windows.Automation.AutomationElement.BoundingRectangleProperty)
{
System.Windows.Rect rectangle = e.NewValue as System.Windows.Rect;
//Do other stuff here
}
}

You should probably call System.Windows.Automation.Automation.RemoveAllEventHandlers after you're done listening to the window's events.
This is just a very basic sample of course. Guy Barker seems to be the best authority on this library and has provided quite a few samples. He suggests using the native version instead of the managed one but each version has its drawbacks. For your purposes it seems the Managed version should do.

C#: capture windowstate changes of another application (wrote in c/c++ i think)

//use this in a timer or hook the window
//this would be the easier way
using System;
using System.Runtime.InteropServices;

public static class WindowState
{
[DllImport("user32")]
private static extern int IsWindowEnabled(int hWnd);

[DllImport("user32")]
private static extern int IsWindowVisible(int hWnd);

[DllImport("user32")]
private static extern int IsZoomed(int hWnd);

[DllImport("user32")]
private static extern int IsIconic(int hWnd);

public static bool IsMaximized(int hWnd)
{
if (IsZoomed(hWnd) == 0)
return false;
else
return true;
}

public static bool IsMinimized(int hWnd)
{
if (IsIconic(hWnd) == 0)
return false;
else
return true;
}

public static bool IsEnabled(int hWnd)
{
if (IsWindowEnabled(hWnd) == 0)
return false;
else
return true;
}

public static bool IsVisible(int hWnd)
{
if (IsWindowVisible(hWnd) == 0)
return false;
else
return true;
}

}

How to get the window state of a C++ console application

For Windows use GetConsoleWindow to get a handle to the window, then e.g. GetWindowPlacement.

But what on Earth are you planning to use this information for?

How to get window station for a given process?

Not straight forward, but try this:

  1. Call EnumWindowStations() to enumerate available window stations in the same Session as the calling process (if you need to query a process in another Session then this will not work).

  2. For each window station, call EnumDesktops() to enumerate its desktops.

  3. For each desktop, call EnumDesktopWindows() to enumerate its top-level windows.

  4. For each window, call GetWindowThreadProcessId() to get its process ID and compare it to the ID you are looking for.

Another option might be to do the following:

  1. Call OpenProcess() to get a HANDLE from the target process ID.

  2. Call NtQueryInformationProcess() to retrieve the address of the process's PEB structure.

  3. Call ReadProcessMemory() to read the PEB. It's ProcessParams.DesktopName field contains the name of the workstation/desktop currently associated with the process (there are many more fields available in the PEB.ProcessParams then what MSDN shows).

  4. Parse the DesktopName to extract the window station and desktop names.

  5. Enumerate workstations as needed, looking for a matching name from GetUserObjectInformation().

Set the window state of a hidden window

The problem with notepad is that it has 3 windows (spy++, class names):

1. "Notepad"
2. "MSCTFIME UI"
3. "IME"

you are getting the handle of the second one (I got anyway), MSCTFIME UI, thats why you can't show it. You need to specify the class name Notepad to get the correct handle:

pHandle = FindWindowEx(IntPtr.Zero, pHandle, "Notepad", Nothing)

Maximize another process' Window in .NET

You can pinvoke to ShowWindow with SW_SHOWMAXIMIZED to maximize the window.

Pinvoke.net has an entry for ShowWindow here.

For example,

// Pinvoke declaration for ShowWindow
private const int SW_SHOWMAXIMIZED = 3;

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

// Sample usage
ShowWindow(proc.MainWindowHandle, SW_SHOWMAXIMIZED);

Restore a minimized window of another application

... 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.



Related Topics



Leave a reply



Submit