Perhaps, instead of checking all windows, you could check all processes with an existing MainWindowHandle.
Therefore, prepare your "User32" class:
[StructLayout(LayoutKind.Sequential)]
public struct RECT {
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll", CharSet=CharSet.Unicode)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
[DllImport("user32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
public static extern IntPtr GetShellWindow();
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(IntPtr hWnd, [Out] out RECT lpRect);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsWindowVisible(IntPtr hWnd);
Now get all main window handles:
HashSet<IntPtr> allHandles = new HashSet<IntPtr>();
foreach (Process process in Process.GetProcesses().Where(x => x.MainWindowHandle != IntPtr.Zero)) {
allHandles.Add(process.MainWindowHandle);
}
You also need to add one special logic to find all explorer windows:
IntPtr explorerHandle = IntPtr.Zero;
while (IntPtr.Zero != (explorerHandle = User32.FindWindowEx(IntPtr.Zero, explorerHandle, "CabinetWClass", null))) {
allHandles.Add(explorerHandle);
}
You likely need to get some special windows you need to skip/filter out:
IntPtr hShellWnd = User32.GetShellWindow();
IntPtr hDefView = User32.FindWindowEx(hShellWnd, IntPtr.Zero, "SHELLDLL_DefView", null);
IntPtr folderView = User32.FindWindowEx(hDefView, IntPtr.Zero, "SysListView32", null);
IntPtr taskBar = User32.FindWindowEx(IntPtr.Zero, IntPtr.Zero, "Shell_TrayWnd", null);
HashSet<IntPtr> ForbiddenWindows = new HashSet<IntPtr>();
ForbiddenWindows.Add(hShellWnd);
ForbiddenWindows.Add(hDefView);
ForbiddenWindows.Add(folderView);
ForbiddenWindows.Add(taskBar);
Now, filter all handles to get the relevant handles:
HashSet<IntPtr> relevantHandles = new HashSet<IntPtr>();
foreach (IntPtr handle in allHandles) {
if (handle != IntPtr.Zero && User32.IsWindowVisible(handle) && !ForbiddenWindows.Contains(handle) && !relevantHandles.Contains(handle)) {
User32.RECT rect = new User32.RECT();
bool locChecked = User32.GetWindowRect(handle, out rect);
Rectangle area = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
if (locChecked && area.X > -1 && area.Width > 0 && area.Height > 0) {
relevantHandles.Add(handle);
}
}
}
Furthermore, instead of checking for area.X, area.Width and area.Height you could implement a check if the window area is contained by any screens workarea. Also be aware, that the size of maximized windows can exceed the size of the workarea (and even the screen bounds when the taskbar is hidden) by 4 to every direction.