Search code examples
c#.netwinformswindows-8windows-xp

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


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

enter image description here

In contrast, when having a form border style of FixedDialog, the values are wrong:

enter image description here

On Windows XP, the values are always correct:

enter image description here

enter image description here

My question is:

How to get the real size of a Window including the complete non-client area?

Update 1:

Seems that it is related to this SO question. I'll try and see whether this would solve my issue here, too.

Update 2:

Just for completeness, here are the results from a VMware Windows 7:

enter image description here

enter image description here

Update 3:

Finally found a solution which involves using the DwmGetWindowAttribute function together with the DWMWA_EXTENDED_FRAME_BOUNDS value. I'll post an answer below.


Solution

  • 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();
        }
    }