Допустимые дружественные имена мониторов с C # - PullRequest
0 голосов
/ 22 октября 2019

Моя основная машина для разработки - это ноутбук с 2 экранами: внутренним экраном и внешним монитором Samsung.

    Generic PnP Monitor= 1366x768, Top: 0, Left: 1920 -> secondary display
    SF350_S24F350FH / S24F352FH / S24F354FH (HDMI)= 1920x1080, Top: 0, Left: 0 -> main display

My display configuration

И мои кодыявляются: Dispay.cs

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

internal class Display
{
  private Rectangle _bounds;
  private DisplayOrientation _orientation;
  private Rectangle _workingArea;
  private string _name,_deviceId;
  private static Display[] _displays;

  public Rectangle Bounds
  {
     get
     {
       return _bounds;
     }
  }

  public DisplayOrientation Orientation
  {
    get
    {
        return _orientation;
    }
  }

  public Rectangle WorkingArea
  {
    get
    {
        return _workingArea;
    }
  }

  public string DeviceId
  {
    get
    {
        return _deviceId;
    }
  }

  public string Name
  {
    get
    {
        return _name;
    }
  }

  public static DisplayImpl[] Displays
  {
    get
    {

        if (_displays == null) QueryDisplayDevices();

        return _displays;
    }

    private static void QueryDisplayDevices()
    {
            List<Display> list = new List<Display>();
            WinApi.MonitorEnumDelegate MonitorEnumProc = new WinApi.MonitorEnumDelegate((IntPtr hMonitor, IntPtr hdcMonitor, ref WinApi.RECT lprcMonitor, IntPtr dwData) => {
                WinApi.MONITORINFOEX mi = new WinApi.MONITORINFOEX() { Size = Marshal.SizeOf(typeof(WinApi.MONITORINFOEX)) };

                if (WinApi.GetMonitorInfo(hMonitor, ref mi))
                {
                    WinApi.DISPLAY_DEVICE device = new WinApi.DISPLAY_DEVICE();
                    device.Initialize();

                    if (WinApi.EnumDisplayDevices(mi.DeviceName.ToLPTStr(), 0, ref device, 0))
                    {
                        Display display = new Display()
                        {
                            _name = device.DeviceString,
                            _deviceId = mi.DeviceName,
                            _bounds=new Rectangle(mi.Monitor.Left,mi.Monitor.Top,mi.Monitor.Right-mi.Monitor.Left,mi.Monitor.Bottom-mi.Monitor.Top),
                            _workingArea = new Rectangle(mi.WorkArea.Left, mi.WorkArea.Top, mi.WorkArea.Right - mi.WorkArea.Left, mi.WorkArea.Bottom - mi.WorkArea.Top),
                        };
                        list.Add(display);
                    }
                }

                return true;
            });

            WinApi.EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, MonitorEnumProc, IntPtr.Zero);
            _displays=list.ToArray();

    }
  }

}

WinApi.cs:

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;

internal class WinApi
{
        #region DISPLAY_DEVICE struct
        [StructLayout(LayoutKind.Sequential)]
        internal struct DISPLAY_DEVICE
        {
            public int cb;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
            public string DeviceName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            public string DeviceString;
            public DisplayDeviceStateFlags StateFlags;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            public string DeviceID;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            public string DeviceKey;

            public void Initialize()
            {
                cb = 0;
                DeviceName = new string((char)32, 32);
                DeviceString = new string((char)32, 128);
                DeviceID = new string((char)32, 128);
                DeviceKey = new string((char)32, 128);
                cb = Marshal.SizeOf(this);
            }
        }
        #endregion

        #region RECT struct
        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }
        #endregion

        #region MONITORINFOEX struct
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct MONITORINFOEX
        {
            public int Size;
            public RECT Monitor;
            public RECT WorkArea;
            public uint Flags;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
            public string DeviceName;
        }
        #endregion

        #region DisplayDeviceStateFlags enum
        [Flags()]
        public enum DisplayDeviceStateFlags : int
        {
            /// <summary>The device is part of the desktop.</summary>
            AttachedToDesktop = 0x1,
            MultiDriver = 0x2,
            /// <summary>The device is part of the desktop.</summary>
            PrimaryDevice = 0x4,
            /// <summary>Represents a pseudo device used to mirror application drawing for remoting or other purposes.</summary>
            MirroringDriver = 0x8,
            /// <summary>The device is VGA compatible.</summary>
            VGACompatible = 0x10,
            /// <summary>The device is removable; it cannot be the primary display.</summary>
            Removable = 0x20,
            /// <summary>The device has more display modes than its output devices support.</summary>
            ModesPruned = 0x8000000,
            Remote = 0x4000000,
            Disconnect = 0x2000000,
        }
        #endregion

        public delegate bool MonitorEnumDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData);

        [DllImport("user32.dll")]
        public static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumDelegate lpfnEnum, IntPtr dwData);

        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        public static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFOEX lpmi);

        [DllImport("User32.dll")]
        internal static extern bool EnumDisplayDevices(byte[] lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, int dwFlags);

        public static byte[] ToLPTStr(this string str)
        {
            var lptArray = new byte[str.Length + 1];

            var index = 0;
            foreach (char c in str.ToCharArray())
                lptArray[index++] = Convert.ToByte(c);

            lptArray[index] = Convert.ToByte('\0');

            return lptArray;
        }


}

Затем я пытаюсь отладить

if(Display.Displays !=null) { }

И я получил эти результаты:

       Display 0:
          Name: Generic PnP Monitor
          DeviceId: \\\\.\\DISPLAY1
          Bounds:
             Top: 0
             Left: 0
             Width: 1920
             Height: 1080

       Display 1:
          Name: SF350_S24F350FH / S24F352FH / S24F354FH (HDMI)
          DeviceId: \\\\.\\DISPLAY2
          Bounds:
             Top: 0
             Left: 1920
             Width: 1366
             Height: 768

Исходя из разрешения экрана и значений в верхнем левом углу, дисплей 0 должен быть «SF350_S24F350FH / S24F352FH / S24F354FH (HDMI)», и почему он был заменен дисплеем 1?

Ответы [ 3 ]

1 голос
/ 22 октября 2019

Зависит от того, какой монитор определен как основной. Не имеет значения положение каждого монитора.

Эта библиотека очень хорошо справляется со своей задачей, если вы хотите: WindowsDisplayAPI

0 голосов
/ 29 октября 2019

С ключами @Dmo я использую эту библиотеку

            Rectangle rect;
            Display display;

            foreach (PathInfo pi in PathInfo.GetActivePaths())
            {
                if (!pi.TargetsInfo[0].DisplayTarget.IsAvailable) continue;

                rect=System.Windows.Forms.Screen.GetWorkingArea(new Rectangle(pi.Position, pi.Resolution));
                display = new DisplayImpl()
                {
                    _name = string.IsNullOrEmpty(pi.TargetsInfo[0].DisplayTarget.FriendlyName)? "Generic PnP Monitor" : pi.TargetsInfo[0].DisplayTarget.FriendlyName,
                    _deviceId = pi.DisplaySource.DisplayName,
                    _devicePath=pi.TargetsInfo[0].DisplayTarget.DevicePath,
                    _bounds = new Rectangle(pi.Position,pi.Resolution),
                    _workingArea = rect,
                };

                list.Add(display);
            }

Она выдает правильное имя монитора и пару настроек! ?

0 голосов
/ 29 октября 2019

В соответствии с документом EnumDisplayDevices

Для получения информации на мониторе дисплея сначала вызовите EnumDisplayDevices с lpDevice, установленным на NULL. Затем вызовите EnumDisplayDevices с lpDevice, установленным на DISPLAY_DEVICE.DeviceName, с первого вызова на EnumDisplayDevices и с iDevNum, установленным на zero. Тогда DISPLAY_DEVICE.DeviceString - это имя монитора.

Образцы:

private static void QueryDisplayDevices()
{
    DISPLAY_DEVICE device = new DISPLAY_DEVICE();
    device.Initialize();
    uint DispNum = 0;
    while (EnumDisplayDevices(null, DispNum, ref device, 0))
    {
        DISPLAY_DEVICE dev = new DISPLAY_DEVICE();
        dev.Initialize();
        if (EnumDisplayDevices(device.DeviceName, 0, ref dev, 0))
       {
            Console.WriteLine("Device Name:" + dev.DeviceName);
            Console.WriteLine("Monitor name:" + dev.DeviceString);
       }
       DispNum++;
       device.Initialize();
    }
}
...