【问题标题】:Form tells wrong size on Windows 8 — how to get real size?窗体在 Windows 8 上显示错误的尺寸 - 如何获得真实尺寸?
【发布时间】:2013-05-05 07:02:47
【问题描述】:

在 Windows 8 上将表单边框样式设置为 Sizable 的 WinForms 表单,DesktopBounds property 告诉正确的值:

相比之下,当表单边框样式为FixedDialog时,值是错误的:

在 Windows XP 上,这些值总是正确的:

我的问题是:

如何获取包含完整非客户区的窗口的实际大小?

更新 1:

好像和this SO question有关。我会尝试看看这是否也能解决我的问题。

更新 2:

为了完整起见,以下是 VMware Windows 7 的结果:

更新 3:

终于找到了一个解决方案,将DwmGetWindowAttribute function 与DWMWA_EXTENDED_FRAME_BOUNDS value 一起使用。我将在下面发布答案。

【问题讨论】:

  • 如果您仔细观察,Windows XP 会表现出相同的行为。只是 Windows 边框是单个像素宽,而不是 Windows 8 中的五个像素(在 XP 中 Fixed 和 Sizable 之间的差异是 2,而在 Windows 8 中是 10)。
  • 是什么让您假设尺寸错误?如果您在更改 FormBorderStyle 时查看 Visual Studio 设计器,您实际上会看到它缩小了
  • @JustinNiessner 是的,我确实看到了; Windows XP 版本返回的尺寸实际上仍然反映了实际的表单大小,而在 Windows 8 上,它们不会。
  • 在 Windows 10 上,如果您在窗口首次被绘制到屏幕之前调用 DwmGetWindowAttribute() 和 DWMWA_EXTENDED_FRAME_BOUNDS(例如,为了在屏幕上正确放置一个新窗口),那么您将获得与GetWindowRect() 相同的结果 - 即包括不可见的边框。您必须等到窗口被渲染后才能给出正确的结果。

标签: c# .net winforms windows-8 windows-xp


【解决方案1】:

为了回答我自己的问题,我终于找到了一个解决方案,它涉及将DwmGetWindowAttribute function 与DWMWA_EXTENDED_FRAME_BOUNDS value 一起使用

答案的灵感来自this source code,它提供了一个似乎适用于所有系统的功能。核心是一个函数:

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

完整代码如下:

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

【讨论】:

  • 我正在使用与此非常相似的代码,并发现在许多高 DPI 显示的情况下,API 函数只返回 0 并回退到 GetWindowRect() 调用。
  • 该来源似乎已移至此处:github.com/ShareX/ShareX/blob/…
【解决方案2】:

我不认为“错误”是正确的表达方式。你看到的价值观是你不理解的,但这并不总是与错误相同。真正的问题是您试图通过获取窗口边界来解决的实际问题是什么?

你试过Win32GetWindowRect的方法吗?我想知道这表明了什么。

您可以尝试的一种方法是检测操作系统并解决这些问题。

要确定 C# 中的操作系统:http://support.microsoft.com/kb/304283(该示例没有具体提及 Windows 8,但我认为 SDK 已针对它进行了更新)

【讨论】:

  • 谢谢。您将如何进行操作系统切换?我无法想象一种计算真实值的方法。即使在检查了SystemInformation 属性之后。
  • 刚刚试过GetWindowRect,它返回完全相同的值。
  • 编辑了有关如何确定操作系统的信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-07
  • 1970-01-01
  • 2019-12-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多