Hello!
I see 4 windows on the monitor (for example), but EnumWindows gives me more than a dozen - some incomprehensible windows that are not on the screen at all. They names are something like "Microsoft Text Input Application, Microsoft Store, etc"
IsVisible returns true, IsIconic returns false, GetWindowsRect return some rect with non-zero width and heights. So, how I can filter them ?? For now all what I can do - to get image with PrintWindow and to see it is totally black, but this way looks like a gag not solution :)
My task is simple - to get screenshot for all windows on the screen one by one, but it is not very good for me to get additional 10 black rectangles.
To be more informative: OS - Windows10
What I have tried:
class OpenWindowsGetter [DllImport( " USER32.DLL" )] static extern bool EnumWindows(EnumWindowsProc enumFunc, int lParam); [DllImport( " USER32.DLL" )] static extern int GetWindowText( IntPtr hWnd, StringBuilder lpString, int nMaxCount); [DllImport( " USER32.DLL" )] static extern int GetWindowTextLength( IntPtr hWnd); [DllImport( " USER32.DLL" )] static extern bool IsWindowVisible( IntPtr hWnd); [DllImport( " USER32.DLL" )] static extern IntPtr GetShellWindow(); [DllImport( " User32.dll" )] static extern bool IsIconic( IntPtr hwnd); delegate bool EnumWindowsProc( IntPtr hWnd, int lParam); /// < summary > Returns a dictionary that contains the handle and title of all opened windows. < /summary > /// < returns > A dictionary that contains the handle and title of all opened windows. < /returns > public static IDictionary<IntPtr, string> GetOpenWindows() IntPtr lShellWindow = GetShellWindow(); Dictionary<IntPtr, string> lWindows = new Dictionary<IntPtr, string>(); EnumWindows( delegate ( IntPtr hWnd, int lParam) if (hWnd == lShellWindow) return true ; if (!IsWindowVisible(hWnd)) return true ; if (IsIconic(hWnd)) return true ; int lLength = GetWindowTextLength(hWnd); if (lLength == 0 ) return true ; StringBuilder lBuilder = new StringBuilder(lLength); GetWindowText(hWnd, lBuilder, lLength + 1 ); lWindows[hWnd] = lBuilder.ToString(); return true ; }, 0 ); return lWindows; And to see a result with combobox WindsCB:
private void button1_Click( object sender, EventArgs e) WindsCB.Items.Clear(); IDictionary<IntPtr, string> winds = OpenWindowsGetter.GetOpenWindows(); foreach ( var item in winds) WindsCB.Items.Add(item);
I do not think there is much you can do. The system itself uses its own Windows for various purposes so you will always get them returned. You can only work on the information provided from the Window's handle.

And the remarks section for the IsWindowVisible function (winuser.h) - Win32 apps | Microsoft Docs [ ^ ] function states:
The visibility state of a window is indicated by the WS_VISIBLE style bit. When WS_VISIBLE is set, the window is displayed and subsequent drawing into it is displayed as long as the window has the WS_VISIBLE style.
Any drawing to a window with the WS_VISIBLE style will not be displayed if the window is obscured by other windows or is clipped by its parent window.
	
About your remarks - do not know why, but with winapi's PrintWindow I get an image from obscured windows w\o problems.

public static Bitmap WindImage(IntPtr hwnd)
{
GetWindowRect(hwnd, out RECT rect);
Bitmap image = new Bitmap(rect.Right - rect.Left, rect.Bottom - rect.Top);
using (var graphics = Graphics.FromImage(image))
{
var hdcBitmap = graphics.GetHdc();
PrintWindow(hwnd, hdcBitmap, 0);
graphics.ReleaseHdc(hdcBitmap);
}
return image;
}

So my problem not in "I can not get what I want", but "I get too much!!!" LOL :))) thanks for your answers anyway!
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; // x position of upper-left corner public int Top; // y position of upper-left corner public int Right; // x position of lower-right corner public int Bottom; // y position of lower-right corner [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.
  • Read the question carefully.
  • Understand that English isn't everyone's first language so be lenient of bad spelling and grammar.
  • If a question is poorly phrased then either ask for clarification, ignore it, or edit the question and fix the problem. Insults are not welcome.
  • Don't tell someone to read the manual. Chances are they have and don't get it. Provide an answer or move on to the next question. Let's work to help developers, not make them feel stupid.
  •