getdpiforwindow是windows 10 1607+/11获取窗口dpi缩放比最直接可靠的方式,返回dpi值需除以96换算为缩放比例(如192→2.0),但要求进程声明dpiawareness(推荐permonitorv2)、窗口已创建且有效,并配合wm_dpichanged响应及坐标缩放处理。

Windows平台用GetDpiForWindow获取窗口DPI缩放比
在Windows 10 1607+和Windows 11上,GetDpiForWindow是获取高DPI缩放比例最直接、最可靠的方式。它返回的是每英寸点数(DPI),不是百分比;需换算成缩放比例:比如192 DPI对应200%(192 ÷ 96 = 2.0)。
注意:该函数要求进程已声明DPI感知(否则始终返回默认96)。未声明时即使系统设为150%,也拿不到真实值。
- 必须在
manifest中设置dpiAwareness="system"或"permonitorv2"(推荐后者) - 调用前确保窗口已创建且句柄有效(
HWND不能为NULL) - 若目标窗口跨多显示器且缩放不同,
GetDpiForWindow返回当前显示器的DPI(per-monitor aware才生效) - 示例:
int dpi = GetDpiForWindow(hwnd); double scale = static_cast<double>(dpi) / 96.0; // 得到1.25、1.5、2.0等</double>
兼容旧系统时回退用GetDeviceCaps + GetDC
对Windows 8.1或未启用Per-Monitor DPI支持的老程序,GetDpiForWindow可能不可用或返回96。此时可用GDI方式估算主显示器缩放:
- 调用
GetDC(NULL)获取屏幕DC,再用GetDeviceCaps(hdc, LOGPIXELSX)读取X方向DPI - 结果仍需除以96得到缩放系数,但该值仅反映主显示器,且无法感知窗口实际所在屏
- 必须配对调用
ReleaseDC(NULL, hdc),否则资源泄漏 - 在多显示器不同缩放场景下会出错——比如窗口在150%屏,但函数返回主屏100%的值
C++跨平台?别硬搞,Linux/macOS没有“系统级DPI缩放比”概念
macOS用的是逻辑像素(points)与设备像素(pixels)分离机制,没有Windows那种全局“125%缩放”设置;Linux桌面环境(GNOME/KDE)缩放由Wayland/X11协议层、Qt/GTK工具包各自处理,不存在统一系统API。
所以C++原生代码里试图写一个get_system_dpi_scale()跨平台函数,注定失败:
- macOS只能通过
NSScreen的backingScaleFactor拿到当前屏的设备像素比(如2.0),但它不等于“系统缩放设置”,也不受用户在“显示器设置”里调的“更大文本”影响 - Linux下
Xft.dpi或gdk_screen_get_monitor_scale_factor()只适用于特定GUI栈,纯控制台程序根本无从获取 - 强行封装会导致行为不一致:Windows返回1.5,macOS返回2.0,Linux返回1.0——数值不可比,也不能用于布局计算
容易被忽略的关键点:DPI感知声明必须匹配实际使用方式
很多开发者加了permonitorv2 manifest,却在窗口创建后没处理WM_DPICHANGED消息,导致窗口缩放后UI元素错位、字体模糊。
真正要让缩放生效,三件事缺一不可:
- manifest中正确设置
dpiAwareness(推荐permonitorv2) - 响应
WM_DPICHANGED:调整窗口大小、重设字体、重绘控件布局 - 所有GDI/DC操作(如
TextOut、StretchBlt)都需按当前DPI缩放坐标和尺寸,不能硬编码像素值
漏掉任意一项,GetDpiForWindow返回的值就只是个数字,起不到适配作用。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











