Windows API 获取 HDR(高动态范围)是否处于活动状态

Windows API to get whether HDR(High Dynamic Range) is active

我的环境是Windows10 20H2(64位)和Visual Studio2019.

我正在开发一个应用程序作为 C# WPF(.NET 5) 项目。我想编写一个代码,让 HDR(高动态范围)当前在系统上处于活动状态。

In this document,我得到了一些关于 Windows HDR 的提示。但是我只能找到关于 UWP 和 DirectX 的文章。

我最希望使用 .NET API 或 Win32 API。 Windows 10 提供那些 API 吗?

您可以使用 Connecting and Configuring Displays (CCD) API.

特别是 DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO 请求(在 MSDN 中没有真正记录,但在 wingdi.h 中定义)

这里是一些 C# 控制台应用程序示例代码,如果它支持 HDR 并且已启用,它会为每个监视器转储。

static void Main()
{
    var err = GetDisplayConfigBufferSizes(QDC.QDC_ONLY_ACTIVE_PATHS, out var pathCount, out var modeCount);
    if (err != 0)
        throw new Win32Exception(err);

    var paths = new DISPLAYCONFIG_PATH_INFO[pathCount];
    var modes = new DISPLAYCONFIG_MODE_INFO[modeCount];
    err = QueryDisplayConfig(QDC.QDC_ONLY_ACTIVE_PATHS, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero);
    if (err != 0)
        throw new Win32Exception(err);

    foreach (var path in paths)
    {
        // get display name
        var info = new DISPLAYCONFIG_TARGET_DEVICE_NAME();
        info.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
        info.header.size = Marshal.SizeOf<DISPLAYCONFIG_TARGET_DEVICE_NAME>();
        info.header.adapterId = path.targetInfo.adapterId;
        info.header.id = path.targetInfo.id;
        err = DisplayConfigGetDeviceInfo(ref info);
        if (err != 0)
            throw new Win32Exception(err);

        var colorInfo = new DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO();
        colorInfo.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO;
        colorInfo.header.size = Marshal.SizeOf<DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO>();
        colorInfo.header.adapterId = path.targetInfo.adapterId;
        colorInfo.header.id = path.targetInfo.id;
        err = DisplayConfigGetDeviceInfo(ref colorInfo);
        if (err != 0)
            throw new Win32Exception(err);

        Console.WriteLine(info.monitorFriendlyDeviceName);
        Console.WriteLine(" Advanced Color Supported: " + colorInfo.advancedColorSupported);
        Console.WriteLine(" Advanced Color Enabled  : " + colorInfo.advancedColorEnabled);
        Console.WriteLine();
    }
}

private enum DISPLAYCONFIG_DEVICE_INFO_TYPE
{
    DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1,
    DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2,
    DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3,
    DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4,
    DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5,
    DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6,
    DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = 7,
    DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = 8,
    DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO = 9,
    DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE = 10,
    DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL = 11,
}

private enum DISPLAYCONFIG_COLOR_ENCODING
{
    DISPLAYCONFIG_COLOR_ENCODING_RGB = 0,
    DISPLAYCONFIG_COLOR_ENCODING_YCBCR444 = 1,
    DISPLAYCONFIG_COLOR_ENCODING_YCBCR422 = 2,
    DISPLAYCONFIG_COLOR_ENCODING_YCBCR420 = 3,
    DISPLAYCONFIG_COLOR_ENCODING_INTENSITY = 4,
}

private enum DISPLAYCONFIG_SCALING
{
    DISPLAYCONFIG_SCALING_IDENTITY = 1,
    DISPLAYCONFIG_SCALING_CENTERED = 2,
    DISPLAYCONFIG_SCALING_STRETCHED = 3,
    DISPLAYCONFIG_SCALING_ASPECTRATIOCENTEREDMAX = 4,
    DISPLAYCONFIG_SCALING_CUSTOM = 5,
    DISPLAYCONFIG_SCALING_PREFERRED = 128,
}

private enum DISPLAYCONFIG_ROTATION
{
    DISPLAYCONFIG_ROTATION_IDENTITY = 1,
    DISPLAYCONFIG_ROTATION_ROTATE90 = 2,
    DISPLAYCONFIG_ROTATION_ROTATE180 = 3,
}

private enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY
{
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER = -1,
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15 = 0,
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SVIDEO = 1,
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPOSITE_VIDEO = 2,
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPONENT_VIDEO = 3,
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DVI = 4,
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI = 5,
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_LVDS = 6,
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_D_JPN = 8,
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDI = 9,
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL = 10,
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED = 11,
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EXTERNAL = 12,
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED = 13,
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDTVDONGLE = 14,
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_MIRACAST = 15,
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_WIRED = 16,
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_VIRTUAL = 17,
    DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL = unchecked((int)0x80000000),
}

private enum DISPLAYCONFIG_TOPOLOGY_ID
{
    DISPLAYCONFIG_TOPOLOGY_INTERNAL = 0x00000001,
    DISPLAYCONFIG_TOPOLOGY_CLONE = 0x00000002,
    DISPLAYCONFIG_TOPOLOGY_EXTEND = 0x00000004,
    DISPLAYCONFIG_TOPOLOGY_EXTERNAL = 0x00000008,
}

private enum DISPLAYCONFIG_PATH
{
    DISPLAYCONFIG_PATH_ACTIVE = 0x00000001,
    DISPLAYCONFIG_PATH_PREFERRED_UNSCALED = 0x00000004,
    DISPLAYCONFIG_PATH_SUPPORT_VIRTUAL_MODE = 0x00000008,
}

private enum DISPLAYCONFIG_SOURCE_FLAGS
{
    DISPLAYCONFIG_SOURCE_IN_USE = 0x00000001,
}

private enum DISPLAYCONFIG_TARGET_FLAGS
{
    DISPLAYCONFIG_TARGET_IN_USE = 0x00000001,
    DISPLAYCONFIG_TARGET_FORCIBLE = 0x00000002,
    DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_BOOT = 0x00000004,
    DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_PATH = 0x00000008,
    DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_SYSTEM = 0x00000010,
    DISPLAYCONFIG_TARGET_IS_HMD = 0x00000020,
}

private enum QDC
{
    QDC_ALL_PATHS = 0x00000001,
    QDC_ONLY_ACTIVE_PATHS = 0x00000002,
    QDC_DATABASE_CURRENT = 0x00000004,
    QDC_VIRTUAL_MODE_AWARE = 0x00000010,
    QDC_INCLUDE_HMD = 0x00000020,
}

private enum DISPLAYCONFIG_SCANLINE_ORDERING
{
    DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0,
    DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1,
    DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED = 2,
    DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_UPPERFIELDFIRST = DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED,
    DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_LOWERFIELDFIRST = 3,
}

private enum DISPLAYCONFIG_PIXELFORMAT
{
    DISPLAYCONFIG_PIXELFORMAT_8BPP = 1,
    DISPLAYCONFIG_PIXELFORMAT_16BPP = 2,
    DISPLAYCONFIG_PIXELFORMAT_24BPP = 3,
    DISPLAYCONFIG_PIXELFORMAT_32BPP = 4,
    DISPLAYCONFIG_PIXELFORMAT_NONGDI = 5,
}

private enum DISPLAYCONFIG_MODE_INFO_TYPE
{
    DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1,
    DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2,
    DISPLAYCONFIG_MODE_INFO_TYPE_DESKTOP_IMAGE = 3,
}

[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_DEVICE_INFO_HEADER
{
    public DISPLAYCONFIG_DEVICE_INFO_TYPE type;
    public int size;
    public LUID adapterId;
    public uint id;
}

[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO
{
    public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
    public uint value;
    public DISPLAYCONFIG_COLOR_ENCODING colorEncoding;
    public int bitsPerColorChannel;

    public bool advancedColorSupported => (value & 0x1) == 0x1;
    public bool advancedColorEnabled => (value & 0x2) == 0x2;
    public bool wideColorEnforced => (value & 0x4) == 0x4;
    public bool advancedColorForceDisabled => (value & 0x8) == 0x8;
}

[StructLayout(LayoutKind.Sequential)]
private struct POINTL
{
    public int x;
    public int y;
}

[StructLayout(LayoutKind.Sequential)]
private struct LUID
{
    public uint LowPart;
    public int HighPart;

    public long Value => ((long)HighPart << 32) | LowPart;
    public override string ToString() => Value.ToString();
}

[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_SOURCE_MODE
{
    public uint width;
    public uint height;
    public DISPLAYCONFIG_PIXELFORMAT pixelFormat;
    public POINTL position;
}

[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_RATIONAL
{
    public uint Numerator;
    public uint Denominator;

    public override string ToString() => Numerator + " / " + Denominator;
}

[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_2DREGION
{
    public uint cx;
    public uint cy;
}

[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO
{
    public POINTL PathSourceSize;
    public RECT DesktopImageRegion;
    public RECT DesktopImageClip;
}

[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO
{
    public ulong pixelRate;
    public DISPLAYCONFIG_RATIONAL hSyncFreq;
    public DISPLAYCONFIG_RATIONAL vSyncFreq;
    public DISPLAYCONFIG_2DREGION activeSize;
    public DISPLAYCONFIG_2DREGION totalSize;
    public uint videoStandard;
    public DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
}

[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_TARGET_MODE
{
    public DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo;
}

[StructLayout(LayoutKind.Explicit)]
private struct DISPLAYCONFIG_MODE_INFO_union
{
    [FieldOffset(0)]
    public DISPLAYCONFIG_TARGET_MODE targetMode;

    [FieldOffset(0)]
    public DISPLAYCONFIG_SOURCE_MODE sourceMode;

    [FieldOffset(0)]
    public DISPLAYCONFIG_DESKTOP_IMAGE_INFO desktopImageInfo;
}

[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_PATH_SOURCE_INFO
{
    public LUID adapterId;
    public uint id;
    public uint modeInfoIdx;
    public DISPLAYCONFIG_SOURCE_FLAGS statusFlags;
}

[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_PATH_TARGET_INFO
{
    public LUID adapterId;
    public uint id;
    public uint modeInfoIdx;
    public DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;
    public DISPLAYCONFIG_ROTATION rotation;
    public DISPLAYCONFIG_SCALING scaling;
    public DISPLAYCONFIG_RATIONAL refreshRate;
    public DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
    public bool targetAvailable;
    public DISPLAYCONFIG_TARGET_FLAGS statusFlags;
}

[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_PATH_INFO
{
    public DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo;
    public DISPLAYCONFIG_PATH_TARGET_INFO targetInfo;
    public DISPLAYCONFIG_PATH flags;
}

[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_MODE_INFO
{
    public DISPLAYCONFIG_MODE_INFO_TYPE infoType;
    public uint id;
    public LUID adapterId;
    public DISPLAYCONFIG_MODE_INFO_union info;
}

[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;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS
{
    public uint value;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct DISPLAYCONFIG_TARGET_DEVICE_NAME
{
    public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
    public DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS flags;
    public DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;
    public ushort edidManufactureId;
    public ushort edidProductCodeId;
    public uint connectorInstance;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
    public string monitorFriendlyDeviceName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
    public string monitorDevicePat;
}

[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
    public int left;
    public int top;
    public int right;
    public int bottom;
}

[DllImport("user32")]
private static extern int GetDisplayConfigBufferSizes(QDC flags, out int numPathArrayElements, out int numModeInfoArrayElements);

[DllImport("user32")]
private static extern int QueryDisplayConfig(QDC flags, ref int numPathArrayElements, [In, Out] DISPLAYCONFIG_PATH_INFO[] pathArray, ref int numModeInfoArrayElements, [In, Out] DISPLAYCONFIG_MODE_INFO[] modeInfoArray, out DISPLAYCONFIG_TOPOLOGY_ID currentTopologyId);

[DllImport("user32")]
private static extern int QueryDisplayConfig(QDC flags, ref int numPathArrayElements, [In, Out] DISPLAYCONFIG_PATH_INFO[] pathArray, ref int numModeInfoArrayElements, [In, Out] DISPLAYCONFIG_MODE_INFO[] modeInfoArray, IntPtr currentTopologyId);

[DllImport("user32")]
private static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO requestPacket);

[DllImport("user32")]
private static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_SOURCE_DEVICE_NAME requestPacket);

[DllImport("user32")]
private static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_TARGET_DEVICE_NAME requestPacket);