如何获得所有屏幕的DPI比例?

Sar*_*rah 13 c# windows wpf

对于连接到计算机的每个屏幕,我需要从控制面板>显示设置获得DPI比例,即使那些没有打开WPF窗口的屏幕也是如此.我已经看到了许多获取DPI的方法(例如,http://dzimchuk.net/post/Best-way-to-get-DPI-value-in-WPF),但这些似乎依赖于Graphics.FromHwnd(IntPtr.Zero)或者PresentationSource.FromVisual(visual).CompositionTarget.TransformToDevice.

有没有办法获得每个屏幕的DPI设置?

背景 - 我正在创建一个布局配置编辑器,以便用户可以在启动之前设置其配置.为此,我将每个屏幕相对于彼此绘制.对于一种配置,我们使用的4K显示器具有大于默认DPI标度集.与其他屏幕相比,它绘制的内容要小得多,因为它报告的分辨率与其他屏幕相同.

Koo*_*ler 20

我找到了一种方法来获得WinAPI的dpi.首先需要参考System.DrawingSystem.Windows.Forms.可以从显示区域的某个点获取带有WinAPI的监视器句柄 - Screen该类可以给我们这一点.然后该GetDpiForMonitor函数返回指定监视器的dpi.

public static class ScreenExtensions
{
    public static void GetDpi(this System.Windows.Forms.Screen screen, DpiType dpiType, out uint dpiX, out uint dpiY)
    {
        var pnt = new System.Drawing.Point(screen.Bounds.Left + 1, screen.Bounds.Top + 1);
        var mon = MonitorFromPoint(pnt, 2/*MONITOR_DEFAULTTONEAREST*/);
        GetDpiForMonitor(mon, dpiType, out dpiX, out dpiY);
    }

    //https://msdn.microsoft.com/en-us/library/windows/desktop/dd145062(v=vs.85).aspx
    [DllImport("User32.dll")]
    private static extern IntPtr MonitorFromPoint([In]System.Drawing.Point pt, [In]uint dwFlags);

    //https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510(v=vs.85).aspx
    [DllImport("Shcore.dll")]
    private static extern IntPtr GetDpiForMonitor([In]IntPtr hmonitor, [In]DpiType dpiType, [Out]out uint dpiX, [Out]out uint dpiY);
}

//https://msdn.microsoft.com/en-us/library/windows/desktop/dn280511(v=vs.85).aspx
public enum DpiType
{
    Effective = 0,
    Angular = 1,
    Raw = 2,
}
Run Code Online (Sandbox Code Playgroud)

缩放有三种类型,您可以在MSDN中找到说明.

我使用新的WPF应用程序快速测试了它:

private void Window_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
    var sb = new StringBuilder();
    sb.Append("Angular\n");
    sb.Append(string.Join("\n", Display(DpiType.Angular)));
    sb.Append("\nEffective\n");
    sb.Append(string.Join("\n", Display(DpiType.Effective)));
    sb.Append("\nRaw\n");
    sb.Append(string.Join("\n", Display(DpiType.Raw)));

    this.Content = new TextBox() { Text = sb.ToString() };
}

private IEnumerable<string> Display(DpiType type)
{
    foreach (var screen in System.Windows.Forms.Screen.AllScreens)
    {
        uint x, y;
        screen.GetDpi(type, out x, out y);
        yield return screen.DeviceName + " - dpiX=" + x + ", dpiY=" + y;
    }
}
Run Code Online (Sandbox Code Playgroud)

我希望它有所帮助!

  • 快速说明,这仅适用于Windows 8及更高版本。 (2认同)
  • 我发现在使用具有不同 DPI 比例的多台显示器的 Windows 10 上,“Angular”是正确的“DpiType”,以获得屏幕元素的正确比例。常规 DPI 为 96,而我的 175% 屏幕上的角度为 55。96 / 1.75 = 54.857,四舍五入为 55。 (2认同)
  • 在执行奇怪的 DPI 操作的 Visual Studio 2019 进程中,从 Point(screen.Bounds.Left + 1, screen.Bounds.Top + 1) 检索监视器的启发式方法不起作用。我必须使用 /sf/answers/351443641/ EnumDisplayMonitors 来获取所有监视器句柄 IntPtr + 我必须使用 DpiType.Effective 来获取正确的 DPI 值(96 = 100% 144 = 150% 192 = 200 % 等等...) (2认同)