How to check if window is really visible in Windows Forms?

后端 未结 9 1377
小蘑菇
小蘑菇 2020-12-30 09:59

Normally you use Form.Visible to check if Window is visible at all. But sometimes on the screen window is below other windows so it\'s really invisible.

So how to ch

9条回答
  •  不思量自难忘°
    2020-12-30 10:30

    I googled trough the web, but coudn't find any straight answer to see if a part of a window is truly visible to the user. I actually needed a way to "hittest" the form, if the mouse is currently on top of the visible part of the window. I thought I'd share the code which took several days to accomplish:

    public class VisibilityTester
    {
        private delegate bool CallBackPtr(int hwnd, int lParam);
        private static CallBackPtr callBackPtr;
    
        /// 
        /// The enumerated pointers of actually visible windows
        /// 
        public static List enumedwindowPtrs = new List();
        /// 
        /// The enumerated rectangles of actually visible windows
        /// 
        public static List enumedwindowRects = new List();
    
        /// 
        /// Does a hit test for specified control (is point of control visible to user)
        /// 
        /// the rectangle (usually Bounds) of the control
        /// the handle for the control
        /// the point to test (usually MousePosition)
        /// a control or window to exclude from hit test (means point is visible through this window)
        /// boolean value indicating if p is visible for ctrlRect
        public static bool HitTest(Rectangle ctrlRect, IntPtr ctrlHandle, Point p, IntPtr ExcludeWindow)
        {
            // clear results
            enumedwindowPtrs.Clear();
            enumedwindowRects.Clear();
    
            // Create callback and start enumeration
            callBackPtr = new CallBackPtr(EnumCallBack);
            EnumDesktopWindows(IntPtr.Zero, callBackPtr, 0);
    
            // Go from last to first window, and substract them from the ctrlRect area
            Region r = new Region(ctrlRect);
    
            bool StartClipping = false;
            for (int i = enumedwindowRects.Count - 1; i >= 0; i--)
            {
                if (StartClipping && enumedwindowPtrs[i] != ExcludeWindow)
                {
                    r.Exclude(enumedwindowRects[i]);
                }
    
                if (enumedwindowPtrs[i] == ctrlHandle) StartClipping = true;
            }
    
            // return boolean indicating if point is visible to clipped (truly visible) window
            return r.IsVisible(p);
        }
    
        /// 
        /// Window enumeration callback
        /// 
        private static bool EnumCallBack(int hwnd, int lParam)
        {
            // If window is visible and not minimized (isiconic)
            if (IsWindow((IntPtr)hwnd) && IsWindowVisible((IntPtr)hwnd) && !IsIconic((IntPtr)hwnd))
            { 
                // add the handle and windowrect to "found windows" collection
                enumedwindowPtrs.Add((IntPtr)hwnd);
    
                RECT rct;
    
                if (GetWindowRect((IntPtr)hwnd, out rct))
                {
                    // add rect to list
                    enumedwindowRects.Add(new Rectangle(rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top));
                }
                else
                {
                    // invalid, make empty rectangle
                    enumedwindowRects.Add(new Rectangle(0, 0, 0, 0));
                }
            }
    
            return true;
        }
    
    
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool IsWindowVisible(IntPtr hWnd);
    
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool IsWindow(IntPtr hWnd);
    
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool IsIconic(IntPtr hWnd);
    
        [DllImport("user32.dll")]
        private static extern int EnumDesktopWindows(IntPtr hDesktop, CallBackPtr callPtr, int lPar);
    
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
    
        [StructLayout(LayoutKind.Sequential)]
        private 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
    
            public override string ToString()
            {
                return Left + "," + Top + "," + Right + "," + Bottom;
            }
        }
    }
    

提交回复
热议问题