WM_DPICHANGED异常及跨显示器DPI获取不符问题求助
解决Per-Monitor DPI感知的两个常见问题
嘿,我来帮你拆解这两个DPI感知的问题,都是新手入门时容易踩的坑,咱们一步步来搞定:
1. 应用启动时收到WPARAM/LPARAM全为0的WM_DPICHANGED消息
这种情况其实是系统在应用初始化阶段发送的预通知消息,此时窗口还没完全完成创建和初始化,参数自然是空的。你只需要在消息处理逻辑里加个判断就能跳过:
case WM_DPICHANGED: if (wParam == 0 && lParam == 0) { // 忽略初始化阶段的空参数消息 return DefWindowProc(hWnd, msg, wParam, lParam); } // 正常处理DPI变更逻辑 // ... break;
另外要确认你已经正确设置了Per-Monitor DPI感知上下文,Win10 1607及以上版本推荐用:
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
避免使用旧的SetProcessDPIAware(),它会强制应用为系统DPI感知,导致Per-Monitor模式失效。
2. GetDeviceCaps始终返回固定DPI,无法获取对应显示器的正确值
GetDeviceCaps(hDC, LOGPIXELSX/LOGPIXELSY)的局限性在于它依赖于你传入的设备上下文(DC):如果你的DC是从主窗口或默认屏幕获取的,它只会返回主显示器的DPI值,根本不会感知当前窗口所在的显示器。
解决办法是使用Win10引入的Per-Monitor DPI专用API:
方法1:直接获取窗口所在显示器的DPI
用GetDpiForWindow可以直接拿到窗口当前所在显示器的DPI,简单高效:
UINT dpi = GetDpiForWindow(hWnd); // dpi就是当前窗口所在显示器的DPI值(比如144对应150%,168对应175%)
方法2:获取指定显示器的DPI
如果需要更精细的控制,先拿到窗口对应的显示器句柄,再调用GetDpiForMonitor:
HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST); UINT dpiX, dpiY; GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY); // dpiX和dpiY就是目标显示器的水平/垂直DPI
记得要包含头文件Shcore.h,并链接Shcore.lib才能使用这些API。
另外可以额外验证:用GetWindowRect获取窗口的位置,确认窗口确实位于175%缩放的显示器上,避免窗口跨屏导致的判断误差。
内容的提问来源于stack exchange,提问作者Martin Lemburg
相关产品推荐
相关产品推荐

