예제 #1
0
        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);
        }
예제 #2
0
        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());
        }