Enumerating Monitors on Windows in C#

Most of readers of this blog post probably never have been working with Windowsds native API implemented long time ago inside User32 and related DLLs. But, as a professional application developer you migth have to deal sometimes with APIs, that are no more used every day in a life of new software developers.

If you feel lost looking for a solution grabbed in secrets of Windows, this post might help you.

The problem I want to solve here sounds very simple. Imagine you want to paint text inside a native window, rendered differently than your WPF, Windows Forms, and MAUI application renders it.

In that case, you will have to look for help inside User32.Dll. For example, assume you want to enlist all monitors in the system currently connected to your PC.

The following code demonstrates the correct C# decaration of all required Windows native functions and structures required to enlist all attached displays (monitors).


/// <summary>
/// Gets the list of monitors.
/// </summary>
static Dictionary<string, MONITORINFOEX> GetMonitors()
{
  EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, **MonitorEnumProc**, IntPtr.Zero);

  foreach (var item in monitors)
  {
    Debug.WriteLine(__aSyNcId_<_alSoubey__quot;{item.Value.szDevice}, Resolution:  
    {item.Value.rcMonitor.Right - item.Value.rcMonitor.Left}, 
    {item.Value.rcMonitor.Left- item.Value.rcMonitor.Top}, Pos: 
    {item.Value.rcMonitor.Left},{item.Value.rcMonitor.Top}");
  }
  
  return monitors;
}

/// <summary>
/// Callback during listing of monitors. Invoked for ever attached display.
/// After last invoke, the method EnumDisplayMonitors returns.
/// </summary>
private static bool MonitorEnumProc(IntPtr hMonitor, IntPtr hdcMonitor, ref Rectangle lprcMonitor, IntPtr dwData)
{
            MONITORINFOEX monitorInfo = new MONITORINFOEX();
            monitorInfo.cbSize = Marshal.SizeOf(typeof(MONITORINFOEX));
            bool res = GetMonitorInfo(hMonitor,  ref monitorInfo);
            if (res == false)
            {                 
                var err = Marshal.GetLastWin32Error();
            }            

            return true;
}
        
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
public struct MONITORINFOEX
{
  public int cbSize;
  public Rectangle rcMonitor;
  public Rectangle rcWork;
  public uint dwFlags;
  [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
  public string szDevice;
}

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumDisplayMonitors(IntPtr hdc,
                                              IntPtr lprcClip,
                                              EnumMonitorsDelegate lpfnEnum,
                                              IntPtr dwData);