GetDpiForSystem返回系统基准DPI(通常96),非当前显示器缩放值;应使用GetDpiForWindow获取窗口所在屏DPI并响应WM_DPICHANGED消息,macOS需Objective-C++调用NSScreen backingScaleFactor。

Windows平台下用GetDpiForSystem获取系统级DPI缩放比例
Windows 10 1703+ 和 Windows 11 默认启用Per-Monitor DPI,但GetDpiForSystem返回的是全局系统DPI(通常为96),它不反映当前显示器的实际缩放值,仅适合粗略判断是否启用了高DPI支持。调用前需确保链接User32.lib,且函数在winuser.h中声明。
常见误用是把它当作当前屏幕DPI——实际它忽略多显示器差异,返回的是“系统基准DPI”,不是缩放比例。真正有意义的缩放比例应通过每显示器DPI计算:scale = dpi / 96.0。
- 返回值是整数DPI(如120、144、192),不是百分比(125%对应120 DPI)
- 若程序未声明
manifest支持DPI感知,该函数可能始终返回96 - 必须在启用DPI感知模式后调用才可靠:在manifest中设置
dpiAware="true"或调用SetProcessDpiAwareness
获取当前窗口所在显示器的DPI:用GetDpiForWindow而非GetDpiForMonitor
GetDpiForWindow是Windows 10 1607+推荐方式,直接传入窗口句柄HWND,自动定位其主显示器并返回该屏DPI。它比GetDpiForMonitor更简单、更健壮——后者需先调用MonitorFromWindow再查HMONITOR,容易因跨屏拖动导致缓存失效。
注意:该函数返回的是逻辑DPI,即操作系统为该窗口分配的渲染DPI,已考虑缩放、文本缩放、DPI虚拟化等策略。不要自行用GetDeviceCaps(hdc, LOGPIXELSX)替代,后者在DPI感知进程里可能被截断或返回错误值。
立即学习“C++免费学习笔记(深入)”;
- 必须确保窗口已创建且
HWND有效,否则返回0 - 若窗口尚未完成DPI适配(例如刚创建、尚未处理
WM_DPICHANGED),可能返回旧DPI - 返回值可直接用于计算缩放因子:
float scale = GetDpiForWindow(hwnd) / 96.0f;
响应DPI变化:必须处理WM_DPICHANGED消息
用户拖动窗口到不同DPI显示器、或手动调整缩放比例时,系统会向窗口发送WM_DPICHANGED。不处理它会导致UI元素模糊、布局错位、鼠标坐标偏移——这是高DPI适配中最常被忽略的环节。
该消息的wParam是新DPI值(整数),lParam低32位是建议的新窗口矩形(RECT*)。你必须用这个矩形调整窗口大小,否则系统可能强制缩放导致失真。
- 不能只更新字体/尺寸而不重设窗口区域;忽略
lParam会导致窗口被裁剪或溢出 - 需要重新计算所有基于像素的布局(如按钮宽高、字体大小、图像缩放倍率)
- 如果使用Direct2D或GDI+,还需调用
SetDpi或重建资源(如ID2D1Factory::MakeScaledDpi) - 务必调用
DefWindowProc,否则系统无法完成DPI切换流程
macOS上通过NSScreen获取缩放因子,但C++需桥接Objective-C++
C++原生无跨平台DPI API,macOS必须用Objective-C++混编。核心是获取当前主屏或窗口所在屏的[NSScreen backingScaleFactor],它返回浮点缩放因子(1.0、2.0、3.0等),对应@1x/@2x/@3x分辨率。
不能用[NSScreen frame]和[NSScreen visibleFrame]差值推算——它们已按缩放因子转换为点(points),不是像素。真正像素密度需结合backingScaleFactor与点坐标计算。
- 必须将文件扩展名改为
.mm并启用Objective-C++编译(Clang/GCC加-x objective-c++) - 需链接
AppKit.framework,并在代码中#import <appkit></appkit> - 多显示器场景下,用
[NSScreen screenWithMouseLocation]或[window screen]获取关联屏,避免硬编码主屏 - macOS没有“系统级缩放比例”概念,每个屏独立缩放,且不提供类似Windows的96 DPI基准
跨平台项目别指望一套C++代码通吃;Windows靠WinAPI,macOS靠AppKit桥接,Linux则依赖X11/Wayland协议或GTK/Qt抽象层——DPI配置从来就不是纯C++问题,而是平台集成问题。


















