getdpiforwindow用于获取指定窗口的dpi值(如96、120、144),除以96得缩放系数;需传入有效hwnd,返回0表示失败,跨屏时应改用getdpiformonitor配合monitorfromwindow。

Windows平台用GetDpiForWindow获取窗口关联DPI缩放系数
在Windows 10 1703+(RS2)及以上版本,推荐用GetDpiForWindow获取与特定窗口绑定的DPI值,它返回的是每英寸像素数(如96、120、144),再除以96即得缩放系数(1.0、1.25、1.5)。这个API比旧的GetDeviceCaps更准确,尤其在多显示器混合缩放场景下。
注意:必须传入一个有效的窗口句柄(HWND),不能传NULL;若窗口尚未创建或已销毁,会返回96(即1.0)——这容易误判为“无缩放”,实际是调用失败。
- 确保窗口已成功创建且
IsWindow(hwnd)返回TRUE - 若需主屏缩放系数但无窗口,可用
MonitorFromPoint+GetDpiForMonitor替代 - 返回值是UINT,不是float;缩放系数需显式计算:
static_cast<double>(dpi) / 96.0</double>
跨显示器时必须用GetDpiForMonitor而非GetDpiForWindow
当窗口跨多个显示器(比如拖到200%缩放的副屏上),GetDpiForWindow仍只返回原始创建屏幕的DPI。真正反映当前显示区域缩放的,是GetDpiForMonitor——它需要先通过MonitorFromWindow或MonitorFromPoint拿到目标HMONITOR,再传入获取。
常见错误是直接对GetDesktopWindow()调用GetDpiForWindow,结果永远只读取主屏DPI,忽略用户把程序拖到高缩放副屏的实际情况。
-
GetDpiForMonitor要求链接shcore.lib,并在编译时定义WINVER≥ 0x0A00 - 返回的DPI类型应指定为
MDT_EFFECTIVE_DPI(推荐),避免用MDT_DEFAULT_DPI(过时) - 若
GetDpiForMonitor返回E_INVALIDARG,大概率是HMONITOR无效,需检查MonitorFromWindow是否返回NULL
Windows 7/8兼容方案:用GetDeviceCaps配合GetDC
在不支持GetDpiForWindow的老系统上,只能退回到GDI方式:用GetDC(NULL)获取屏幕DC,再调用GetDeviceCaps查LOGPIXELSX。但它返回的是系统级全局DPI,无法感知多显示器差异,且在远程桌面或高DPI模拟模式下可能不准。
- 必须配对调用
ReleaseDC(NULL, hdc),否则资源泄漏 - 该方法始终返回主显示器DPI,即使程序运行在副屏上也不会更新
- 若应用启用了
SetProcessDpiAwarenessContext(如DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2),此方法结果可能与实际渲染不一致
Qt或wxWidgets等框架内不要绕过封装直接调Windows API
Qt 5.14+ 提供QScreen::devicePixelRatio(),返回浮点缩放因子(如2.0);wxWidgets 3.1.6+ 有wxDisplay::GetScaleFactor()。这些封装已处理了DPI感知模式切换、多屏边界、动态缩放通知等细节。
手动调用GetDpiForWindow可能和框架内部状态冲突——比如Qt在QApplication初始化前调用会崩溃,或在QScreen未就绪时返回错误值。
- 优先使用框架提供的接口,除非你明确需要绕过框架做底层渲染适配
- Qt中
devicePixelRatio()返回的是逻辑像素比物理像素的比值,和Windows的“DPI / 96”数值一致 - wxWidgets需确保
wxDisplay对象构造时传入正确屏幕索引,否则默认返回主屏
真正麻烦的不是获取那个数字,而是它随时可能变——用户热插拔显示器、调整缩放设置、甚至远程连接时DPI都会突变。所以别只在启动时读一次,得监听WM_DPICHANGED或框架对应的缩放变更事件。否则界面文字突然模糊或控件错位,用户根本不知道问题出在哪。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











