getdpiforwindow是windows 10 1703+获取窗口dpi的推荐方式,返回整数型dpi值(如120表示120%),需hwnd且实时有效;跨显示器应配合monitorfromwindow和getdpiformonitor;无窗口程序只能用getdpiforsystem(不实时)。

Windows平台用GetDpiForWindow获取当前窗口DPI缩放值
Windows 10 1703+ 支持 per-monitor DPI,GetDpiForWindow 是最直接、推荐的方式。它返回逻辑像素到物理像素的缩放比例(如 120 表示 120%,即 1.2x),不是百分比字符串,也不是缩放因子的小数形式——而是整数型 DPI 值(默认 96,125% → 120,150% → 144,175% → 168,200% → 192)。
关键点:
-
GetDpiForWindow需要窗口句柄(HWND),不能用于无窗口程序(如控制台);若在 UI 线程调用且窗口已创建,结果实时有效 - 必须链接
User32.lib,并在编译时定义WINVER≥ 0x0A00(即 Windows 10) - 返回值是每英寸点数(DPI),换算为缩放因子需除以 96.0:例如
static_cast<double>(dpi) / 96.0</double> - 该函数不触发 DPI 变更通知,仅读取当前状态;若需响应缩放变化(如窗口拖到另一显示器),应监听
WM_DPICHANGED消息
跨显示器场景下用GetDpiForMonitor配合MonitorFromWindow
单个窗口可能跨越多个显示器,而每个显示器可设置不同缩放比例。GetDpiForWindow 返回的是主监视器 DPI(或窗口所在主区域的 DPI),不够精确。更稳妥的做法是先定位窗口所属主显示器,再查其 DPI:
实操步骤:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 调用
MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST)获取最近显示器句柄(HMONITOR) - 传入该
HMONITOR调用GetDpiForMonitor(hmon, MDT_EFFECTIVE_DPI, &dpiX, &dpiY),推荐用MDT_EFFECTIVE_DPI(等效 DPI,含系统级缩放与文本缩放叠加效果) -
GetDpiForMonitor要求 Windows 8.1+,且需链接Shcore.lib;dpiX和dpiY通常相等,取其一即可 - 注意:该函数返回的是“有效 DPI”,会反映用户在「设置 > 显示 > 缩放与布局」中开启的“让文本和其他项目变大”全局滑块影响,比单纯系统缩放更贴近实际渲染行为
控制台程序或无窗口场景只能用GetDpiForSystem(但不实时)
没有 HWND 的程序(如命令行工具、后台服务)无法使用前两个 API,只能退而求其次调用 GetDpiForSystem。它返回系统级默认 DPI(通常是主显示器的缩放值),但有严重限制:
- 该值在进程启动时确定,**不会随系统缩放设置动态更新**;即使用户中途修改了显示缩放,已运行的进程仍返回旧值
- 它不感知多显示器差异,始终返回主显示器的 DPI
- 适用于初始化阶段粗略适配(如计算字体大小基准),但不能用于实时 UI 布局或图像缩放决策
- 若真需要控制台程序响应缩放变化,唯一可行路径是轮询注册表(
HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics下的AppliedDPI值),但微软明确不支持此方式,且不包含 per-monitor 信息
常见错误:混淆SetProcessDpiAwareness和实际DPI读取
很多开发者以为只要调用 SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE) 就能“自动获得正确 DPI”,这是误解。该函数只影响系统如何向你的进程提供坐标和消息(比如是否缩放 WM_SIZE 中的尺寸),**并不改变你读取 DPI 的方式,也不自动刷新 DPI 值**。
典型坑点:
- 未调用
SetProcessDpiAwareness就直接读 DPI,可能拿到被系统“兼容缩放”干扰的值(尤其是高 DPI 模式下运行非 DPI 感知程序) - 调用了
PROCESS_SYSTEM_DPI_AWARE后误以为能跨显示器适配——其实它只对主显示器生效,副屏仍按主屏 DPI 渲染,导致模糊 - 在
WM_CREATE或构造函数里读一次 DPI 就缓存起来,后续窗口移动、缩放变更后不再刷新,UI 元素错位或模糊 - C++/CLI 或 Qt 等封装层可能内部已处理 DPI 感知,重复调用
SetProcessDpiAwareness会失败(返回E_ACCESSDENIED),应优先检查框架自身 DPI 接口
真正可靠的实时 DPI 获取,永远依赖窗口上下文 + 正确的 API 组合 + 对 WM_DPICHANGED 的响应。没有“一劳永逸”的全局变量可读——DPI 是显示器属性,不是系统属性。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










