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

Graphics.DpiX/DpiY仅返回主显示器DPI,如何获取当前扩展显示器DPI?

问题原因

你遇到的问题不是接口本身的缺陷,根源如下:

  • WinForm项目默认未开启Per-Monitor DPI感知模式,系统会对非感知模式的程序做DPI虚拟化,统一返回主显示器的DPI值,屏蔽不同显示器的DPI差异
  • CreateGraphics()返回的Graphics对象默认关联主显示器的渲染上下文,不会随窗口所在显示器变化自动切换
解决方案

第一步:开启Per-Monitor DPI感知

.NET 6+ WinForm项目可直接在Program.cs入口添加配置:

Application.SetHighDpiMode(HighDpiMode.PerMonitorV2);

低版本.NET项目可修改app.manifest文件,添加如下配置:

<application xmlns="urn:schemas-microsoft-com:asm.v3">
  <windowsSettings>
    <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
  </windowsSettings>
</application>

第二步:获取当前窗口所在显示器DPI

方案1:适配Win10 1607及以上版本(推荐)

先声明Win32 API,直接调用GetDpiForWindow获取窗口对应DPI:

// 导入API声明
[DllImport("user32.dll")]
static extern uint GetDpiForWindow(IntPtr hWnd);

// 调用示例
private void getDPIButton1_Click(object sender, EventArgs e)
{
    uint currentDpi = GetDpiForWindow(this.Handle);
    // X、Y方向DPI通常一致,直接使用currentDpi即可
}

方案2:兼容Win7及以上版本

先获取窗口所在显示器的句柄,再查询对应显示器的DPI:

// 导入API声明
[DllImport("user32.dll")]
static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags);
const uint MONITOR_DEFAULTTONEAREST = 0x00000002;

[DllImport("shcore.dll")]
static extern int GetDpiForMonitor(IntPtr hmonitor, int dpiType, out uint dpiX, out uint dpiY);
const int MDT_EFFECTIVE_DPI = 0;

// 调用示例
private void getDPIButton1_Click(object sender, EventArgs e)
{
    IntPtr hMonitor = MonitorFromWindow(this.Handle, MONITOR_DEFAULTTONEAREST);
    GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, out uint dpiX, out uint dpiY);
    // dpiX、dpiY分别为当前显示器的水平、垂直DPI
}
额外提示

开启Per-Monitor DPI感知后,窗口跨显示器移动时会收到WM_DPICHANGED系统消息,你可以重写窗口的WndProc方法监听该消息,自动更换对应DPI的图片资源,无需手动触发查询刷新。


内容的提问来源于stack exchange,提问作者Mohanram Anbukkarasu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 08:09:03