主显示器缩放超100%时GetMonitorInfo返回副屏尺寸错误导致无框WPF窗口最大化溢出
问题原因
这个问题是WPF默认的DPI感知机制和Windows的DPI虚拟化逻辑共同导致的:
- 你的程序默认仅开启了系统级DPI感知,而非逐显示器级DPI感知。这种模式下Windows会统一以主显示器的缩放比例作为全局标准,所有外接显示器的坐标、尺寸都会经过主显示器缩放比例换算后再返回给程序接口。
- 你主显示器缩放为250%,调用
GetMonitorInfo获取副屏尺寸时,Windows返回的数值是按2.5倍放大后的逻辑尺寸,远大于副屏2560x1440的实际物理分辨率,因此最大化后窗口会超出显示范围。 - 主显示器缩放设为100%时换算比例为1,返回的尺寸和实际尺寸一致,窗口就能正常显示。
修复方案
1. 开启逐显示器DPI感知
这是最根本的解决方法,在项目中添加应用程序清单(app.manifest),加入如下配置:
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <!-- 其他已有配置 --> <application xmlns="urn:schemas-microsoft-com:asm.v3"> <windowsSettings> <!-- 兼容Win7及以上系统的逐显示器DPI感知 --> <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware> <!-- Win10 1703及以上系统推荐使用PerMonitorV2,支持动态DPI切换、弹出菜单缩放等特性 --> <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness> </windowsSettings> </application> </assembly>
开启该配置后,GetMonitorInfo会直接返回当前所在显示器的真实物理坐标,无需额外换算即可正常最大化。
2. 手动做DPI换算(可选,兼容旧系统)
如果需要兼容不支持逐显示器DPI感知的旧系统,可以补充DPI换算逻辑,先获取当前显示器的缩放比例再对坐标做修正:
首先在FormMaximize类中添加DPI获取的API声明:
[DllImport("User32.dll")] internal static extern uint GetDpiForMonitor(IntPtr hmonitor, int dpiType, out uint xDpi, out uint yDpi); private const int MDT_EFFECTIVE_DPI = 0;
然后修改WmGetMinMaxInfo方法中的尺寸计算逻辑:
if (monitor != IntPtr.Zero) { MonitorInfo monitorInfo = new MonitorInfo(); GetMonitorInfo(monitor, monitorInfo); // 获取当前显示器的有效DPI计算缩放比例 GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, out uint xDpi, out uint yDpi); double scaleFactor = xDpi / 96.0; Rectangle workArea = monitorInfo.WorkArea; Rectangle monitorArea = monitorInfo.MonitorArea; // 按比例修正坐标和尺寸 minmaxInfo.MaxPosition.X = (int)Math.Round(Math.Abs(workArea.Left - monitorArea.Left) / scaleFactor); minmaxInfo.MaxPosition.Y = (int)Math.Round(Math.Abs(workArea.Top - monitorArea.Top) / scaleFactor); minmaxInfo.MaxSize.X = (int)Math.Round(Math.Abs(workArea.Right - workArea.Left) / scaleFactor); minmaxInfo.MaxSize.Y = (int)Math.Round(Math.Abs(workArea.Bottom - workArea.Top) / scaleFactor); }
内容的提问来源于stack exchange,提问作者mottosson
相关产品推荐
相关产品推荐

