Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 405
Uwe Keim Avatar asked May 10 '13 14:05

Uwe Keim


1 Answers

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();
    }
}
like image 136
Uwe Keim Avatar answered Nov 06 '22 01:11

Uwe Keim