C# 获取 Windows 中每个显示器的 DPI 缩放比例

2024-01-29

我正在使用 WPF 应用程序中的代码,该应用程序需要计算 Windows 中每个显示器的 DPI 缩放大小。我能够计算出主屏幕的 DPI,但由于某种原因,我无法计算出如何获取其他显示器的比例 - 其他显示器都返回与主显示器相同的 DPI。

有一些代码可以做到这一点,所以请耐心等待。第一组代码涉及根据 HWND 获取 DPI。该代码获取活动监视器,然后检索 DPI 设置并比较与 96 DPI 的比率(通常为 100%)。

public static decimal GetDpiRatio(Window window)
{
    var dpi = WindowUtilities.GetDpi(window, DpiType.Effective);
    decimal ratio = 1;
    if (dpi > 96)
        ratio = (decimal)dpi / 96M;

    return ratio;
}
public static decimal GetDpiRatio(IntPtr hwnd)
{            
    var dpi = GetDpi(hwnd, DpiType.Effective);            
    decimal ratio = 1;
    if (dpi > 96)
        ratio = (decimal)dpi / 96M;

    //Debug.WriteLine($"Scale: {factor} {ratio}");
    return ratio;
}

public static uint GetDpi(IntPtr hwnd, DpiType dpiType)
{            
    var screen = Screen.FromHandle(hwnd);            
    var pnt = new Point(screen.Bounds.Left + 1, screen.Bounds.Top + 1);
    var mon = MonitorFromPoint(pnt, 2 /*MONITOR_DEFAULTTONEAREST*/);

    Debug.WriteLine("monitor handle: " + mon);
    try
    {
        uint dpiX, dpiY;
        GetDpiForMonitor(mon, dpiType, out dpiX, out dpiY);
        return dpiX;
    }
    catch
    {
        // fallback for Windows 7 and older - not 100% reliable
        Graphics graphics = Graphics.FromHwnd(hwnd);
        float dpiXX = graphics.DpiX;                
        return Convert.ToUInt32(dpiXX);
    }
}


public static uint GetDpi(Window window, DpiType dpiType)
{
    var hwnd = new WindowInteropHelper(window).Handle;
    return GetDpi(hwnd, dpiType);
}     

[DllImport("User32.dll")]
private static extern IntPtr MonitorFromPoint([In]System.Drawing.Point pt, [In]uint dwFlags);

[DllImport("Shcore.dll")]
private static extern IntPtr GetDpiForMonitor([In]IntPtr hmonitor, [In]DpiType dpiType, [Out]out uint dpiX, [Out]out uint dpiY);        


public enum DpiType
{
    Effective = 0,
    Angular = 1,
    Raw = 2,
}

此代码用作屏幕捕获解决方案的一部分,其中应该在用户鼠标所在的窗口上覆盖。我捕获鼠标位置,并根据该位置获取像素位置,然后在那里创建 WPF 窗口。在这里,我必须应用 DPI 比率,以使窗口在正确的位置和大小上渲染。

只要 DPI 相同,这在主显示器或多台显示器上都可以正常工作。

问题是调用GetDpiForMonitor()始终返回主显示器 DPI,即使HMONITOR传递给它的值是不同的。

DPI 意识

这是一个 WPF 应用程序,因此该应用程序具有 DPI 感知能力,但 WPF 在系统 DPI 感知中运行,而不是在每监视器 DPI 感知中运行。为此我连接了static App()启动时显式设置为每个显示器 DPI 的代码:

    try
    {
        // for this to work make sure [assembly:dpiawareness
        PROCESS_DPI_AWARENESS awareness;
        GetProcessDpiAwareness(Process.GetCurrentProcess().Handle, out awareness);
        var result = SetProcessDpiAwareness(PROCESS_DPI_AWARENESS.Process_Per_Monitor_DPI_Aware);
        GetProcessDpiAwareness(Process.GetCurrentProcess().Handle, out awareness);
}

[DllImport("SHCore.dll", SetLastError = true)]
public static extern bool SetProcessDpiAwareness(PROCESS_DPI_AWARENESS awareness);

[DllImport("SHCore.dll", SetLastError = true)]
public static extern void GetProcessDpiAwareness(IntPtr hprocess, out PROCESS_DPI_AWARENESS awareness);

public enum PROCESS_DPI_AWARENESS
{
    Process_DPI_Unaware = 0,
    Process_System_DPI_Aware = 1,
    Process_Per_Monitor_DPI_Aware = 2
}

// and in assemblyinfo
[assembly: DisableDpiAwareness]

我看到 DPI 设置更改为Process_Per_Monitor_DPI_Aware但这似乎也对行为没有影响。我仍然看到返回的 DPI 结果与主显示器相同。

在一个较大的解决方案中有一个测试,允许在这里使用它:https://github.com/RickStrahl/MarkdownMonster/blob/master/Tests/ScreenCaptureAddin.Test/DpiDetectionTests.cs https://github.com/RickStrahl/MarkdownMonster/blob/master/Tests/ScreenCaptureAddin.Test/DpiDetectionTests.cs如果有人有兴趣检查一下。

有什么想法可以可靠地获取系统上所有显示器的 DPI 缩放级别(以及为什么没有系统 API 甚至没有 WMI 设置)?


自 .NET Framework 4.6.2 起,WPF 就支持每显示器 DPI。 GitHub 上提供了更多信息和示例:http://github.com/Microsoft/WPF-Samples/tree/master/PerMonitorDPI http://github.com/Microsoft/WPF-Samples/tree/master/PerMonitorDPI.

您可能还想查看VisualTreeHelper.GetDpi https://msdn.microsoft.com/en-us/library/system.windows.media.visualtreehelper.getdpi%28v=vs.110%29.aspx method.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# 获取 Windows 中每个显示器的 DPI 缩放比例 的相关文章

  • R 脚本自动化时的不同结果

    以下命令对 pdf 文件执行 Ghostscript 这pdf file变量包含该 pdf 的路径 bbox lt system paste C gs gs8 64 bin gswin32c exe sDEVICE bbox dNOPAUS
  • RabbitMq 和“致命错误:握手失败 -handshake_decode_error”

    我正在使用 Windows Server 2012 Erlang 19 2 和 RabbitMq 3 6 6 我在使用 TLS 配置端点之间的连接时遇到问题 我已经尝试了所有关于 SO 的答案 以及所有 RabbitMq 文档here ht
  • Python 无法在 git bash 命令行中工作

    Python 不会在 git bash Windows 中运行 当我在命令行中输入 python 时 它会将我带到一个空行 而不会像在 Powershell 中一样显示它已输入 python 2 7 10 它没有给我错误消息 但 pytho
  • WPF - 检测鼠标按下一段时间

    检测鼠标按钮何时在特定元素上按住特定时间段的最佳方法是什么 感谢您的提示 我创建了一个附加属性以避免任何代码隐藏 using System using System Windows using System Windows Threadin
  • 批处理文件 FOR /f 标记

    任何人都可以逐行准确解释以下代码是如何工作的 我真的迷路了 我一直在尝试学习如何使用 FOR 命令 但我不明白这一点 echo off for f tokens delims f in myfile do set line f call p
  • WPF DataGrid 绑定 DataGridCell 内容

    希望这将是一个非常简单的答案 我认为我只是没有看到众所周知的树木 我有一个 DataGridCell 样式 我想将单元格的内容绑定到图像的源属性 这是我目前使用的 XAML
  • .wav 文件长度/持续时间,无需读入文件

    有没有办法提取有关 wav 文件长度 持续时间的信息 而无需在 R 中读取文件 我有数千个这样的文件 如果我必须阅读每个文件才能找到其持续时间 那将需要很长时间 Windows 文件资源管理器为您提供了打开 长度 字段的选项 并且您可以查看
  • 如何从任何进程关闭 Windows 上的套接字(ipv4 和 ipv6)连接?

    如何在 Windows 上关闭 tcp v4 和 tcp v6 连接 我不想终止具有开放连接的整个进程 因为这显然会将其他人踢出该进程 我需要从一个单独的进程执行此操作 因此无法访问套接字句柄等 我正在使用 Windows API 来获取
  • 如何在 C++ 中急于提交分配的内存?

    总体情况 带宽 CPU 使用率和 GPU 使用率都极其密集的应用程序需要每秒从一个 GPU 向另一个 GPU 传输约 10 15GB 的数据 它使用 DX11 API 来访问 GPU 因此上传到 GPU 只能在每次上传都需要映射的缓冲区中进
  • Windows 上的 Openssl 错误 0x02001005 和 0x2006D002?

    我正在尝试使用 openssl 将 cer 证书转换为 p12 证书 这是我正在使用的命令 C OpenSSL Win32 bin gt openssl x509 inform der in developer identity cer o
  • 移动/调整窗口大小时闪烁

    我开发了一个显示 jpeg 图像的应用程序 它可以显示 4 个图像 屏幕的每个象限各一个 为此 它使用了 4 个窗口 窗口没有边框 框架 也没有标题栏 当加载新图像时 窗口大小会根据新图像进行调整 然后显示该图像 尤其是当窗户做得较大时 经
  • 从命令行运行 R 代码 (Windows)

    我在名为 analysis r 的文件中有一些 R 代码 我希望能够从命令行 CMD 运行该文件中的代码 而无需通过 R 终端 并且我还希望能够传递参数并在我的代码中使用这些参数 例如就像下面的伪代码 C gt execute r scri
  • 使 DataTemplate 可混合

    如何为 ViewModel 制作可混合的数据模板 可在表达式混合中设计 当我转到资源并尝试直接编辑数据模板时 我在绘图板上看到的只是一个空白矩形 这是因为 DataTemplate 没有绑定到任何东西 当然 我可以创建一个 UserCont
  • C# - 方法必须有返回类型

    我在调用 C 中的方法时遇到问题 不断收到消息 方法 计算 必须有返回类型 using System Diagnostics namespace WindowsFormsApplication1 public partial class F
  • 更改鼠标悬停时的矩形背景

    所以我有一个没有背景的矩形 当用户将鼠标悬停在其上时 我想给它一个背景渐变 然后当鼠标离开矩形时删除渐变 请有人发布所需的代码 并告诉我将其放在 cs xaml 文件中的位置吗 Thanks This
  • 如何在Windows上模拟socket.socketpair

    标准Python函数套接字 套接字对 https docs python org 3 library socket html socket socketpair不幸的是 它在 Windows 上不可用 从 Python 3 4 1 开始 我
  • Vim 在 Mingw 上表现异常

    我在 MinGW 4 6 2 上的 Vim 表现得很奇怪 例如 在插入模式下按 Backspace 会删除字符 但我必须用箭头键移动光标才能删除的字符消失 而且它也会使我退出插入模式 另一个例子 按 Del 删除字符有时会生成奇怪的字符 例
  • WPF 数据绑定到复合类模式?

    我是第一次尝试 WPF 并且正在努力解决如何将控件绑定到使用其他对象的组合构建的类 例如 如果我有一个由两个单独的类组成的类 Comp 为了清楚起见 请注意省略的各种元素 class One int first int second cla
  • 游戏内的java.awt.Robot?

    我正在尝试使用下面的代码来模拟击键 当我打开记事本时 它工作正常 但当我打开我想使用它的游戏时 它没有执行任何操作 所以按键似乎不起作用 我尝试模拟鼠标移动和点击 这些动作确实有效 有谁知道如何解决这个问题 我发现这个问题 如何在游戏中使用
  • 相当于Linux中的导入库

    在 Windows C 中 当您想要链接 DLL 时 您必须提供导入库 但是在 GNU 构建系统中 当您想要链接 so 文件 相当于 dll 时 您就不需要链接 为什么是这样 是否有等效的 Windows 导入库 注意 我不会谈论在 Win

随机推荐