C# - 如何在多显示器上下文中获得真实的屏幕分辨率?

标签 c# wpf winapi interop multiple-monitors

对于我的一个应用程序(用 WPF 编写),我需要获取有关监视器的一些信息:当前分辨率、比例因子和实际分辨率。

我知道这个问题已经被问过很多次了,但我无法在所有讨论过这个问题的 SO 问题中找到一个好的答案......

以我为例,我按以下顺序放置了 3 个显示器:

  • 显示器 1(集成笔记本电脑屏幕):1920x1080,缩放比例为 125%
  • 显示器 2 (LG 22"):1920x1080,按 100% 缩放(主显示器)
  • 显示器 3 (LG 22"):1920x1080,按 100% 缩放

当使用 System.Windows.Forms.Screen.AllScreens 时,我的第一台显示器获得了 1536x864 的分辨率。没关系,因为 1536*1.25 = 1920。但是我找不到 1.25 或 1920 ^^ (对于其他显示器来说没问题,因为它们按 100% 缩放)。

但是如果我将显示器 1 设置为主显示器,我可以获得它的实际分辨率,但是对于显示器 2 和 3,我获得 2400*1350...它是 1920x1080 乘以主显示器的比例因子:1.25

自从我尝试了很多方法以来已经过去了 2 天。我在 Windows.Forms 中尝试过 AllScreens。在 WinAPI 中,我尝试了 EnumDisplayMonitors、GetDeviceCaps、GetScaleFactorForMonitor、GetDpiForMonitor ... 对于我的第一台显示器,一切总是给我 100% 的比例因子或 96 的 DPI,这是一个错误...

您知道获取这些信息的安全方法吗?在 WMI、注册表等中...

感谢您的帮助!

(PS:如果需要,我可以提供我尝试过的代码示例,但我不想在第一篇文章中泛滥成灾)

编辑:我忘了提到我需要在没有任何可视化应用程序的情况下获取这些信息(我的 DLL 是从 VB 应用程序调用的)

最佳答案

我有几乎完全相同的设置。我能够通过使用 p/invoke 调用 EnumDisplaySettings 获得真正的分辨率。

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

const int ENUM_CURRENT_SETTINGS = -1;

foreach (Screen screen in Screen.AllScreens)
{
    var dm = new DEVMODE();
    dm.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE));
    EnumDisplaySettings(screen.DeviceName, ENUM_CURRENT_SETTINGS, ref dm);

    Console.WriteLine($"Device: {screen.DeviceName}");
    Console.WriteLine($"Real Resolution: {dm.dmPelsWidth}x{dm.dmPelsHeight}");
    Console.WriteLine($"Virtual Resolution: {screen.Bounds.Width}x{screen.Bounds.Height}");
    Console.WriteLine();
}

[DllImport("user32.dll")]
static extern bool EnumDisplaySettings(string lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode);

[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
    public string dmDeviceName;
    public short dmSpecVersion;
    public short dmDriverVersion;
    public short dmSize;
    public short dmDriverExtra;
    public int dmFields;
    public int dmPositionX;
    public int dmPositionY;
    public ScreenOrientation dmDisplayOrientation;
    public int dmDisplayFixedOutput;
    public short dmColor;
    public short dmDuplex;
    public short dmYResolution;
    public short dmTTOption;
    public short dmCollate;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
    public string dmFormName;
    public short dmLogPixels;
    public int dmBitsPerPel;
    public int dmPelsWidth;
    public int dmPelsHeight;
    public int dmDisplayFlags;
    public int dmDisplayFrequency;
    public int dmICMMethod;
    public int dmICMIntent;
    public int dmMediaType;
    public int dmDitherType;
    public int dmReserved1;
    public int dmReserved2;
    public int dmPanningWidth;
    public int dmPanningHeight;
}

输出:

Device: \\.\DISPLAY1
Real Resolution: 1920x1080
Virtual Resolution: 1536x864

Device: \\.\DISPLAY2
Real Resolution: 1920x1080
Virtual Resolution: 1920x1080

Device: \\.\DISPLAY3
Real Resolution: 1920x1080
Virtual Resolution: 1920x1080

https://stackoverflow.com/a/36864741/987968 http://pinvoke.net/default.aspx/user32/EnumDisplaySettings.html?diff=y

关于C# - 如何在多显示器上下文中获得真实的屏幕分辨率?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43187663/

相关文章:

c# - 旧 PC 无法运行 XNA,对于创建简单的 2D 游戏有什么建议?

c# - 我们什么时候为字典执行 GetHashCode()?

C# 复杂返回类型

c# - 不区分大小写的 GetMethod?

c++ - 如何在 Windows 上获取硬件 MAC 地址

winapi - CreateFile ("CONIN$"..) 做什么?

c# - 从 "run as"凭据下运行的进程获取登录用户名

c# - 带背景的 WPF WindowChrome - 系统按钮被隐藏

c# - 为什么 TextBlock 不绑定(bind)?

winapi - mkdir 和 CreateDirectory 之间的区别