You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取不受Windows显示缩放影响的显示器真实像素分辨率

Windows下获取不受显示缩放影响的真实物理像素分辨率方法

问题根源

你观察到的API返回值和实际GDI坐标不匹配的现象,是Windows DPI虚拟化机制的默认行为:当进程未声明高DPI感知时,系统会自动向进程上报缩放后的虚拟分辨率,同时对进程发起的所有GDI绘制、屏幕捕获操作做自动坐标缩放,才会出现125%缩放下GetSystemMetrics(SM_CXSCREEN)返回1536、传入该值调用BitBlt只能截取部分屏幕、SetPixel坐标偏移的问题。

可用实现方案

方案1:开启进程高DPI感知后调用常规API(推荐,无坐标换算成本)

这是最稳定、兼容性最好的方案,开启高DPI感知后系统会关闭对进程的DPI虚拟化,所有系统API返回的坐标、尺寸都和物理像素一一对应,不需要额外做换算。
你需要在程序启动阶段、创建任何窗口/调用任何GDI API之前,根据程序兼容的Windows版本选择对应API设置DPI感知等级:

  • Windows 10 1607及以上版本:调用SetProcessDpiAwarenessContext,传入参数DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
  • Windows 8.1及以上版本:调用SetProcessDpiAwareness,传入参数PROCESS_PER_MONITOR_DPI_AWARE
  • Windows Vista及以上版本:调用SetProcessDPIAware

设置完成后,即可通过常规API拿到真实物理分辨率:

  • 单屏场景:直接调用GetSystemMetrics(SM_CXSCREEN)获取水平真实像素,GetSystemMetrics(SM_CYSCREEN)获取垂直真实像素
  • 多屏场景:通过EnumDisplayMonitors枚举目标显示器,调用GetMonitorInfo拿到的rcMonitor矩形就是该显示器的物理像素范围;也可以针对目标显示器的设备上下文调用GetDeviceCaps(hdc, HORZRES)、GetDeviceCaps(hdc, VERTRES)获取对应宽高。

方案2:不修改进程DPI感知状态直接读取物理分辨率(适配特殊场景)

如果你的程序不需要全局开启高DPI感知,仅需要单独获取真实分辨率,可以直接通过显示配置枚举API读取,返回值不受进程DPI感知状态影响:
调用EnumDisplaySettings传入目标显示器的设备名和ENUM_CURRENT_SETTINGS参数,填充DEVMODE结构后,结构内的dmPelsWidth、dmPelsHeight字段就是当前显示器的真实水平、垂直像素值。
核心代码示例:

DEVMODE devMode = {};
devMode.dmSize = sizeof(DEVMODE);
// 传入NULL获取主屏幕配置,多屏场景替换为对应显示器的设备名即可
EnumDisplaySettings(nullptr, ENUM_CURRENT_SETTINGS, &devMode);
// devMode.dmPelsWidth = 真实水平像素
// devMode.dmPelsHeight = 真实垂直像素

注意:使用该方案时,进程仍处于DPI虚拟化状态,后续调用BitBlt、SetPixel等GDI API时,系统仍会做自动坐标缩放。你需要先通过GetDeviceCaps(hdc, LOGPIXELSX)拿到当前系统的DPI值,计算出缩放系数(缩放系数=当前DPI/96),将物理像素坐标除以缩放系数得到虚拟坐标后再传入GDI API,否则还是会出现坐标错位、截取不全的问题。


内容的提问来源于stack exchange,提问作者Steven Brown

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.22 16:12:26