DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2下WM_GETDPISCALEDSIZE未触发咨询
DPI感知窗口跨显示器移动时WM_GETDPISCALEDSIZE消息缺失问题分析
问题核心
你创建了基于DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2的WinAPI应用,在两台分辨率相同但缩放比例分别为100%和150%的显示器间移动窗口时,发现有时只收到WM_DPICHANGED消息,而非预期的先WM_GETDPISCALEDSIZE后WM_DPICHANGED的消息序列。
原因拆解
窗口最大化状态的影响
你的代码中,窗口创建时指定了WS_MAXIMIZE样式,并且立即调用ShowWindow(hwnd, SW_SHOWMAXIMIZED)让窗口处于最大化状态。当最大化窗口跨DPI显示器移动时,系统会直接接管窗口尺寸调整,适配目标显示器的最大化规格,这个流程不会触发WM_GETDPISCALEDSIZE——该消息的设计目的是让应用在窗口处于正常(非最大化/非最小化)状态下,自定义调整缩放后的窗口尺寸,只有这种场景才会触发。系统消息触发逻辑
根据WinAPI官方定义,WM_GETDPISCALEDSIZE仅在两个条件同时满足时发送:
- 窗口位置变化导致其所在显示器的DPI发生变更
- 窗口处于可自由调整尺寸的状态(正常状态)
如果窗口是最大化或最小化,系统会跳过应用自定义尺寸的环节,直接发送WM_DPICHANGED通知DPI变更完成。
代码修正与验证
针对你的测试代码,调整以下两点即可复现预期的消息序列:
- 移除窗口样式中的
WS_MAXIMIZE,保留可最大化的按钮(WS_MAXIMIZEBOX)即可:
DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME; // 去掉WS_MAXIMIZE
- 将窗口显示方式改为正常状态,而非直接最大化:
ShowWindow(hwnd, SW_SHOW); // 替换SW_SHOWMAXIMIZED
修改后,先确保窗口处于正常非最大化状态,再跨显示器移动,就能按预期先收到WM_GETDPISCALEDSIZE,再收到WM_DPICHANGED。
额外注意事项
- 如果窗口仅部分区域跨到不同DPI的显示器(而非整个窗口切换到目标显示器),系统也可能不会发送
WM_GETDPISCALEDSIZE,只有当窗口的主要显示区域切换到新DPI显示器时,才会触发完整的消息序列。 - 确认测试环境为Windows 10 1709及以上版本,
PER_MONITOR_AWARE_V2在更早版本中存在兼容性问题。
内容的提问来源于stack exchange,提问作者Irbis
相关产品推荐
相关产品推荐

