using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using WindowsDisplayAPI.DisplayConfig; using WindowsDisplayAPI.Exceptions; using WindowsDisplayAPI.Native; using WindowsDisplayAPI.Native.DeviceContext; using WindowsDisplayAPI.Native.DeviceContext.Structures; using WindowsDisplayAPI.Native.Structures; namespace WindowsDisplayAPI { /// /// Contains information about a display source screen /// public class DisplayScreen { private readonly IntPtr _monitorHandle; private DisplayScreen(IntPtr monitorHandle) { _monitorHandle = monitorHandle; } /// /// Gets the source identification number /// public int SourceId { get { var name = ScreenName; if (string.IsNullOrWhiteSpace(name)) { return 0; } var index = ScreenName.IndexOf("DISPLAY", StringComparison.Ordinal); return index < 0 ? 0 : int.Parse(name.Substring(index + 7)); } } /// /// Gets a list of all active screens /// /// An array of instances. public static DisplayScreen[] GetScreens() { var result = new List(); var callback = new DeviceContextApi.MonitorEnumProcedure( (IntPtr handle, IntPtr dcHandle, ref RectangleL rect, IntPtr callbackObject) => { result.Add(new DisplayScreen(handle)); return 1; } ); return DeviceContextApi.EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, callback, IntPtr.Zero) ? result.ToArray() : null; } /// /// Gets a instance representing the screen current settings /// public DisplaySetting CurrentSetting { get => DisplaySetting.GetCurrentFromScreenName(ScreenName); } /// /// Gets a instance representing this screen saved settings /// public DisplaySetting SavedSetting { get => DisplaySetting.GetSavedFromScreenName(ScreenName); } /// /// Disables and detaches all devices connected to this screen /// /// Indicating if the changes should be applied immediately, recommended value is false public void Disable(bool apply) { SetSettings(new DisplaySetting(), apply); } /// /// Enables and attach all devices connected to this screen /// /// The display settings that should be applied while enabling the display device /// Indicating if the changes should be applied immediately, recommended value is false public void Enable(DisplaySetting displaySetting, bool apply = false) { SetSettings(displaySetting, apply); } /// /// Changes the display device settings to a new instance /// /// The display settings that should be applied /// Indicating if the changes should be applied immediately, recommended value is false public void SetSettings(DisplaySetting displaySetting, bool apply = false) { if (!IsValid) { throw new InvalidDisplayException(null); } displaySetting.Save(ScreenName, apply); } /// /// Get information about the monitor covering the most of a rectangle. /// /// The rectangle to get the main monitor information for. /// An instance of . public static DisplayScreen FromRectangle(Rectangle rectangle) { var monitorHandle = DeviceContextApi.MonitorFromRect( new RectangleL(rectangle), MonitorFromFlag.DefaultToNearest ); return monitorHandle == IntPtr.Zero ? null : new DisplayScreen(monitorHandle); } /// /// Get information about the monitor containing or the nearest to a point. /// /// The point to get the main monitor information for. /// An instance of . public static DisplayScreen FromPoint(Point point) { var monitorHandle = DeviceContextApi.MonitorFromPoint( new PointL(point), MonitorFromFlag.DefaultToNearest ); return monitorHandle == IntPtr.Zero ? null : new DisplayScreen(monitorHandle); } /// /// Get information about the screen covering the most of a window. /// /// The window handle to get the main screen information for. /// An instance of . public static DisplayScreen FromWindow(IntPtr hWnd) { if (hWnd == IntPtr.Zero) { throw new ArgumentException("Invalid window handle provided.", nameof(hWnd)); } var monitorHandle = DeviceContextApi.MonitorFromWindow( hWnd, MonitorFromFlag.DefaultToNearest ); return monitorHandle == IntPtr.Zero ? null : new DisplayScreen(monitorHandle); } #if !NETSTANDARD /// /// Returns the corresponding instance /// /// A instance of Screen object public System.Windows.Forms.Screen GetWinFormScreen() { if (!IsValid) throw new Exceptions.InvalidDisplayException(); try { return System.Windows.Forms.Screen.AllScreens.FirstOrDefault(screen => screen.DeviceName.Equals(ScreenName)); } catch { // ignored } return null; } #endif /// /// Get the corresponding instances. /// /// An array of instances. public Display[] GetDisplays() { return Display.GetDisplays().Where(display => display.ScreenName.Equals(ScreenName)).ToArray(); } /// /// Gets the bounds of the monitor /// public Rectangle Bounds { get => GetMonitorInfo()?.Bounds.ToRectangle() ?? Rectangle.Empty; } /// /// Gets the source name of the screen /// public string ScreenName { get => GetMonitorInfo()?.DisplayName; } /// /// Gets a boolean value indicating if this is the primary display /// public bool IsPrimary { get => GetMonitorInfo()?.Flags.HasFlag(MonitorInfoFlags.Primary) ?? false; } /// /// Gets a boolean value indicating if this instance contains valid information. /// public bool IsValid { get => GetMonitorInfo() != null; } /// /// Gets the working area of the monitor /// public Rectangle WorkingArea { get => GetMonitorInfo()?.WorkingArea.ToRectangle() ?? Rectangle.Empty; } /// /// Returns a list of possible display setting for this screen /// /// An enumerable list of instances public IEnumerable GetPossibleSettings() { if (!IsValid) { yield break; } var index = -1; while (true) { index++; var deviceMode = new DeviceMode(DeviceModeFields.None); if (!DeviceContextApi.EnumDisplaySettings(ScreenName, (DisplaySettingsMode)index, ref deviceMode)) { break; } yield return new DisplayPossibleSetting(deviceMode); } } /// /// Returns the best possible display setting for this screen /// /// A instance public DisplayPossibleSetting GetPreferredSetting() { return IsValid ? GetPossibleSettings() .OrderByDescending(setting => (int)setting.ColorDepth) .ThenByDescending(setting => (ulong)setting.Resolution.Width * (ulong)setting.Resolution.Height) .ThenByDescending(setting => setting.Frequency) .FirstOrDefault() : null; } /// /// Returns the corresponding instance /// /// An instance of , or null public PathDisplaySource ToPathDisplaySource() { return PathDisplaySource .GetDisplaySources() .FirstOrDefault(source => source.DisplayName.Equals(ScreenName)); } private MonitorInfo? GetMonitorInfo() { var monitorInfo = MonitorInfo.Initialize(); if (DeviceContextApi.GetMonitorInfo(_monitorHandle, ref monitorInfo)) { return monitorInfo; } return null; } } }