窗体在Windows 8上显示错误的大小 – 如何获得实际大小?

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

在此处输入图像描述

相反,当具有FixedDialog的表单边框样式时,值是错误的:

在此处输入图像描述

在Windows XP上,值始终是正确的:

在此处输入图像描述

在此处输入图像描述

我的问题是:

如何获得一个窗口的实际大小,包括完整的非客户区域?

更新1:

似乎它与这个SO问题有关 。 我会试着看看这是否能在这里解决我的问题。

更新2:

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

在此处输入图像描述

在此处输入图像描述

更新3:

最后找到了一个解决方案,它涉及将DwmGetWindowAttribute函数与DWMWA_EXTENDED_FRAME_BOUNDS值一起使用。 我将在下面发布一个答案。

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

答案的灵感来自于这个源代码 ,它提供了一个似乎适用于所有系统的function。 核心是一个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); } } 

完整代码如下:

 public static class WindowHelper { // https://code.google.com/p/zscreen/source/browse/trunk/ZScreenLib/Global/GraphicsCore.cs?r=1349 ///  /// Get real window size, no matter whether Win XP, Win Vista, 7 or 8. ///  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(); } } 

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

你试过Win32 GetWindowRect方法吗? 我不知道那是什么。

你可以尝试的一个黑客是检测操作系统并解释这些问题。

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