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:
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).For each window station, call
EnumDesktops()
to enumerate its desktops.For each desktop, call
EnumDesktopWindows()
to enumerate its top-level windows.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:
Call
OpenProcess()
to get aHANDLE
from the target process ID.Call
NtQueryInformationProcess()
to retrieve the address of the process'sPEB
structure.Call
ReadProcessMemory()
to read thePEB
. It'sProcessParams.DesktopName
field contains the name of the workstation/desktop currently associated with the process (there are many more fields available in thePEB.ProcessParams
then what MSDN shows).Parse the
DesktopName
to extract the window station and desktop names.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
Detect Windows Font Size (100%, 125%, and 150%)
Wpf Binding - Default Value for Empty String
Automatically Rename a File If It Already Exists in Windows Way
Encrypting/Decrypting Large Files (.Net)
Using a List as a Data Source for Datagridview
Wpf How to Access Control from Datatemplate
How to Secure Passwords Stored Inside Web.Config
Does Dispose Still Get Called When Exception Is Thrown Inside of a Using Statement
How to Create Trial Version of .Net Software
When Is It Ok to Catch an Outofmemoryexception and How to Handle It
Is There a Synchronization Class That Guarantee Fifo Order in C#
Why Is This Process Crashing as Soon as It Is Launched
How to Add Moving Effects to My Controls in C#
The Connection Was Not Closed the Connection's Current State Is Open