检测连接的监视器数始终返回1或更多而不是0

时间:2018-08-09 15:21:42

标签: c# .net windows visual-studio

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

到目前为止,我已经能够在Internet和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认为要渲染到的屏幕数?

1 个答案:

答案 0 :(得分:0)

经过大量的修补和头部刮擦,我设法创建了一个可靠地返回正确数量的已连接屏幕的函数,即使该数量在程序运行时发生了变化,即使已连接屏幕的数量为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。

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