public static MonitorInfo GetMonitorFromWindowHandle(IntPtr handle) { if (handle == IntPtr.Zero) { throw Log.ErrorAndCreateException((string errorMessage) => new ArgumentException(errorMessage, nameof(handle)), "Pointer has been initialized to zero"); } // Get screen from window handle var monitorHandle = NativeMethods.MonitorFromWindow(handle, 0); var nativeInfo = NativeMonitorInfoEx.Initialize(); var success = NativeMethods.GetMonitorInfo(monitorHandle, ref nativeInfo); if (!success) { return(null); } // note: can this cause issues when monitor mirror, probably need to check DisplayDeviceStateFlag? var outputDevice = GetOutputDevicesForDevice(nativeInfo.GetDeviceName())?.FirstOrDefault(); if (outputDevice is null || outputDevice.Value.Size == 0) { return(null); } var displayConfigs = GetDisplayConfigs(); // Get dpi var dpiScale = new DpiScale(); NativeMethods.GetDpiForMonitor(monitorHandle, DpiType.Effective, out var dpiScaleX, out var dpiScaleY); if (dpiScaleX > 0 && dpiScaleY > 0) { dpiScale.SetScaleFromAbsolute(dpiScaleX, dpiScaleY); } var matchedDisplayConfig = displayConfigs.FirstOrDefault(c => string.Equals(c.MonitorDevicePath, outputDevice.Value.DeviceId)); var di = new MonitorInfo { DeviceName = nativeInfo.GetDeviceName(), ScreenWidth = nativeInfo.Monitor.GetWidth().ToString(), ScreenHeight = nativeInfo.Monitor.GetHeight().ToString(), MonitorArea = nativeInfo.Monitor.ToInt32Rect(), WorkingArea = nativeInfo.Work.ToInt32Rect(), Availability = nativeInfo.Flags.ToString(), IsPrimary = nativeInfo.Flags == 1, FriendlyName = string.IsNullOrEmpty(matchedDisplayConfig.MonitorFriendDeviceName) ? outputDevice.Value.DeviceString : matchedDisplayConfig.MonitorFriendDeviceName, DeviceNameFull = outputDevice.Value.DeviceName, AdapterDeviceName = nativeInfo.GetDeviceName(), DpiScale = dpiScale }; return(di); }
public static MonitorInfo[] GetAllMonitors(bool throwErrorsForWrongAppManifest = true) { if (throwErrorsForWrongAppManifest) { // Step 1: check DPI awareness, must be PerMonitor NativeMethods.GetProcessDpiAwareness(Process.GetCurrentProcess().Handle, out var awareness); if (awareness != DpiAwareness.ProcessPerMonitor) { throw Log.ErrorAndCreateException <NotSupportedException>("Application manifest is incorrect to retrieve reliable monitor info, see https://github.com/wildgums/orchestra/364 for more info"); } // Step 2: check whether app is dpi-aware (should be false) // Or shall we just override? //var result = SetProcessDpiAwareness(PROCESS_DPI_AWARENESS.ProcessPerMonitor); //GetProcessDpiAwareness(Process.GetCurrentProcess().Handle, out awareness); } var monitorInfos = new List <MonitorInfo>(); var videoAdapters = new List <DisplayDevice>(); var adapterIndex = -1; // Step 3: Go through Video Adapters Outputs while (true) { adapterIndex++; var adapter = DisplayDevice.Initialize(); if (!NativeMethods.EnumDisplayDevices(null, (uint)adapterIndex, ref adapter, 0)) { break; } videoAdapters.Add(adapter); } var displayDevicesToAdapter = new Dictionary <DisplayDevice, string>(); // Step 4: Step into each device attached to every output and find out monitor devices foreach (var adapter in videoAdapters) { var displayIndex = -1; while (true) { displayIndex++; var display = DisplayDevice.Initialize(); if (!NativeMethods.EnumDisplayDevices(adapter.DeviceName, (uint)displayIndex, ref display, 1)) { break; } displayDevicesToAdapter[display] = adapter.DeviceName; } } var nativeMonitorInfos = new Dictionary <NativeMonitorInfoEx, IntPtr>(); var displayConfigs = GetDisplayConfigs(); // Step 5: Enumerate available monitors NativeMethods.EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, delegate(IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData) { var monitorInfo = NativeMonitorInfoEx.Initialize(); var success = NativeMethods.GetMonitorInfo(hMonitor, ref monitorInfo); if (success) { nativeMonitorInfos.Add(monitorInfo, hMonitor); // add handle, we can use it later to get dpi } return(true); }, IntPtr.Zero); // Step 6: Compare native infos from GetMonitorInfo with display devices foreach (var keyValuePair in displayDevicesToAdapter) { var displayDevice = keyValuePair.Key; var adapterDeviceName = keyValuePair.Value; var nativeMonitorInfoAndHandle = nativeMonitorInfos.FirstOrDefault(x => string.Equals(x.Key.GetDeviceName(), adapterDeviceName)); var nativeMonitorInfo = nativeMonitorInfoAndHandle.Key; if (nativeMonitorInfo == default) { // then this monitor is disabled or in some invalid state continue; } var monitorHandle = nativeMonitorInfoAndHandle.Value; // Get dpi var dpiScale = new DpiScale(); NativeMethods.GetDpiForMonitor(monitorHandle, DpiType.Effective, out var dpiScaleX, out var dpiScaleY); if (dpiScaleX > 0 && dpiScaleY > 0) { dpiScale.SetScaleFromAbsolute(dpiScaleX, dpiScaleY); } var matchedDisplayConfig = displayConfigs.FirstOrDefault(c => string.Equals(c.MonitorDevicePath, displayDevice.DeviceId)); var di = new MonitorInfo { DeviceName = nativeMonitorInfo.GetDeviceName(), ScreenWidth = nativeMonitorInfo.Monitor.GetWidth().ToString(), ScreenHeight = nativeMonitorInfo.Monitor.GetHeight().ToString(), MonitorArea = nativeMonitorInfo.Monitor.ToInt32Rect(), WorkingArea = nativeMonitorInfo.Work.ToInt32Rect(), Availability = nativeMonitorInfo.Flags.ToString(), IsPrimary = nativeMonitorInfo.Flags == 1, FriendlyName = string.IsNullOrEmpty(matchedDisplayConfig.MonitorFriendDeviceName) ? displayDevice.DeviceString : matchedDisplayConfig.MonitorFriendDeviceName, DeviceNameFull = displayDevice.DeviceName, AdapterDeviceName = adapterDeviceName, DpiScale = dpiScale, ProductCodeId = matchedDisplayConfig.EDIDProductCodeId, ManufactureCode = ConvertEDIDManufactureIdToCode(matchedDisplayConfig.EDIDManufactureId) }; monitorInfos.Add(di); } return(monitorInfos.ToArray()); }