问题
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