【问题标题】:How to get count of monitors connected to the PC in C#?如何在 C# 中获取连接到 PC 的显示器数量?
【发布时间】:2015-06-25 07:25:08
【问题描述】:

我需要检测物理连接到计算机的显示器数量(以确定屏幕配置是否处于单一、扩展、重复模式)。 System.Windows.Forms.Screen.AllScreens.LengthSystem.Windows.Forms.SystemInformation.MonitorCount 都返回虚拟屏幕(桌面)的计数。

所以,如果有 2 个以上的显示器连接到 PC,我可以使用此值在复制/扩展模式之间做出决定,但我无法决定是否只有一个物理显示器连接到 PC,因此屏幕配置是在单屏模式下。

【问题讨论】:

    标签: c# wpf screen


    【解决方案1】:

    基于 Xanatos 的回答,我创建了简单的帮助类来检测屏幕配置:

    using System;
    using System.Management;
    using System.Windows.Forms;
    
    public static class ScreensConfigurationDetector
    {
        public static ScreensConfiguration GetConfiguration()
        {
            int physicalMonitors = GetActiveMonitors();
            int virtualMonitors = Screen.AllScreens.Length;
    
            if (physicalMonitors == 1)
            {
                return ScreensConfiguration.Single;
            }
    
            return physicalMonitors == virtualMonitors 
                ? ScreensConfiguration.Extended 
                : ScreensConfiguration.DuplicateOrShowOnlyOne;
        }
    
        private static int GetActiveMonitors()
        {
            int counter = 0;
            ManagementObjectSearcher monitorObjectSearch = new ManagementObjectSearcher("SELECT * FROM Win32_DesktopMonitor");
            foreach (ManagementObject Monitor in monitorObjectSearch.Get())
            {
                try
                {
                    if ((UInt16)Monitor["Availability"] == 3)
                    {
                        counter++;
                    }
                }
                catch (Exception)
                {
                    continue;
                }
    
            }
            return counter;
        }
    }
    
    public enum ScreensConfiguration
    {
        Single,
        Extended,
        DuplicateOrShowOnlyOne
    }
    

    【讨论】:

      【解决方案2】:

      尝试以下方法:

          System.Management.ManagementObjectSearcher monitorObjectSearch = new System.Management.ManagementObjectSearcher("SELECT * FROM Win32_DesktopMonitor");
          int Counter = monitorObjectSearch.Get().Count;
      

      找到以下问题的答案:

      WMI Get All Monitors Not Returning All Monitors

      更新

      尝试以下检测到拔出显示器的功能:

          private int GetActiveMonitors()
          {
              int Counter = 0;
              System.Management.ManagementObjectSearcher monitorObjectSearch = new System.Management.ManagementObjectSearcher("SELECT * FROM Win32_DesktopMonitor");
              foreach (ManagementObject Monitor in monitorObjectSearch.Get())
              {
                  UInt16 Status = 0;
                  try
                  {
                      Status = (UInt16)Monitor["Availability"];
                  }
                  catch (Exception ex)
                  {
                      //Error handling if you want to
                      continue;
                  }
                  if (Status == 3)
                      Counter++;
      
              }
              return Counter;
          }
      

      以下是状态列表:https://msdn.microsoft.com/en-us/library/aa394122%28v=vs.85%29.aspx

      也许您还需要增加其他状态码的计数器。查看链接了解更多信息。

      【讨论】:

      • 谢谢,但如果我有 2 台显示器连接到计算机,然后我断开一台,计数器仍然返回不正确的(旧)计数 -> 2(直到下次启动 Windows)...
      • 谢谢,但它不起作用 - 如果我将屏幕配置设置为“复制”,它现在只检测一个物理监视器(在复制模式下,第二个监视器的状态为 8 - 离线,相同状态好像监视器已断开连接)
      【解决方案3】:

      我发现在 WPF 中获取监视器计数的最可靠方法是侦听 WM_DISPLAYCHANGE 以了解 mionitor 何时连接和断开连接,然后使用 EnumDisplayMonitors 获取监视器计数。这是代码。

      挂钩到 WndProc 以获取 WM_DISPLAYCHANGE 消息。

      public partial class MainWindow : IDisposable
      {
      ...
              protected override void OnSourceInitialized(EventArgs e)
              {
                  base.OnSourceInitialized(e);
                  HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
                  source.AddHook(WndProc);
              }
      
              private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
              {
                  if (msg == WM_DISPLAYCHANGE)
                  {
                      int lparamInt = lParam.ToInt32();
      
                      uint width = (uint)(lparamInt & 0xffff);
                      uint height = (uint)(lparamInt >> 16);
      
                      int monCount = ScreenInformation.GetMonitorCount();
                      int winFormsMonCount = System.Windows.Forms.Screen.AllScreens.Length;
      
                      _viewModel.MonitorCountChanged(monCount);
                  }
      
                  return IntPtr.Zero;
              }
      

      获取展示次数

      public class ScreenInformation
      {
          [StructLayout(LayoutKind.Sequential)]
          private struct ScreenRect
          {
              public int left;
              public int top;
              public int right;
              public int bottom;
          }
      
          [DllImport("user32")]
          private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lpRect, MonitorEnumProc callback, int dwData);
      
          private delegate bool MonitorEnumProc(IntPtr hDesktop, IntPtr hdc, ref ScreenRect pRect, int dwData);
      
          public static int GetMonitorCount()
          {
              int monCount = 0;
              MonitorEnumProc callback = (IntPtr hDesktop, IntPtr hdc, ref ScreenRect prect, int d) => ++monCount > 0;
      
              if (EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, callback, 0))
                  Console.WriteLine("You have {0} monitors", monCount);
              else
                  Console.WriteLine("An error occured while enumerating monitors");
      
              return monCount;
          }
      }
      

      【讨论】:

        【解决方案4】:

        “SELECT * FROM Win32_DesktopMonitor”查询在 Vista 之后可能无法正常工作。我花了几个小时寻找解决方案,但没有一个能够在 Windows 7 和更高版本中正确处理这个问题。基于Dominik's answer

        ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_PnPEntity where service=\"monitor\"");
        int numberOfMonitors = searcher.Get().Count;
        

        将返回物理监视器的计数。有了这个改变,他的助手类也对我有用。

        【讨论】:

          猜你喜欢
          • 2013-08-02
          • 2011-02-20
          • 2015-12-09
          • 1970-01-01
          • 2014-10-28
          • 2012-08-10
          • 1970-01-01
          • 1970-01-01
          • 2021-10-22
          相关资源
          最近更新 更多