这是在 WinUI3 中获取窗口屏幕的 ScreenHeightInRawPixels、RawPixelsPerViewPixel、DiagonalSizeInInches 和 DpiChanged 事件的方法

问题描述 投票:0回答:1

我正在尝试将我的 UWP 应用程序转换为 WinUI3,但无法获取监视器信息(我的应用程序窗口所在的位置[或所属])。

我需要知道 UWP 应用程序中的以下值。

var currentViewDisplay = DisplayInformation.GetForCurrentView();
//currentViewDisplay.ScreenHeightInRawPixels
//currentViewDisplay.RawPixelsPerViewPixel
//currentViewDisplay.ScreenWidthInRawPixels
//currentViewDisplay.RawPixelsPerViewPixel;
//currentViewDisplay.DiagonalSizeInInches
//and
//currentViewDisplay.DpiChanged event

我已将 nuget CsWin32 添加到我的项目中,并尝试探索以下本机方法:

GetMonitorInfo
MonitorFromWindow
EnumDisplaySettings
EnumDisplayDevices
DisplayConfigGetDeviceInfo
IDisplayPathInterop
DISPLAYCONFIG_SOURCE_DEVICE_NAME
DISPLAYCONFIG_TARGET_DEVICE_NAME
using (var mgr = DisplayManager.Create(DisplayManagerOptions.None))
{
    var state = mgr.TryReadCurrentStateForAllTargets().State;
    foreach (var view in state.Views)
    {
        foreach (var path in view.Paths)
        {
            var monitor = path.Target.TryGetMonitor();
            if (monitor != null)
            {

            }
        }
    }

// or

var displayList = await DeviceInformation.FindAllAsync(DisplayMonitor.GetDeviceSelector());
var monitorInfo = await DisplayMonitor.FromInterfaceIdAsync(displayList[0].Id);

所有这些方法都会返回有用的信息,但我不知道如何找到我的窗口所属的监视器。

所以我尝试了下一个,但令人沮丧,因为它不返回任何内容并且只需要标头作为输入。为什么只有标题? CsWin32有问题吗?

var ip = WinRT.CastExtensions.As<winmdroot.System.WinRT.Display.IDisplayPathInterop>(path);
var sourceId = ip.GetSourceId();
var targetName = new winmdroot.Devices.Display.DISPLAYCONFIG_TARGET_DEVICE_NAME();
targetName.header.adapterId.LowPart = monitor.DisplayAdapterId.LowPart;
targetName.header.adapterId.HighPart = monitor.DisplayAdapterId.HighPart;
targetName.header.id = sourceId;
targetName.header.type = winmdroot.Devices.Display.DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
targetName.header.size = (uint)Marshal.SizeOf(typeof(winmdroot.Devices.Display.DISPLAYCONFIG_TARGET_DEVICE_NAME));
var dcgdiR = PInvoke.DisplayConfigGetDeviceInfo(ref targetName.header);
// dcgdiR == 31, what does 31 mean?

我也尝试过,并没有关于显示器物理特性的内容。 监视器是

nint
,所以只是数字...

var displayArea = DisplayArea.GetFromWindowId(window.AppWindow.Id, DisplayAreaFallback.Nearest);
var dispalyInfo = Microsoft.Graphics.Display.DisplayInformation.CreateForDisplayId(displayArea.DisplayId);
var monitor = Win32Interop.GetMonitorFromDisplayId(displayArea.DisplayId);

然后我尝试了下一个,我希望(我希望,不确定)它与我的应用程序窗口的显示器有关,并且有一些关于分辨率和 dpi 的数据,但没有关于 DiagonalSizeInInches

var devmodew = new winmdroot.Graphics.Gdi.DEVMODEW();
PInvoke.EnumDisplaySettings(null, winmdroot.Graphics.Gdi.ENUM_DISPLAY_SETTINGS_MODE.ENUM_CURRENT_SETTINGS, ref devmodew);

然后我尝试了下一个,

dv
props 有点 0 左右,没有什么用处。

var dv = new winmdroot.Graphics.Gdi.DISPLAY_DEVICEW();
uint devN = 0;
while (PInvoke.EnumDisplayDevices(null, devN, ref dv, 0) == 1)
{
  devN++;
}

为什么我错过了将所有这些关联起来? 还有其他方法吗?

winapi uwp win32com winui-3 dpi
1个回答
0
投票

物理监视器可以通过以下方式识别:

  • 显示器手柄
  • 显示名称(例如\.\DISPLAY1)
  • 设备 ID 或设备路径(例如 \?\DISPLAY#xxx#yyy#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7})
  • 设备实例 ID(例如 DISPLAY\xxx\yyy)

注意:监视器句柄与物理监视器句柄不同,从逻辑上讲,监视器句柄可以与多个物理监视器句柄关联(请参阅GetPhysicalMonitorsFromHMONITOR)。我不知道这种事什么时候发生,但我敢打赌这种情况很少见。这同样适用于显示名称。设备 ID 或设备路径通常可转换为设备实例 ID。

如何使用上述信息关联监视器上来自各种 API 的信息就像是一个谜题。

你已经有了

DisplayMonitor
,它的DeviceId就是设备ID。然后,您可以通过 MonitorFromWindow 或 MonitorFromPoint 或 MonitorFromRect 函数获取监视器句柄。接下来是连接设备 ID 和监视器句柄。其中一种方法是结合传统的 EnumDisplayDevices 和 EnumDisplayMonitors 以及 GetMonitorInfo 函数。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;

internal static class DeviceHelper
{
    public static IEnumerable<(IntPtr monitorHandle, string displayName, string deviceId, string deviceInstanceId)> EnumerateDisplayDeviceMonitorPairs()
    {
        var devices = GetDisplayDevices();

        foreach (var monitor in GetDisplayMonitors())
        {
            foreach (var device in devices.Where(x => x.displayDeviceName == monitor.displayDeviceName))
            {
                var deviceInstanceId = ConvertToDeviceInstanceId(device.monitorDeviceId);
                yield return (monitor.monitorHandle, device.displayDeviceName, device.monitorDeviceId, deviceInstanceId);
            }
        }
    }

    private static (string displayDeviceName, string monitorDeviceId)[] GetDisplayDevices()
    {
        var list = new List<(string, string)>();
        var size = (uint)Marshal.SizeOf<DISPLAY_DEVICE>();
        var display = new DISPLAY_DEVICE { cb = size };
        var monitor = new DISPLAY_DEVICE { cb = size };

        for (uint i = 0; EnumDisplayDevices(null, i, ref display, EDD_GET_DEVICE_INTERFACE_NAME); i++)
        {
            for (uint j = 0; EnumDisplayDevices(display.DeviceName, j, ref monitor, EDD_GET_DEVICE_INTERFACE_NAME); j++)
            {
                list.Add((display.DeviceName, monitor.DeviceID));
            }
        }
        return list.ToArray();
    }

    private static (string displayDeviceName, IntPtr monitorHandle)[] GetDisplayMonitors()
    {
        var list = new List<(string, IntPtr)>();
        var size = (uint)Marshal.SizeOf<MONITORINFOEX>();

        EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero,
            (monitorHandle, hdcMonitor, lprcMonitor, dwData) =>
            {
                var monitorInfo = new MONITORINFOEX { cbSize = size };
                if (GetMonitorInfo(monitorHandle, ref monitorInfo))
                {
                    list.Add((monitorInfo.szDevice, monitorHandle));
                }
                return true;
            }, IntPtr.Zero);
        return list.ToArray();
    }

    private static string ConvertToDeviceInstanceId(string? deviceId)
    {
        if (!string.IsNullOrEmpty(deviceId))
        {
            var pattern = new Regex(@"\\\?\\DISPLAY#(?<hardware>\w+)#(?<instance>[\w|&]+)#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}");
            var match = pattern.Match(deviceId);
            if (match.Success)
            {
                return $@"DISPLAY\{match.Groups["hardware"]}\{match.Groups["instance"]}";
            }
        }
        return string.Empty;
    }

    [DllImport("User32.dll", CharSet = CharSet.Ansi)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool EnumDisplayDevices(
        string? lpDevice,
        uint iDevNum,
        ref DISPLAY_DEVICE lpDisplayDevice,
        uint dwFlags);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    private struct DISPLAY_DEVICE
    {
        public uint cb;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
        public string DeviceName;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string DeviceString;

        public uint StateFlags;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string DeviceID;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
        public string DeviceKey;
    }

    private const uint EDD_GET_DEVICE_INTERFACE_NAME = 0x00000001;

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

    [return: MarshalAs(UnmanagedType.Bool)]
    private delegate bool MonitorEnumProc(
        IntPtr hMonitor,
        IntPtr hdcMonitor,
        IntPtr lprcMonitor,
        IntPtr dwData);

    [DllImport("User32.dll", CharSet = CharSet.Unicode)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetMonitorInfo(
        IntPtr hMonitor,
        ref MONITORINFOEX lpmi);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct MONITORINFOEX
    {
        public uint cbSize;
        public RECT rcMonitor;
        public RECT rcWork;
        public uint dwFlags;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
        public string szDevice;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.