【问题标题】:Detecting the number of connected monitors always returns 1 or more instead of 0检测连接的监视器的数量总是返回 1 或更多而不是 0
【发布时间】:2019-01-17 03:18:10
【问题描述】:

我有一个 Windows 应用程序需要在运行时检测正确数量的连接监视器。

到目前为止,我在互联网和 Stack Overflow 上找到的所有方法都失败了。无论屏幕是否实际连接,它们都返回 1。并且当连接2个屏幕时,其中一些正确返回2,但是,当没有连接屏幕时,它们都不返回0。我需要它在没有连接屏幕时返回 0。

即使是检测屏幕是否连接的方法也可以工作。

下面是我尝试过的6种方法的代码列表。

int numberOfScreens = 0;

        numberOfScreens = Screen.AllScreens.Length; //1 DOESN'T WORK

        numberOfScreens = SystemInformation.MonitorCount; //2 DOESN'T WORK

        numberOfScreens = GetSystemMetrics(80); //3 DOESN'T WORK

        /*4 DOESN'T WORK 
         * //This code was outside of the function
         * [DllImport("user32")]
         * private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lpRect, MonitorEnumProc callback, int dwData);
         * private delegate bool MonitorEnumProc(IntPtr hDesktop, IntPtr hdc, ref Rect pRect, int dwData);
         * [StructLayout(LayoutKind.Sequential)]
         * private struct Rect {
         *     public int left;
         *     public int top;
         *     public int right;
         *     public int bottom;
         * }
         */
        int monCount = 0;
        Rect r = new Rect();
        MonitorEnumProc callback = (IntPtr hDesktop, IntPtr hdc, ref Rect prect, int d) => ++monCount > 0;
        if (EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, callback, 0)) {
            Console.WriteLine("You have {0} monitors", monCount);
            numberOfScreens = monCount;
        } else {
            Console.WriteLine("An error occured while enumerating monitors");
        }

        //5 DOESN'T WORK 
        ManagementObjectSearcher searcher =
            new ManagementObjectSearcher("root\\CIMV2",
            "SELECT * FROM Win32_PnPEntity where service =\"monitor\"");
        numberOfScreens = searcher.Get().Count;

        //6 DOESN'T WORK
        var active = true;
        var query = "select * from WmiMonitorBasicDisplayParams";
        using (var wmiSearcher = new ManagementObjectSearcher("\\root\\wmi", query)) {
            var results = wmiSearcher.Get();
            foreach (ManagementObject wmiObj in results) {
                // get the "Active" property and cast to a boolean, which should 
                // tell us if the display is active. I've interpreted this to mean "on"
                active = (Boolean)wmiObj["Active"];
            }
        }
        Console.WriteLine(active);

如果有任何其他可靠的方法来检测正确的显示器数量,我将不胜感激。

谢谢!


附带说明,在 Default_Monitor 的注册表中设置了 EDID_OVERRIDE,因此无论发生什么,EDID 都不会改变。这不是我能改变的。但这可能是 Windows 说有监视器而实际上没有监视器的原因。这意味着它不会根据实际连接的显示器数量来计算显示器,而是根据它认为正在渲染到的显示器数量来计算。

鉴于这种怀疑,有没有一种方法可以检测实际连接的显示器数量?例如,插入了多少 HDMI/DVI/VGA 电缆,而不是 Windows 认为它​​要渲染到多少屏幕?

【问题讨论】:

标签: c# .net windows visual-studio


【解决方案1】:

经过大量的修补和摸索,我设法创建了一个函数,该函数能够可靠地返回正确的连接屏幕数量,即使该数字在程序运行时发生变化,即使连接的屏幕数量为 0 .

这意味着它也可以用来检测屏幕/显示器/监视器是否完全连接到计算机。

功能:

using System;
using System.Management;

/// <summary>
/// Returns the number of monitors currently connected to the computer.
/// </summary>
/// <returns>(int) number of monitors</returns>
public int getNumberOfConnectedMonitors() {
    int numberOfMonitors = 1;

    //Detect number of monitors. However, this does NOT work when no monitors are connected. It instead gives a 1.
    ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_PnPEntity where service =\"monitor\"");
    numberOfMonitors = searcher.Get().Count;

    //Get's the monitor's instance name. "Default_Monitor" is the "monitor" Windows defaults to when nothing is connected
    string activeScreen = "";
    using (var wmiSearcher = new ManagementObjectSearcher("\\root\\wmi", "select * from WmiMonitorBasicDisplayParams")) {
        var results = wmiSearcher.Get();
        foreach (ManagementObject wmiObj in results) {
            // tell us if the display is active
            var active = (Boolean)wmiObj["Active"];
            //Get the instance name of the active monitor
            if (active) {
                activeScreen = (string)wmiObj["InstanceName"];
            }
        }
    }

    //If Windows says only one monitor is connected and that monitor is Default_Monitor, then that means that there are no monitors detected by Windows
    if(numberOfMonitors == 1 && activeScreen.Contains("Default_Monitor")) {
        numberOfMonitors = 0;
    }

    return numberOfMonitors;
}

详细信息和说明(如果需要)

上述函数是方法 5 和方法 6 的科学怪人混合(见问题)。

首先它从方法 5 中获取监视器的数量,当连接的监视器数量大于 0 时(至少对于我测试的监视器),该方法可靠地给出了正确的数量。但是,当实际连接了 0 个监视器时,它会返回 1。

其次,它通过方法 6 的修改版本获取其中一个活动监视器的名称。方法 6 使用 WmiMonitorBasicDisplayParams class 获取有关已连接监视器的信息。首先,它检查监视器是否处于活动状态。如果是,那么它将获取监视器的实例名称。实例名称的格式类似于 DISPLAY\(monitorNameHere)\(seeminglyRandomValuesHere)

如果只连接了一个监视器,并且该监视器的实例名称包含“Default_Monitor”,则表示当前没有连接有效监视器,该函数返回 0。

“Default_Monitor”是 Windows 赋予“监视器”的名称,当未检测到监视器时它会显示该名称。 (至少,没有提供有效EDID 的监视器)


现在,原来的功能对我不起作用的原因可能是因为我将 Default_Monitor 设置为拥有自己的 EDID。但是,我认为无论如何这个功能仍然是可靠的。

这个函数也非常适合检测是否连接了屏幕/显示器/监视器(因为如果没有,它返回 0),这是我在互联网上其他任何地方也找不到的东西,导致我相信即使我没有为 Default_Monitor 设置 EDID,这些函数也不会返回 0。

无论哪种方式,这个功能在我的测试中都能可靠地工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-06
    • 1970-01-01
    • 2020-10-29
    相关资源
    最近更新 更多