Form tells wrong size on Windows 8 — how to get real size?

前端 未结 2 1355
抹茶落季
抹茶落季 2020-12-10 08:07

Having a WinForms form with form border style set to Sizable on Windows 8, the DesktopBounds property tells the correct values:

相关标签:
2条回答
  • 2020-12-10 08:20

    To answer my own question, I finally found a solution which involves using the DwmGetWindowAttribute function together with the DWMWA_EXTENDED_FRAME_BOUNDS value

    The answer was inspired by this source code which presents a function that seems to work on all system. The core is a function:

    public static Rectangle GetWindowRectangle(IntPtr handle)
    {
        if (Environment.OSVersion.Version.Major < 6)
        {
            return GetWindowRect(handle);
        }
        else
        {
            Rectangle rectangle;
            return DWMWA_EXTENDED_FRAME_BOUNDS(handle, out rectangle) 
                       ? rectangle 
                       : GetWindowRect(handle);
        }
    }
    

    Full code is provided below:

    public static class WindowHelper
    {
        // https://code.google.com/p/zscreen/source/browse/trunk/ZScreenLib/Global/GraphicsCore.cs?r=1349
    
        /// <summary>
        /// Get real window size, no matter whether Win XP, Win Vista, 7 or 8.
        /// </summary>
        public static Rectangle GetWindowRectangle(IntPtr handle)
        {
            if (Environment.OSVersion.Version.Major < 6)
            {
                return GetWindowRect(handle);
            }
            else
            {
                Rectangle rectangle;
                return DWMWA_EXTENDED_FRAME_BOUNDS(handle, out rectangle) ? rectangle : GetWindowRect(handle);
            }
        }
    
        [DllImport(@"dwmapi.dll")]
        private static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out Rect pvAttribute, int cbAttribute);
    
        private enum Dwmwindowattribute
        {
            DwmwaExtendedFrameBounds = 9
        }
    
        [Serializable, StructLayout(LayoutKind.Sequential)]
        private struct Rect
        {
            // ReSharper disable MemberCanBePrivate.Local
            // ReSharper disable FieldCanBeMadeReadOnly.Local
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
            // ReSharper restore FieldCanBeMadeReadOnly.Local
            // ReSharper restore MemberCanBePrivate.Local
    
            public Rectangle ToRectangle()
            {
                return Rectangle.FromLTRB(Left, Top, Right, Bottom);
            }
        }
    
        private static bool DWMWA_EXTENDED_FRAME_BOUNDS(IntPtr handle, out Rectangle rectangle)
        {
            Rect rect;
            var result = DwmGetWindowAttribute(handle, (int)Dwmwindowattribute.DwmwaExtendedFrameBounds,
                out rect, Marshal.SizeOf(typeof(Rect)));
            rectangle = rect.ToRectangle();
            return result >= 0;
        }
    
        [DllImport(@"user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool GetWindowRect(IntPtr hWnd, out Rect lpRect);
    
        private static Rectangle GetWindowRect(IntPtr handle)
        {
            Rect rect;
            GetWindowRect(handle, out rect);
            return rect.ToRectangle();
        }
    }
    
    0 讨论(0)
  • 2020-12-10 08:39

    I don't think "wrong" is quite the right way to put it.. you are seeing values you don't understand, but that's not always the same as wrong. The real question is what is the actual problem you are trying to solve by getting the window bounds?

    Have you tried the Win32 GetWindowRect method? I wonder what that shows.

    One hack you could try would be to detect the OS and account for these.

    To determine the OS in C#: http://support.microsoft.com/kb/304283 (that sample doesn't mention Windows 8 specifically, but I assume the SDK has been updated for it)

    0 讨论(0)
提交回复
热议问题