我想向用户显示一个下拉列表,其中除了每个条目之外还显示设备名称(如 Windows 分辨率设置)。我可以通过
Windows.Devices.Display.DisplayMonitor
和相关 API 来完成此操作,如下所示:
private async Task CollectMonitors() {
var displays = await DeviceInformation.FindAllAsync(DisplayMonitor.GetDeviceSelector());
List<DisplayMonitor> displayMonitors = new List<DisplayMonitor>();
foreach (var display in displays)
{
displayMonitors.Add(await DisplayMonitor.FromInterfaceIdAsync(display.Id));
}
// etc...
}
现在,
displayMonitors
包含所有显示器,并且每个显示器都有一个DisplayName
属性,这正是Windows屏幕分辨率设置显示的内容(例如"DELL P2422H"
),以及一个DeviceId
(例如\\?\DISPLAY#DELA1C5#4&b8ecaec&0&UID24627#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
) ) 每个设备都是唯一的。
它不会告诉我以下非常重要的信息,我需要这些信息才能实际使用所选屏幕在其上放置 WPF 窗口:
此信息由
System.Windows.Forms.Screen.AllScreens
提供。我对这个 API 的问题是,它不包括我需要向用户显示的 DisplayName
(如 "DELL P2422H"
)。
我现在的问题是:
DisplayMonitor
映射到 Forms.Screen
吗?这将是最简单的解决方案。我找不到每个监视器唯一且由这两个 API/结果共享的任何标识符。没有文档说明 Forms.Screen.AllScreens
中的屏幕顺序是否与通过 DisplayMonitors
枚举 DeviceInformation.FindAllAsync
返回的顺序有关,所以可能不是(?)。DisplayMonitor
、或从 EDID、或从 DisplayMonitor
API 提供的任何其他信息或从任何相关 API 获取工作区域的范围我可以在这里使用吗?相关链接:
DisplayMonitor
API:https://learn.microsoft.com/en-us/uwp/api/windows.devices.display.displaymonitorForms.Screen
API:https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.screen这是不是相关问题的回答,这些问题要么a)不提及显示名称,要么b)不提及工作区域/在显示器上生成WPF窗口。
将 WinRT 类与 GDI/GDI+ 类链接起来并不容易,因为 WinRT 类不会公开 GDI 的设备名称,例如 Winforms 使用的
\\?\DISPLAY1
(也可以从 WPF 使用)。
因此您可以使用连接和配置显示器 (CCD) Win32 API(顺便说一句,这是 WinRT 类用来获取显示器的显示名称等的内容。您还可以使用它们来确定 HDR 是否打开/关闭Windows用于获取 HDR(高动态范围)是否处于活动状态的 API),以根据适配器 ID 确定 GDI 设备名称:
public static string GetGdiDeviceName(int adapterIdHigh, uint adapterIdLow, uint sourceId)
{
var info = new DISPLAYCONFIG_SOURCE_DEVICE_NAME();
const int DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1;
info.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
info.header.size = Marshal.SizeOf<DISPLAYCONFIG_SOURCE_DEVICE_NAME>();
info.header.adapterIdHigh = adapterIdHigh;
info.header.adapterIdLow = adapterIdLow;
info.header.id = sourceId;
var err = DisplayConfigGetDeviceInfo(ref info);
if (err != 0)
throw new Win32Exception(err);
return info.viewGdiDeviceName;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct DISPLAYCONFIG_SOURCE_DEVICE_NAME
{
public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string viewGdiDeviceName;
public override string ToString() => viewGdiDeviceName;
}
[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_DEVICE_INFO_HEADER
{
public int type;
public int size;
public uint adapterIdLow;
public int adapterIdHigh;
public uint id;
}
[DllImport("user32")]
private static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_SOURCE_DEVICE_NAME requestPacket);
但这需要一个“SourceId”,您可以使用 IDisplayPathInterop 接口从 WinRT 获取
[ComImport, Guid("A6BA4205-E59E-4E71-B25B-4E436D21EE3D"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDisplayPathInterop
{
[PreserveSig]
int CreateSourcePresentationHandle(out IntPtr value);
[PreserveSig]
int GetSourceId(out uint sourceId);
}
现在您可以使用所有这些来转储最大数量的信息,例如这个 C# 控制台应用程序:
static void Main()
{
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)
{
Console.WriteLine(monitor.DisplayName);
var ip = (object)path as IDisplayPathInterop;
ip.GetSourceId(out var sourceId);
var gdiDeviceName = GetGdiDeviceName(monitor.DisplayAdapterId.HighPart, monitor.DisplayAdapterId.LowPart, sourceId);
Console.WriteLine(" GDI Name : " + gdiDeviceName);
// use gdiDeviceName to correlate with other APIs such as Screen from Winforms
var screen = Screen.AllScreens.FirstOrDefault(s => s.DeviceName == gdiDeviceName);
Console.WriteLine(" Is Primary : " + screen.Primary);
Console.WriteLine(" Working Area : " + screen.WorkingArea);
Console.WriteLine();
}
}
}
}
}
将输出类似这样的内容(2个显示器):
DELL U2715H
GDI Name : \\.\DISPLAY1
Is Primary : False
Working Area : {X=2560,Y=0,Width=2560,Height=1392}
C27HG7x
GDI Name : \\.\DISPLAY2
Is Primary : True
Working Area : {X=0,Y=0,Width=2560,Height=1392}