Dominik Palo
Dominik Palo

Reputation: 3111

How to get the number of monitors connected to the PC in C#?

I need to detect the number of monitors that are physically connected to the computer (to decide if the screen configuration is in single, extended, or duplicate mode).

Both System.Windows.Forms.Screen.AllScreens.Length and System.Windows.Forms.SystemInformation.MonitorCount return the number of virtual screens (desktops).

I need that if there are 2+ monitors connected to the PC, I can decide between duplicate/extended mode using this value, but I can't decide if there is only one physical monitor connected to the PC, and therefore the screen configuration is in single screen mode.

Upvotes: 3

Views: 8432

Answers (5)

SWSBB
SWSBB

Reputation: 91

Maybe a bit late, but here is what I used:

[DllImport("User32.dll", EntryPoint = "GetSystemMetrics")]
internal extern static int fGetSystemMetrics(int metric);

const int SM_CMONITORS = 80;

fGetSystemMetrics(SM_CMONITORS);

Edit: See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemmetrics

Upvotes: 0

Ozgur O.
Ozgur O.

Reputation: 97

"SELECT * FROM Win32_DesktopMonitor" query might not work properly after Vista. I spent hours looking for a solution but none of them managed to handle this properly for Windows 7 and newer. Based on Dominik's answer;

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

will return the count of physical monitors. With this change, his helper class also worked for me.

Upvotes: 2

Matt Becker
Matt Becker

Reputation: 2368

The most reliable way I found to get a monitor count in WPF was to listen for WM_DISPLAYCHANGE to know when mionitors are connected and disconnected and then use EnumDisplayMonitors to get the monitor count. Here's the code.

Hook into WndProc for the WM_DISPLAYCHANGE message.

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;
        }

Get the display count

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;
    }
}

Upvotes: 0

Dominik Palo
Dominik Palo

Reputation: 3111

Based on the Xanatos answer, I created simple helper class to detect the screens configuration:

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
}

Upvotes: 3

Xanatos
Xanatos

Reputation: 445

Try the following:

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

Answer found on the following question:

WMI Get All Monitors Not Returning All Monitors

Update

Try the following function it detects unplugging the monitor:

    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;
    }

Here are a list for the status: https://msdn.microsoft.com/en-us/library/aa394122%28v=vs.85%29.aspx

Maybe you need to increase the counter on a other statuscode as well. Check the link for more information.

Upvotes: 7

Related Questions