为什么在切换监视器时

为什么在切换监视器时

本文介绍了为什么在切换监视器时 DwmGetWindowAttribute 和 DWMWA_EXTENDED_FRAME_BOUNDS 的行为异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我的 WinForm 应用程序从主监视器移动到辅助监视器时,这些属性和 winapi 函数返回的边界(窗口的高度和宽度)值不会改变:

When my WinForm application is moved from a primary monitor to a secondary monitor, the bounds (Height and Width of the Window) value returned by these properties and winapi function does not change :

  • Form.Bounds
  • 形式.大小
  • GetWindowRect()

但是 DwmGetWindowAttributeDWMWA_EXTENDED_FRAME_BOUNDS 返回的值发生了巨大的变化.

But the value returned by DwmGetWindowAttribute with DWMWA_EXTENDED_FRAME_BOUNDS changes drastically.

根据评论的建议进行例如,在主监视器中 DwmgetWindowAttribute 返回宽度和高度 292, 100 和其他值返回 306, 107.考虑到投影占用 7 个像素,这是连贯的.但是当窗口移动到辅助监视器时,DwmgetWindowAttribute返回437, 150,其他方法返回相同的306, 107

Edits after suggestion from comments: For instance, in the primary monitor DwmgetWindowAttribute returns a rect of width and height 292, 100 and the other values return 306, 107. This is coherent considering the drop shadow takes up 7 pixels. But when the window is moved to the secondary monitor, DwmgetWindowAttribute returns 437, 150 and the other methods return the same 306, 107

事实上,我的两台显示器的分辨率都是 1920 * 1080(但如果重要的话,比例会有所不同)

In fact both my monitors are of resolution 1920 * 1080 (but the scale differs though if it matters)

问题:为什么会这样?是只有我还是其他人遇到过类似的问题?最终我想计算阴影大小.还有其他办法吗?

Question: Why does this happen this way? Is it only me or have anyone else faced similar issues? Ultimately I want to calculate the drop shadow size. Is there any other way?

复制:

如果您希望重现此内容,请创建一个 winform 项目.在构造函数中使用 AllocConsole() 分配控制台.为 LocationChanged 添加一个事件处理程序,并将以下代码添加到事件处理程序中:

If you wish to reproduce this, create a winform project. Allocate console using AllocConsole() in the constructor. Add an event handler for LocationChanged and add the following code to the event handler:

private void AgentMainForm_LocationChanged(object sender, EventArgs e)
{
      Console.WriteLine("bounds: {0}, {1}", Bounds.Width, Bounds.Height);
      Console.WriteLine("Size: {0}, {1}", Size.Width, Size.Height);
      Console.WriteLine("Window Rect: {0}, {1}", GetSizeWithShadow().Width, GetSizeWithShadow().Height);
      Console.WriteLine("Window Rect: {0}, {1}", GetSizeWithoutShadow().Width, GetSizeWithoutShadow().Height);
}

[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);

[DllImport("dwmapi.dll")]
public static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out RECT pvAttribute, int cbAttribute);

public Size GetSizeWithoutShadow()
{
      RECT regionWithoutShadow;
      IntPtr hWnd = this.Handle;
      if (Environment.OSVersion.Version.Major < 6) //DwmGetWindowAttribute does not work in XP, compatible only from Vista
      {
            GetWindowRect(hWnd, out regionWithoutShadow);
      }
      else
      {
            if (DwmGetWindowAttribute(hWnd, DWMWA_EXTENDED_FRAME_BOUNDS, out regionWithoutShadow, Marshal.SizeOf(typeof(RECT))) != 0)
            {
                 //Handle for failure
            }
      }

      return new Size(regionWithoutShadow.right - regionWithoutShadow.left, regionWithoutShadow.bottom - regionWithoutShadow.top);
}

public Size GetSizeWithShadow()
{
     RECT regionWithoutShadow;
     IntPtr hWnd = this.Handle;

     GetWindowRect(hWnd, out regionWithoutShadow);

     return new Size(regionWithoutShadow.right - regionWithoutShadow.left, regionWithoutShadow.bottom - regionWithoutShadow.top);
}

[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
    public int left;
    public int top;
    public int right;
    public int bottom;
}

推荐答案

您得到这个答案是因为您的 DPI 比例在一台显示器上为 1.5,在另一台显示器上为 1.0.可以使用 GetDpiForWindow.

You get this answer because your DPI scale is 1.5 on one monitor and 1.0 on the other. It might be possible to reconcile using GetDpiForWindow.

这篇关于为什么在切换监视器时 DwmGetWindowAttribute 和 DWMWA_EXTENDED_FRAME_BOUNDS 的行为异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!