Screen.AllScreen is not giving the correct monitor count

DanTheMan picture DanTheMan · Feb 16, 2011 · Viewed 16.8k times · Source

I am doing something like this in my program:

Int32 currentMonitorCount = Screen.AllScreens.Length;

if  (currentMonitorCount < 2)
{
   //Put app in single screen mode.
}
else
{
   //Put app in dual screen mode.
}

It is VERY important my application recognizes how many monitors are currently connected.

However, after I plug/unplug the monitor a couple of times, Screen.AllScreens.Length always returns '2'.

My monitor knows it's not connected (it has entered 'power save' mode), and the control panel knows that it's not connected (it shows only one monitor).

So what am I missing? How do I figure out that there's only one monitor?

Answer

driis picture driis · Feb 16, 2011

I had a look at the source (remember we can do that using the MS Symbol servers). AllScreens uses an unmanaged API to get the screens on the first access, then stores the result in a static variable for later use.

The consequence of this, is that if the number of monitors changes while your program is running; then Screen.AllScreens will not pick up the change.

The easiest way to get around this would probably be to call the unmanaged API directly. (Or you could be evil, and use reflection to set the static screens field to null before asking. Don't do that).

Edit:

If you just need to know the count, check whether you can use System.Windows.Forms.SystemInformation.MonitorCount (as suggested in the comments) before going the P/Invoke route. This calls GetSystemMetrics directly, and it is probably correctly updated.

If you find you need to do it using P/Invoke, here is a complete example that demonstrates the usage of the unmanaged API from C#:

using System;
using System.Runtime.InteropServices;

class Program
{
    public static void Main()
    {
        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);
        else
            Console.WriteLine("An error occured while enumerating monitors");

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