Why does DwmGetWindowAttribute with DWMWA_EXTENDED_FRAME_BOUNDS behave unexpectedly when switching monitors?

余生长醉 提交于 2020-05-15 09:58:05

问题


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
  • Form.Size
  • GetWindowRect()

But the value returned by DwmGetWindowAttribute with DWMWA_EXTENDED_FRAME_BOUNDS changes drastically.

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

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?

To Reproduce:

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

回答1:


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.



来源:https://stackoverflow.com/questions/49002910/why-does-dwmgetwindowattribute-with-dwmwa-extended-frame-bounds-behave-unexpecte

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!