Reputation: 3111
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
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
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
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
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
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