DisplayMagician/DisplayMagicianShared/Windows/WinLibrary.cs
Terry MacDonald b6bd89bed2 Updated NVIDIALibrary and WinLibrary based on NVIDIAInfo testing
Added in the ability to map the Windows CCD Display name to NVAPI DisplayId, which will make it possible to use that information within DisplayMagician.
2021-09-01 20:44:00 +12:00

1236 lines
83 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;
using DisplayMagicianShared;
using System.ComponentModel;
using System.Text.RegularExpressions;
namespace DisplayMagicianShared.Windows
{
[StructLayout(LayoutKind.Sequential)]
public struct ADVANCED_HDR_INFO_PER_PATH : IEquatable<ADVANCED_HDR_INFO_PER_PATH>
{
public LUID AdapterId;
public uint Id;
public DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO AdvancedColorInfo;
public DISPLAYCONFIG_SDR_WHITE_LEVEL SDRWhiteLevel;
public override bool Equals(object obj) => obj is ADVANCED_HDR_INFO_PER_PATH other && this.Equals(other);
public bool Equals(ADVANCED_HDR_INFO_PER_PATH other)
=> // AdapterId.Equals(other.AdapterId) && // Removed the AdapterId from the Equals, as it changes after reboot.
Id == other.Id &&
AdvancedColorInfo.Equals(other.AdvancedColorInfo) &&
SDRWhiteLevel.Equals(other.SDRWhiteLevel);
public override int GetHashCode()
{
return (Id, AdvancedColorInfo, SDRWhiteLevel).GetHashCode();
}
public static bool operator ==(ADVANCED_HDR_INFO_PER_PATH lhs, ADVANCED_HDR_INFO_PER_PATH rhs) => lhs.Equals(rhs);
public static bool operator !=(ADVANCED_HDR_INFO_PER_PATH lhs, ADVANCED_HDR_INFO_PER_PATH rhs) => !(lhs == rhs);
}
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWS_DISPLAY_CONFIG : IEquatable<WINDOWS_DISPLAY_CONFIG>
{
public Dictionary<ulong, string> DisplayAdapters;
public DISPLAYCONFIG_PATH_INFO[] DisplayConfigPaths;
public DISPLAYCONFIG_MODE_INFO[] DisplayConfigModes;
public ADVANCED_HDR_INFO_PER_PATH[] DisplayHDRStates;
public Dictionary<uint, string> DisplaySources;
public List<string> DisplayIdentifiers;
public override bool Equals(object obj) => obj is WINDOWS_DISPLAY_CONFIG other && this.Equals(other);
public bool Equals(WINDOWS_DISPLAY_CONFIG other)
=> DisplayConfigPaths.SequenceEqual(other.DisplayConfigPaths) &&
DisplayConfigModes.SequenceEqual(other.DisplayConfigModes) &&
DisplayHDRStates.SequenceEqual(other.DisplayHDRStates);
public override int GetHashCode()
{
return (DisplayConfigPaths, DisplayConfigModes, DisplayHDRStates).GetHashCode();
}
public static bool operator ==(WINDOWS_DISPLAY_CONFIG lhs, WINDOWS_DISPLAY_CONFIG rhs) => lhs.Equals(rhs);
public static bool operator !=(WINDOWS_DISPLAY_CONFIG lhs, WINDOWS_DISPLAY_CONFIG rhs) => !(lhs == rhs);
}
public class WinLibrary : IDisposable
{
// Static members are 'eagerly initialized', that is,
// immediately when class is loaded for the first time.
// .NET guarantees thread safety for static initialization
private static WinLibrary _instance = new WinLibrary();
private bool _initialised = false;
// To detect redundant calls
private bool _disposed = false;
// Instantiate a SafeHandle instance.
private SafeHandle _safeHandle = new SafeFileHandle(IntPtr.Zero, true);
private IntPtr _adlContextHandle = IntPtr.Zero;
static WinLibrary() { }
public WinLibrary()
{
SharedLogger.logger.Trace("WinLibrary/WinLibrary: Intialising Windows CCD library interface");
_initialised = true;
}
~WinLibrary()
{
// The WinLibrary was initialised, but doesn't need to be freed.
SharedLogger.logger.Trace("WinLibrary/~WinLibrary: Destroying Windows CCD library interface");
}
// Public implementation of Dispose pattern callable by consumers.
public void Dispose() => Dispose(true);
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
// Dispose managed state (managed objects).
_safeHandle?.Dispose();
}
_disposed = true;
}
public bool IsInstalled
{
get
{
return _initialised;
}
}
public static WinLibrary GetLibrary()
{
return _instance;
}
private void PatchAdapterIDs(ref WINDOWS_DISPLAY_CONFIG savedDisplayConfig, Dictionary<ulong, string> currentAdapterMap)
{
Dictionary<ulong, ulong> adapterOldToNewMap = new Dictionary<ulong, ulong>();
SharedLogger.logger.Trace("WinLibrary/PatchAdapterIDs: Going through the list of adapters we stored in the config to figure out the old adapterIDs");
foreach (KeyValuePair<ulong, string> savedAdapter in savedDisplayConfig.DisplayAdapters)
{
foreach (KeyValuePair<ulong, string> currentAdapter in currentAdapterMap)
{
if (currentAdapter.Value.Equals(savedAdapter.Value))
{
// we have found the new LUID Value for the same adapter
// So we want to store it
SharedLogger.logger.Trace($"WinLibrary/PatchAdapterIDs: We found that saved adapter {savedAdapter.Key} has now been assigned adapter id {currentAdapter.Key} (AdapterName is {savedAdapter.Value})");
adapterOldToNewMap.Add(savedAdapter.Key, currentAdapter.Key);
}
}
}
ulong newAdapterValue = 0;
// Update the paths with the current adapter id
SharedLogger.logger.Trace($"WinLibrary/PatchAdapterIDs: Going through the display config paths to update the adapter id");
for (int i = 0; i < savedDisplayConfig.DisplayConfigPaths.Length; i++)
{
// Change the Path SourceInfo and TargetInfo AdapterIDs
if (adapterOldToNewMap.ContainsKey(savedDisplayConfig.DisplayConfigPaths[i].SourceInfo.AdapterId.Value))
{
// We get here if there is a matching adapter
newAdapterValue = adapterOldToNewMap[savedDisplayConfig.DisplayConfigPaths[i].SourceInfo.AdapterId.Value];
savedDisplayConfig.DisplayConfigPaths[i].SourceInfo.AdapterId = AdapterValueToLUID(newAdapterValue);
newAdapterValue = adapterOldToNewMap[savedDisplayConfig.DisplayConfigPaths[i].TargetInfo.AdapterId.Value];
savedDisplayConfig.DisplayConfigPaths[i].TargetInfo.AdapterId = AdapterValueToLUID(newAdapterValue);
}
else
{
// if there isn't a matching adapter, then we just pick the first current one and hope that works!
// (it is highly likely to... its only if the user has multiple graphics cards with some weird config it may break)
newAdapterValue = currentAdapterMap.First().Key;
SharedLogger.logger.Warn($"WinLibrary/PatchAdapterIDs: Uh Oh. Adapter {savedDisplayConfig.DisplayConfigPaths[i].SourceInfo.AdapterId.Value} didn't have a current match! It's possible the adapter was swapped or disabled. Attempting to use adapter {newAdapterValue} instead.");
savedDisplayConfig.DisplayConfigPaths[i].SourceInfo.AdapterId = AdapterValueToLUID(newAdapterValue);
savedDisplayConfig.DisplayConfigPaths[i].TargetInfo.AdapterId = AdapterValueToLUID(newAdapterValue);
}
}
SharedLogger.logger.Trace($"WinLibrary/PatchAdapterIDs: Going through the display config modes to update the adapter id");
// Update the modes with the current adapter id
for (int i = 0; i < savedDisplayConfig.DisplayConfigModes.Length; i++)
{
// Change the Mode AdapterID
if (adapterOldToNewMap.ContainsKey(savedDisplayConfig.DisplayConfigModes[i].AdapterId.Value))
{
// We get here if there is a matching adapter
newAdapterValue = adapterOldToNewMap[savedDisplayConfig.DisplayConfigModes[i].AdapterId.Value];
savedDisplayConfig.DisplayConfigModes[i].AdapterId = AdapterValueToLUID(newAdapterValue);
}
else
{
// if there isn't a matching adapter, then we just pick the first current one and hope that works!
// (it is highly likely to... its only if the user has multiple graphics cards with some weird config it may break)
newAdapterValue = currentAdapterMap.First().Key;
SharedLogger.logger.Warn($"WinLibrary/PatchAdapterIDs: Uh Oh. Adapter {savedDisplayConfig.DisplayConfigModes[i].AdapterId.Value} didn't have a current match! It's possible the adapter was swapped or disabled. Attempting to use adapter {newAdapterValue} instead.");
savedDisplayConfig.DisplayConfigModes[i].AdapterId = AdapterValueToLUID(newAdapterValue);
}
}
SharedLogger.logger.Trace($"WinLibrary/PatchAdapterIDs: Going through the display config HDR info to update the adapter id");
// Update the HDRInfo with the current adapter id
for (int i = 0; i < savedDisplayConfig.DisplayHDRStates.Length; i++)
{
// Change the Mode AdapterID
if (adapterOldToNewMap.ContainsKey(savedDisplayConfig.DisplayHDRStates[i].AdapterId.Value))
{
// We get here if there is a matching adapter
newAdapterValue = adapterOldToNewMap[savedDisplayConfig.DisplayHDRStates[i].AdapterId.Value];
savedDisplayConfig.DisplayHDRStates[i].AdapterId = AdapterValueToLUID(newAdapterValue);
newAdapterValue = adapterOldToNewMap[savedDisplayConfig.DisplayHDRStates[i].AdvancedColorInfo.Header.AdapterId.Value];
savedDisplayConfig.DisplayHDRStates[i].AdvancedColorInfo.Header.AdapterId = AdapterValueToLUID(newAdapterValue);
newAdapterValue = adapterOldToNewMap[savedDisplayConfig.DisplayHDRStates[i].SDRWhiteLevel.Header.AdapterId.Value];
savedDisplayConfig.DisplayHDRStates[i].SDRWhiteLevel.Header.AdapterId = AdapterValueToLUID(newAdapterValue);
}
else
{
// if there isn't a matching adapter, then we just pick the first current one and hope that works!
// (it is highly likely to... its only if the user has multiple graphics cards with some weird config it may break)
newAdapterValue = currentAdapterMap.First().Key;
SharedLogger.logger.Warn($"WinLibrary/PatchAdapterIDs: Uh Oh. Adapter {savedDisplayConfig.DisplayHDRStates[i].AdapterId.Value} didn't have a current match! It's possible the adapter was swapped or disabled. Attempting to use adapter {newAdapterValue} instead.");
savedDisplayConfig.DisplayHDRStates[i].AdapterId = AdapterValueToLUID(newAdapterValue);
savedDisplayConfig.DisplayHDRStates[i].AdvancedColorInfo.Header.AdapterId = AdapterValueToLUID(newAdapterValue);
savedDisplayConfig.DisplayHDRStates[i].SDRWhiteLevel.Header.AdapterId = AdapterValueToLUID(newAdapterValue);
}
}
}
public WINDOWS_DISPLAY_CONFIG GetActiveConfig()
{
SharedLogger.logger.Trace($"WinLibrary/GetActiveConfig: Getting the currently active config");
return GetWindowsDisplayConfig(QDC.QDC_ONLY_ACTIVE_PATHS);
}
private WINDOWS_DISPLAY_CONFIG GetWindowsDisplayConfig(QDC selector = QDC.QDC_ONLY_ACTIVE_PATHS)
{
// Get the size of the largest Active Paths and Modes arrays
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Getting the size of the largest Active Paths and Modes arrays");
int pathCount = 0;
int modeCount = 0;
WIN32STATUS err = CCDImport.GetDisplayConfigBufferSizes(QDC.QDC_ONLY_ACTIVE_PATHS, out pathCount, out modeCount);
if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/GetWindowsDisplayConfig: ERROR - GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes");
throw new WinLibraryException($"GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes");
}
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Getting the current Display Config path and mode arrays");
var paths = new DISPLAYCONFIG_PATH_INFO[pathCount];
var modes = new DISPLAYCONFIG_MODE_INFO[modeCount];
err = CCDImport.QueryDisplayConfig(QDC.QDC_ONLY_ACTIVE_PATHS, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero);
if (err == WIN32STATUS.ERROR_INSUFFICIENT_BUFFER)
{
SharedLogger.logger.Warn($"WinLibrary/GetWindowsDisplayConfig: The displays were modified between GetDisplayConfigBufferSizes and QueryDisplayConfig so we need to get the buffer sizes again.");
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Getting the size of the largest Active Paths and Modes arrays");
// Screen changed in between GetDisplayConfigBufferSizes and QueryDisplayConfig, so we need to get buffer sizes again
// as per https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-querydisplayconfig
err = CCDImport.GetDisplayConfigBufferSizes(QDC.QDC_ONLY_ACTIVE_PATHS, out pathCount, out modeCount);
if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/GetWindowsDisplayConfig: ERROR - GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes again");
throw new WinLibraryException($"GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes again");
}
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Getting the current Display Config path and mode arrays");
paths = new DISPLAYCONFIG_PATH_INFO[pathCount];
modes = new DISPLAYCONFIG_MODE_INFO[modeCount];
err = CCDImport.QueryDisplayConfig(QDC.QDC_ONLY_ACTIVE_PATHS, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero);
if (err == WIN32STATUS.ERROR_INSUFFICIENT_BUFFER)
{
SharedLogger.logger.Error($"WinLibrary/GetWindowsDisplayConfig: ERROR - The displays were still modified between GetDisplayConfigBufferSizes and QueryDisplayConfig, even though we tried twice. Something is wrong.");
throw new WinLibraryException($"The displays were still modified between GetDisplayConfigBufferSizes and QueryDisplayConfig, even though we tried twice. Something is wrong.");
}
else if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/GetWindowsDisplayConfig: ERROR - QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays again");
throw new WinLibraryException($"QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays again.");
}
}
else if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/GetWindowsDisplayConfig: ERROR - QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays");
throw new WinLibraryException($"QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays.");
}
// Prepare the empty windows display config
WINDOWS_DISPLAY_CONFIG windowsDisplayConfig = new WINDOWS_DISPLAY_CONFIG();
windowsDisplayConfig.DisplayAdapters = new Dictionary<ulong, string>();
windowsDisplayConfig.DisplayHDRStates = new ADVANCED_HDR_INFO_PER_PATH[pathCount];
windowsDisplayConfig.DisplaySources = new Dictionary<uint, string>();
// Now cycle through the paths and grab the HDR state information
// and map the adapter name to adapter id
var hdrInfos = new ADVANCED_HDR_INFO_PER_PATH[pathCount];
int hdrInfoCount = 0;
foreach (var path in paths)
{
// get display source name
var sourceInfo = new DISPLAYCONFIG_SOURCE_DEVICE_NAME();
sourceInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
sourceInfo.Header.Size = (uint)Marshal.SizeOf<DISPLAYCONFIG_SOURCE_DEVICE_NAME>();
sourceInfo.Header.AdapterId = path.SourceInfo.AdapterId;
sourceInfo.Header.Id = path.SourceInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref sourceInfo);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
// Store it for later
windowsDisplayConfig.DisplaySources.Add(path.SourceInfo.Id, sourceInfo.ViewGdiDeviceName);
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Display Source {sourceInfo.ViewGdiDeviceName} for source {path.SourceInfo.Id}.");
}
else
{
SharedLogger.logger.Warn($"WinLibrary/PrintActiveConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the source info for source adapter #{path.SourceInfo.AdapterId}");
}
// Get adapter ID for later
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Attempting to get adapter name for adapter {path.TargetInfo.AdapterId.Value}.");
if (!windowsDisplayConfig.DisplayAdapters.ContainsKey(path.TargetInfo.AdapterId.Value))
{
var adapterInfo = new DISPLAYCONFIG_ADAPTER_NAME();
adapterInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME;
adapterInfo.Header.Size = (uint)Marshal.SizeOf<DISPLAYCONFIG_ADAPTER_NAME>();
adapterInfo.Header.AdapterId = path.TargetInfo.AdapterId;
adapterInfo.Header.Id = path.TargetInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref adapterInfo);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
// Store it for later
windowsDisplayConfig.DisplayAdapters.Add(path.TargetInfo.AdapterId.Value, adapterInfo.AdapterDevicePath);
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found adapter name {adapterInfo.AdapterDevicePath} for adapter {path.TargetInfo.AdapterId.Value}.");
}
else
{
SharedLogger.logger.Error($"WinLibrary/GetWindowsDisplayConfig: ERROR - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to query the adapter name for adapter {path.TargetInfo.AdapterId.Value}.");
}
}
// Get advanced color info
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Attempting to get advanced color info for display {path.TargetInfo.Id}.");
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 = (uint)Marshal.SizeOf<DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO>();
colorInfo.Header.AdapterId = path.TargetInfo.AdapterId;
colorInfo.Header.Id = path.TargetInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref colorInfo);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found color info for display {path.TargetInfo.Id}.");
if (colorInfo.AdvancedColorSupported)
{
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: HDR is supported for display {path.TargetInfo.Id}.");
}
else
{
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: HDR is NOT supported for display {path.TargetInfo.Id}.");
}
if (colorInfo.AdvancedColorEnabled)
{
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: HDR is enabled for display {path.TargetInfo.Id}.");
}
else
{
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: HDR is NOT enabled for display {path.TargetInfo.Id}.");
}
}
else
{
SharedLogger.logger.Warn($"WinLibrary/GetWindowsDisplayConfig: WARNING - Unabled to get advanced color settings for display {path.TargetInfo.Id}.");
}
// get SDR white levels
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Attempting to get SDR white levels for adapter {path.TargetInfo.AdapterId.Value}.");
var whiteLevelInfo = new DISPLAYCONFIG_SDR_WHITE_LEVEL();
whiteLevelInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL;
whiteLevelInfo.Header.Size = (uint)Marshal.SizeOf<DISPLAYCONFIG_SDR_WHITE_LEVEL>();
whiteLevelInfo.Header.AdapterId = path.TargetInfo.AdapterId;
whiteLevelInfo.Header.Id = path.TargetInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref whiteLevelInfo);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found SDR White levels for display {path.TargetInfo.Id}.");
}
else
{
SharedLogger.logger.Warn($"WinLibrary/GetWindowsDisplayConfig: WARNING - Unabled to get SDR White levels for display {path.TargetInfo.Id}.");
}
hdrInfos[hdrInfoCount] = new ADVANCED_HDR_INFO_PER_PATH();
hdrInfos[hdrInfoCount].AdapterId = path.TargetInfo.AdapterId;
hdrInfos[hdrInfoCount].Id = path.TargetInfo.Id;
hdrInfos[hdrInfoCount].AdvancedColorInfo = colorInfo;
hdrInfos[hdrInfoCount].SDRWhiteLevel = whiteLevelInfo;
hdrInfoCount++;
}
// Store the active paths and modes in our display config object
windowsDisplayConfig.DisplayConfigPaths = paths;
windowsDisplayConfig.DisplayConfigModes = modes;
windowsDisplayConfig.DisplayHDRStates = hdrInfos;
windowsDisplayConfig.DisplayIdentifiers = GetCurrentDisplayIdentifiers();
return windowsDisplayConfig;
}
public static Dictionary<uint, string> GetDisplaySourceNames()
{
// Get the size of the largest Active Paths and Modes arrays
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Getting the size of the largest Active Paths and Modes arrays");
int pathCount = 0;
int modeCount = 0;
WIN32STATUS err = CCDImport.GetDisplayConfigBufferSizes(QDC.QDC_ONLY_ACTIVE_PATHS, out pathCount, out modeCount);
if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/GetWindowsDisplayConfig: ERROR - GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes");
throw new WinLibraryException($"GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes");
}
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Getting the current Display Config path and mode arrays");
var paths = new DISPLAYCONFIG_PATH_INFO[pathCount];
var modes = new DISPLAYCONFIG_MODE_INFO[modeCount];
err = CCDImport.QueryDisplayConfig(QDC.QDC_ONLY_ACTIVE_PATHS, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero);
if (err == WIN32STATUS.ERROR_INSUFFICIENT_BUFFER)
{
SharedLogger.logger.Warn($"WinLibrary/GetWindowsDisplayConfig: The displays were modified between GetDisplayConfigBufferSizes and QueryDisplayConfig so we need to get the buffer sizes again.");
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Getting the size of the largest Active Paths and Modes arrays");
// Screen changed in between GetDisplayConfigBufferSizes and QueryDisplayConfig, so we need to get buffer sizes again
// as per https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-querydisplayconfig
err = CCDImport.GetDisplayConfigBufferSizes(QDC.QDC_ONLY_ACTIVE_PATHS, out pathCount, out modeCount);
if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/GetWindowsDisplayConfig: ERROR - GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes again");
throw new WinLibraryException($"GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes again");
}
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Getting the current Display Config path and mode arrays");
paths = new DISPLAYCONFIG_PATH_INFO[pathCount];
modes = new DISPLAYCONFIG_MODE_INFO[modeCount];
err = CCDImport.QueryDisplayConfig(QDC.QDC_ONLY_ACTIVE_PATHS, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero);
if (err == WIN32STATUS.ERROR_INSUFFICIENT_BUFFER)
{
SharedLogger.logger.Error($"WinLibrary/GetWindowsDisplayConfig: ERROR - The displays were still modified between GetDisplayConfigBufferSizes and QueryDisplayConfig, even though we tried twice. Something is wrong.");
throw new WinLibraryException($"The displays were still modified between GetDisplayConfigBufferSizes and QueryDisplayConfig, even though we tried twice. Something is wrong.");
}
else if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/GetWindowsDisplayConfig: ERROR - QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays again");
throw new WinLibraryException($"QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays again.");
}
}
else if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/GetWindowsDisplayConfig: ERROR - QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays");
throw new WinLibraryException($"QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays.");
}
// Prepare the empty DisplaySources dictionary
Dictionary<uint, string> DisplaySources = new Dictionary<uint, string>();
// Now cycle through the paths and grab the HDR state information
// and map the adapter name to adapter id
var hdrInfos = new ADVANCED_HDR_INFO_PER_PATH[pathCount];
int hdrInfoCount = 0;
foreach (var path in paths)
{
// get display source name
var sourceInfo = new DISPLAYCONFIG_SOURCE_DEVICE_NAME();
sourceInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
sourceInfo.Header.Size = (uint)Marshal.SizeOf<DISPLAYCONFIG_SOURCE_DEVICE_NAME>();
sourceInfo.Header.AdapterId = path.SourceInfo.AdapterId;
sourceInfo.Header.Id = path.SourceInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref sourceInfo);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
// Store it for later
DisplaySources.Add(path.SourceInfo.Id, sourceInfo.ViewGdiDeviceName);
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Display Source {sourceInfo.ViewGdiDeviceName} for source {path.SourceInfo.Id}.");
}
else
{
SharedLogger.logger.Warn($"WinLibrary/PrintActiveConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the source info for source adapter #{path.SourceInfo.AdapterId}");
}
}
return DisplaySources;
}
private LUID AdapterValueToLUID(ulong adapterValue)
{
LUID luid = new LUID();
luid.LowPart = (uint)(adapterValue & uint.MaxValue);
luid.HighPart = (uint)(adapterValue >> 32);
return luid;
}
public string PrintActiveConfig()
{
string stringToReturn = "";
stringToReturn += $"****** WINDOWS CCD CONFIGURATION *******\n";
// Get the size of the largest Active Paths and Modes arrays
int pathCount = 0;
int modeCount = 0;
WIN32STATUS err = CCDImport.GetDisplayConfigBufferSizes(QDC.QDC_ONLY_ACTIVE_PATHS, out pathCount, out modeCount);
if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/PrintActiveConfig: ERROR - GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes");
throw new WinLibraryException($"GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes");
}
SharedLogger.logger.Trace($"WinLibrary/PrintActiveConfig: Getting the current Display Config path and mode arrays");
var paths = new DISPLAYCONFIG_PATH_INFO[pathCount];
var modes = new DISPLAYCONFIG_MODE_INFO[modeCount];
err = CCDImport.QueryDisplayConfig(QDC.QDC_ONLY_ACTIVE_PATHS, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero);
if (err == WIN32STATUS.ERROR_INSUFFICIENT_BUFFER)
{
SharedLogger.logger.Warn($"WinLibrary/PrintActiveConfig: The displays were modified between GetDisplayConfigBufferSizes and QueryDisplayConfig so we need to get the buffer sizes again.");
SharedLogger.logger.Trace($"WinLibrary/PrintActiveConfig: Getting the size of the largest Active Paths and Modes arrays");
// Screen changed in between GetDisplayConfigBufferSizes and QueryDisplayConfig, so we need to get buffer sizes again
// as per https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-querydisplayconfig
err = CCDImport.GetDisplayConfigBufferSizes(QDC.QDC_ONLY_ACTIVE_PATHS, out pathCount, out modeCount);
if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/PrintActiveConfig: ERROR - GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes again");
throw new WinLibraryException($"GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes again");
}
SharedLogger.logger.Trace($"WinLibrary/PrintActiveConfig: Getting the current Display Config path and mode arrays");
paths = new DISPLAYCONFIG_PATH_INFO[pathCount];
modes = new DISPLAYCONFIG_MODE_INFO[modeCount];
err = CCDImport.QueryDisplayConfig(QDC.QDC_ONLY_ACTIVE_PATHS, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero);
if (err == WIN32STATUS.ERROR_INSUFFICIENT_BUFFER)
{
SharedLogger.logger.Error($"WinLibrary/PrintActiveConfig: ERROR - The displays were still modified between GetDisplayConfigBufferSizes and QueryDisplayConfig, even though we tried twice. Something is wrong.");
throw new WinLibraryException($"The displays were still modified between GetDisplayConfigBufferSizes and QueryDisplayConfig, even though we tried twice. Something is wrong.");
}
else if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/PrintActiveConfig: ERROR - QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays again");
throw new WinLibraryException($"QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays again.");
}
}
else if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/PrintActiveConfig: ERROR - QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays");
throw new WinLibraryException($"QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays.");
}
foreach (var path in paths)
{
stringToReturn += $"----++++==== Path ====++++----\n";
// get display source name
var sourceInfo = new DISPLAYCONFIG_SOURCE_DEVICE_NAME();
sourceInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
sourceInfo.Header.Size = (uint)Marshal.SizeOf<DISPLAYCONFIG_SOURCE_DEVICE_NAME>();
sourceInfo.Header.AdapterId = path.SourceInfo.AdapterId;
sourceInfo.Header.Id = path.SourceInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref sourceInfo);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/PrintActiveConfig: Found Display Source {sourceInfo.ViewGdiDeviceName} for source {path.SourceInfo.Id}.");
stringToReturn += $"****** Interrogating Display Source {path.SourceInfo.Id} *******\n";
stringToReturn += $"Found Display Source {sourceInfo.ViewGdiDeviceName}\n";
stringToReturn += $"\n";
}
else
{
SharedLogger.logger.Warn($"WinLibrary/PrintActiveConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the source info for source adapter #{path.SourceInfo.AdapterId}");
}
// get display target name
var targetInfo = new DISPLAYCONFIG_TARGET_DEVICE_NAME();
targetInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
targetInfo.Header.Size = (uint)Marshal.SizeOf<DISPLAYCONFIG_TARGET_DEVICE_NAME>();
targetInfo.Header.AdapterId = path.TargetInfo.AdapterId;
targetInfo.Header.Id = path.TargetInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref targetInfo);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/PrintActiveConfig: Connector Instance: {targetInfo.ConnectorInstance} for source {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/PrintActiveConfig: EDID Manufacturer ID: {targetInfo.EdidManufactureId} for source {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/PrintActiveConfig: EDID Product Code ID: {targetInfo.EdidProductCodeId} for source {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/PrintActiveConfig: Flags Friendly Name from EDID: {targetInfo.Flags.FriendlyNameFromEdid} for source {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/PrintActiveConfig: Flags Friendly Name Forced: {targetInfo.Flags.FriendlyNameForced} for source {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/PrintActiveConfig: Flags EDID ID is Valid: {targetInfo.Flags.EdidIdsValid} for source {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/PrintActiveConfig: Monitor Device Path: {targetInfo.MonitorDevicePath} for source {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/PrintActiveConfig: Monitor Friendly Device Name: {targetInfo.MonitorFriendlyDeviceName} for source {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/PrintActiveConfig: Output Technology: {targetInfo.OutputTechnology} for source {path.TargetInfo.Id}.");
stringToReturn += $"****** Interrogating Display Target {targetInfo.MonitorFriendlyDeviceName} *******\n";
stringToReturn += $" Connector Instance: {targetInfo.ConnectorInstance}\n";
stringToReturn += $" EDID Manufacturer ID: {targetInfo.EdidManufactureId}\n";
stringToReturn += $" EDID Product Code ID: {targetInfo.EdidProductCodeId}\n";
stringToReturn += $" Flags Friendly Name from EDID: {targetInfo.Flags.FriendlyNameFromEdid}\n";
stringToReturn += $" Flags Friendly Name Forced: {targetInfo.Flags.FriendlyNameForced}\n";
stringToReturn += $" Flags EDID ID is Valid: {targetInfo.Flags.EdidIdsValid}\n";
stringToReturn += $" Monitor Device Path: {targetInfo.MonitorDevicePath}\n";
stringToReturn += $" Monitor Friendly Device Name: {targetInfo.MonitorFriendlyDeviceName}\n";
stringToReturn += $" Output Technology: {targetInfo.OutputTechnology}\n";
stringToReturn += $"\n";
}
else
{
SharedLogger.logger.Warn($"WinLibrary/PrintActiveConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the target info for display #{path.TargetInfo.Id}");
}
// get display adapter name
var adapterInfo = new DISPLAYCONFIG_ADAPTER_NAME();
adapterInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME;
adapterInfo.Header.Size = (uint)Marshal.SizeOf<DISPLAYCONFIG_ADAPTER_NAME>();
adapterInfo.Header.AdapterId = path.TargetInfo.AdapterId;
adapterInfo.Header.Id = path.TargetInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref adapterInfo);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/PrintActiveConfig: Found Adapter Device Path {adapterInfo.AdapterDevicePath} for source {path.TargetInfo.AdapterId}.");
stringToReturn += $"****** Interrogating Display Adapter {adapterInfo.AdapterDevicePath} *******\n";
stringToReturn += $" Display Adapter {adapterInfo.AdapterDevicePath}\n";
stringToReturn += $"\n";
}
else
{
SharedLogger.logger.Warn($"WinLibrary/GetWindowsDisplayConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the adapter device path for target #{path.TargetInfo.AdapterId}");
}
// get display target preferred mode
var targetPreferredInfo = new DISPLAYCONFIG_TARGET_PREFERRED_MODE();
targetPreferredInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE;
targetPreferredInfo.Header.Size = (uint)Marshal.SizeOf<DISPLAYCONFIG_TARGET_PREFERRED_MODE>();
targetPreferredInfo.Header.AdapterId = path.TargetInfo.AdapterId;
targetPreferredInfo.Header.Id = path.TargetInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref targetPreferredInfo);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Target Preferred Width {targetPreferredInfo.Width} for target {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Target Preferred Height {targetPreferredInfo.Height} for target {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Target Video Signal Info Active Size: ({targetPreferredInfo.TargetMode.TargetVideoSignalInfo.ActiveSize.Cx}x{targetPreferredInfo.TargetMode.TargetVideoSignalInfo.ActiveSize.Cy} for target {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Target Video Signal Info Total Size: ({targetPreferredInfo.TargetMode.TargetVideoSignalInfo.TotalSize.Cx}x{targetPreferredInfo.TargetMode.TargetVideoSignalInfo.TotalSize.Cy} for target {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Target Video Signal Info HSync Frequency: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.HSyncFreq} for target {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Target Video Signal Info VSync Frequency: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.VSyncFreq} for target {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Target Video Signal Info Pixel Rate: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.PixelRate} for target {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Target Video Signal Info Scan Line Ordering: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.ScanLineOrdering} for target {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Target Video Signal Info Video Standard: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.VideoStandard} for target {path.TargetInfo.Id}.");
stringToReturn += $"****** Interrogating Target Preferred Mode for Display {path.TargetInfo.Id} *******\n";
stringToReturn += $" Target Preferred Width {targetPreferredInfo.Width} for target {path.TargetInfo.Id}\n";
stringToReturn += $" Target Preferred Height {targetPreferredInfo.Height} for target {path.TargetInfo.Id}\n";
stringToReturn += $" Target Video Signal Info Active Size: ({targetPreferredInfo.TargetMode.TargetVideoSignalInfo.ActiveSize.Cx}x{targetPreferredInfo.TargetMode.TargetVideoSignalInfo.ActiveSize.Cy}\n";
stringToReturn += $" Target Video Signal Info Total Size: ({targetPreferredInfo.TargetMode.TargetVideoSignalInfo.TotalSize.Cx}x{targetPreferredInfo.TargetMode.TargetVideoSignalInfo.TotalSize.Cy}\n";
stringToReturn += $" Target Video Signal Info HSync Frequency: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.HSyncFreq}\n";
stringToReturn += $" Target Video Signal Info VSync Frequency: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.VSyncFreq}\n";
stringToReturn += $" Target Video Signal Info Pixel Rate: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.PixelRate}\n";
stringToReturn += $" Target Video Signal Info Scan Line Ordering: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.ScanLineOrdering}\n";
stringToReturn += $" Target Video Signal Info Video Standard: {targetPreferredInfo.TargetMode.TargetVideoSignalInfo.VideoStandard}\n";
stringToReturn += $"\n";
}
else
{
SharedLogger.logger.Warn($"WinLibrary/GetWindowsDisplayConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the preferred target name for display #{path.TargetInfo.Id}");
}
// get display target base type
var targetBaseTypeInfo = new DISPLAYCONFIG_TARGET_BASE_TYPE();
targetBaseTypeInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE;
targetBaseTypeInfo.Header.Size = (uint)Marshal.SizeOf<DISPLAYCONFIG_TARGET_BASE_TYPE>();
targetBaseTypeInfo.Header.AdapterId = path.TargetInfo.AdapterId;
targetBaseTypeInfo.Header.Id = path.TargetInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref targetBaseTypeInfo);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Virtual Resolution is Disabled: {targetBaseTypeInfo.BaseOutputTechnology} for target {path.TargetInfo.Id}.");
stringToReturn += $"****** Interrogating Target Base Type for Display {path.TargetInfo.Id} *******\n";
stringToReturn += $" Base Output Technology: {targetBaseTypeInfo.BaseOutputTechnology}\n";
stringToReturn += $"\n";
}
else
{
SharedLogger.logger.Warn($"WinLibrary/GetWindowsDisplayConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the target base type for display #{path.TargetInfo.Id}");
}
// get display support virtual resolution
var supportVirtResInfo = new DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION();
supportVirtResInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION;
supportVirtResInfo.Header.Size = (uint)Marshal.SizeOf<DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION>();
supportVirtResInfo.Header.AdapterId = path.TargetInfo.AdapterId;
supportVirtResInfo.Header.Id = path.TargetInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref supportVirtResInfo);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Base Output Technology: {supportVirtResInfo.IsMonitorVirtualResolutionDisabled} for target {path.TargetInfo.Id}.");
stringToReturn += $"****** Interrogating Target Supporting virtual resolution for Display {path.TargetInfo.Id} *******\n";
stringToReturn += $" Virtual Resolution is Disabled: {supportVirtResInfo.IsMonitorVirtualResolutionDisabled}\n";
stringToReturn += $"\n";
}
else
{
SharedLogger.logger.Warn($"WinLibrary/GetWindowsDisplayConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to find out the virtual resolution support for display #{path.TargetInfo.Id}");
}
//get advanced color info
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 = (uint)Marshal.SizeOf<DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO>();
colorInfo.Header.AdapterId = path.TargetInfo.AdapterId;
colorInfo.Header.Id = path.TargetInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref colorInfo);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Advanced Color Supported: {colorInfo.AdvancedColorSupported} for target {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Advanced Color Enabled: {colorInfo.AdvancedColorEnabled} for target {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Advanced Color Force Disabled: {colorInfo.AdvancedColorForceDisabled} for target {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Bits per Color Channel: {colorInfo.BitsPerColorChannel} for target {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Color Encoding: {colorInfo.ColorEncoding} for target {path.TargetInfo.Id}.");
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Wide Color Enforced: {colorInfo.WideColorEnforced} for target {path.TargetInfo.Id}.");
stringToReturn += $"****** Interrogating Advanced Color Info for Display {path.TargetInfo.Id} *******\n";
stringToReturn += $" Advanced Color Supported: {colorInfo.AdvancedColorSupported}\n";
stringToReturn += $" Advanced Color Enabled: {colorInfo.AdvancedColorEnabled}\n";
stringToReturn += $" Advanced Color Force Disabled: {colorInfo.AdvancedColorForceDisabled}\n";
stringToReturn += $" Bits per Color Channel: {colorInfo.BitsPerColorChannel}\n";
stringToReturn += $" Color Encoding: {colorInfo.ColorEncoding}\n";
stringToReturn += $" Wide Color Enforced: {colorInfo.WideColorEnforced}\n";
stringToReturn += $"\n";
}
else
{
SharedLogger.logger.Warn($"WinLibrary/GetWindowsDisplayConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to find out the virtual resolution support for display #{path.TargetInfo.Id}");
}
// get SDR white levels
var whiteLevelInfo = new DISPLAYCONFIG_SDR_WHITE_LEVEL();
whiteLevelInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL;
whiteLevelInfo.Header.Size = (uint)Marshal.SizeOf<DISPLAYCONFIG_SDR_WHITE_LEVEL>();
whiteLevelInfo.Header.AdapterId = path.TargetInfo.AdapterId;
whiteLevelInfo.Header.Id = path.TargetInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref whiteLevelInfo);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found SDR White Level: {whiteLevelInfo.SDRWhiteLevel} for target {path.TargetInfo.Id}.");
stringToReturn += $"****** Interrogating SDR Whilte Level for Display {path.TargetInfo.Id} *******\n";
stringToReturn += $" SDR White Level: {whiteLevelInfo.SDRWhiteLevel}\n";
stringToReturn += $"\n";
}
else
{
SharedLogger.logger.Warn($"WinLibrary/GetWindowsDisplayConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to find out the SDL white level for display #{path.TargetInfo.Id}");
}
}
return stringToReturn;
}
public bool SetActiveConfig(WINDOWS_DISPLAY_CONFIG displayConfig)
{
// Get the all possible windows display configs
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Generating a list of all the current display configs");
WINDOWS_DISPLAY_CONFIG allWindowsDisplayConfig = GetWindowsDisplayConfig(QDC.QDC_ALL_PATHS);
// Now we go through the Paths to update the LUIDs as per Soroush's suggestion
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Patching the adapter IDs to make the saved config valid");
PatchAdapterIDs(ref displayConfig, allWindowsDisplayConfig.DisplayAdapters);
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Testing whether the display configuration is valid");
// Test whether a specified display configuration is supported on the computer
uint myPathsCount = (uint)displayConfig.DisplayConfigPaths.Length;
uint myModesCount = (uint)displayConfig.DisplayConfigModes.Length;
WIN32STATUS err = CCDImport.SetDisplayConfig(myPathsCount, displayConfig.DisplayConfigPaths, myModesCount, displayConfig.DisplayConfigModes, SDC.DISPLAYMAGICIAN_VALIDATE);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Successfully validated that the display configuration supplied would work!");
}
else
{
SharedLogger.logger.Error($"WinLibrary/SetActiveConfig: ERROR - SetDisplayConfig couldn't validate the display configuration supplied. This display configuration wouldn't work.");
return false;
}
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Yay! The display configuration is valid! Attempting to set the Display Config now");
// Now set the specified display configuration for this computer
err = CCDImport.SetDisplayConfig(myPathsCount, displayConfig.DisplayConfigPaths, myModesCount, displayConfig.DisplayConfigModes, SDC.DISPLAYMAGICIAN_SET);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Successfully set the display configuration to the settings supplied!");
}
else
{
SharedLogger.logger.Error($"WinLibrary/SetActiveConfig: ERROR - SetDisplayConfig couldn't set the display configuration using the settings supplied. Something is wrong.");
throw new WinLibraryException($"SetDisplayConfig couldn't set the display configuration using the settings supplied. Something is wrong.");
}
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: SUCCESS! The display configuration has been successfully applied");
foreach (ADVANCED_HDR_INFO_PER_PATH myHDRstate in displayConfig.DisplayHDRStates)
{
SharedLogger.logger.Trace($"Trying to get information whether HDR color is in use now on Display {myHDRstate.Id}.");
// Get advanced HDR info
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 = (uint)Marshal.SizeOf<DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO>();
colorInfo.Header.AdapterId = myHDRstate.AdapterId;
colorInfo.Header.Id = myHDRstate.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref colorInfo);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Advanced Color Info gathered from Display {myHDRstate.Id}");
if (myHDRstate.AdvancedColorInfo.AdvancedColorSupported && colorInfo.AdvancedColorEnabled != myHDRstate.AdvancedColorInfo.AdvancedColorEnabled)
{
SharedLogger.logger.Trace($"HDR is available for use on Display {myHDRstate.Id}, and we want it set to {myHDRstate.AdvancedColorInfo.AdvancedColorEnabled} but is currently {colorInfo.AdvancedColorEnabled}.");
var setColorState = new DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE();
setColorState.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE;
setColorState.Header.Size = (uint)Marshal.SizeOf<DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE>();
setColorState.Header.AdapterId = myHDRstate.AdapterId;
setColorState.Header.Id = myHDRstate.Id;
setColorState.EnableAdvancedColor = myHDRstate.AdvancedColorInfo.AdvancedColorEnabled;
err = CCDImport.DisplayConfigSetDeviceInfo(ref setColorState);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: SUCCESS! Set HDR successfully to {myHDRstate.AdvancedColorInfo.AdvancedColorEnabled} on Display {myHDRstate.Id}");
}
else
{
SharedLogger.logger.Error($"WinLibrary/SetActiveConfig: ERROR - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to set the HDR settings for display #{myHDRstate.Id}");
return false;
}
}
else
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Skipping setting HDR on Display {myHDRstate.Id} as it does not support HDR");
}
}
else
{
SharedLogger.logger.Warn($"WinLibrary/GetWindowsDisplayConfig: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to find out if HDR is supported for display #{myHDRstate.Id}");
}
}
return true;
}
public bool IsActiveConfig(WINDOWS_DISPLAY_CONFIG displayConfig)
{
// Get the current windows display configs to compare to the one we loaded
WINDOWS_DISPLAY_CONFIG currentWindowsDisplayConfig = GetWindowsDisplayConfig(QDC.QDC_ONLY_ACTIVE_PATHS);
// Check whether the display config is in use now
SharedLogger.logger.Trace($"WinLibrary/IsActiveConfig: Checking whether the display configuration is already being used.");
if (displayConfig.Equals(currentWindowsDisplayConfig))
{
SharedLogger.logger.Trace($"WinLibrary/IsActiveConfig: The display configuration is already being used (supplied displayConfig Equals currentWindowsDisplayConfig");
return true;
}
else
{
SharedLogger.logger.Trace($"WinLibrary/IsActiveConfig: The display configuration is NOT currently in use (supplied displayConfig Equals currentWindowsDisplayConfig");
return false;
}
}
public bool IsValidConfig(WINDOWS_DISPLAY_CONFIG displayConfig)
{
// Get the current windows display configs
WINDOWS_DISPLAY_CONFIG allWindowsDisplayConfig = GetWindowsDisplayConfig(QDC.QDC_ALL_PATHS);
SharedLogger.logger.Trace("WinLibrary/PatchAdapterIDs: Going through the list of adapters we stored in the config to make sure they still exist");
// Firstly check that the Adapter Names are still currently available (i.e. the adapter hasn't been replaced).
foreach (string savedAdapterName in displayConfig.DisplayAdapters.Values)
{
// If there is even one of the saved adapters that has changed, then it's no longer possible
// to use this display config!
if (!allWindowsDisplayConfig.DisplayAdapters.Values.Contains(savedAdapterName))
{
SharedLogger.logger.Error($"WinLibrary/PatchAdapterIDs: ERROR - Saved adapter {savedAdapterName} is not available right now! This display configuration won't work!");
return false;
}
}
SharedLogger.logger.Trace($"WinLibrary/PatchAdapterIDs: All teh adapters that the display configuration uses are still avilable to use now!");
// Now we go through the Paths to update the LUIDs as per Soroush's suggestion
SharedLogger.logger.Trace($"WinLibrary/IsPossibleConfig: Attemptong to patch the saved display configuration's adapter IDs so that it will still work (these change at each boot)");
PatchAdapterIDs(ref displayConfig, allWindowsDisplayConfig.DisplayAdapters);
SharedLogger.logger.Trace($"WinLibrary/IsPossibleConfig: Testing whether the display configuration is valid ");
// Test whether a specified display configuration is supported on the computer
uint myPathsCount = (uint)displayConfig.DisplayConfigPaths.Length;
uint myModesCount = (uint)displayConfig.DisplayConfigModes.Length;
WIN32STATUS err = CCDImport.SetDisplayConfig(myPathsCount, displayConfig.DisplayConfigPaths, myModesCount, displayConfig.DisplayConfigModes, SDC.DISPLAYMAGICIAN_VALIDATE);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/IsPossibleConfig: SetDisplayConfig validated that the display configuration is valid and can be used!");
return true;
}
else
{
SharedLogger.logger.Trace($"WinLibrary/IsPossibleConfig: SetDisplayConfig confirmed that the display configuration is invalid and cannot be used!");
return false;
}
}
public bool IsPossibleConfig(WINDOWS_DISPLAY_CONFIG displayConfig)
{
// We want to check the Windows Display profile can be used now
SharedLogger.logger.Trace($"WinLibrary/IsPossibleConfig: Testing whether the Windows display configuration is possible to be used now");
// check what the currently available displays are (include the ones not active)
List<string> currentAllIds = GetAllConnectedDisplayIdentifiers();
// CHeck that we have all the displayConfig DisplayIdentifiers we need available now
//if (currentAllIds.Intersect(displayConfig.DisplayIdentifiers).Count() == displayConfig.DisplayIdentifiers.Count)
if (displayConfig.DisplayIdentifiers.All(value => currentAllIds.Contains(value)))
{
SharedLogger.logger.Trace($"WinLibrary/IsPossibleConfig: Success! THe Windows display configuration is possible to be used now");
return true;
}
else
{
SharedLogger.logger.Trace($"WinLibrary/IsPossibleConfig: Uh oh! THe Windows display configuration is possible cannot be used now");
return false;
}
}
public List<string> GetCurrentDisplayIdentifiers()
{
SharedLogger.logger.Error($"WinLibrary/GetCurrentDisplayIdentifiers: Getting the current display identifiers for the displays in use now");
return GetSomeDisplayIdentifiers(QDC.QDC_ONLY_ACTIVE_PATHS);
}
public List<string> GetAllConnectedDisplayIdentifiers()
{
SharedLogger.logger.Error($"WinLibrary/GetAllConnectedDisplayIdentifiers: Getting all the display identifiers that can possibly be used");
return GetSomeDisplayIdentifiers(QDC.QDC_ALL_PATHS);
}
private List<string> GetSomeDisplayIdentifiers(QDC selector = QDC.QDC_ONLY_ACTIVE_PATHS)
{
SharedLogger.logger.Debug($"WinLibrary/GetCurrentDisplayIdentifiers: Generating the unique Display Identifiers for the currently active configuration");
List<string> displayIdentifiers = new List<string>();
SharedLogger.logger.Trace($"WinLibrary/GetCurrentDisplayIdentifiers: Testing whether the display configuration is valid (allowing tweaks).");
// Get the size of the largest Active Paths and Modes arrays
int pathCount = 0;
int modeCount = 0;
WIN32STATUS err = CCDImport.GetDisplayConfigBufferSizes(selector, out pathCount, out modeCount);
if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/PrintActiveConfig: ERROR - GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes");
throw new WinLibraryException($"GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes");
}
SharedLogger.logger.Trace($"WinLibrary/GetSomeDisplayIdentifiers: Getting the current Display Config path and mode arrays");
var paths = new DISPLAYCONFIG_PATH_INFO[pathCount];
var modes = new DISPLAYCONFIG_MODE_INFO[modeCount];
err = CCDImport.QueryDisplayConfig(selector, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero);
if (err == WIN32STATUS.ERROR_INSUFFICIENT_BUFFER)
{
SharedLogger.logger.Warn($"WinLibrary/GetSomeDisplayIdentifiers: The displays were modified between GetDisplayConfigBufferSizes and QueryDisplayConfig so we need to get the buffer sizes again.");
SharedLogger.logger.Trace($"WinLibrary/GetSomeDisplayIdentifiers: Getting the size of the largest Active Paths and Modes arrays");
// Screen changed in between GetDisplayConfigBufferSizes and QueryDisplayConfig, so we need to get buffer sizes again
// as per https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-querydisplayconfig
err = CCDImport.GetDisplayConfigBufferSizes(selector, out pathCount, out modeCount);
if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/GetSomeDisplayIdentifiers: ERROR - GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes again");
throw new WinLibraryException($"GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes again");
}
SharedLogger.logger.Trace($"WinLibrary/GetSomeDisplayIdentifiers: Getting the current Display Config path and mode arrays");
paths = new DISPLAYCONFIG_PATH_INFO[pathCount];
modes = new DISPLAYCONFIG_MODE_INFO[modeCount];
err = CCDImport.QueryDisplayConfig(selector, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero);
if (err == WIN32STATUS.ERROR_INSUFFICIENT_BUFFER)
{
SharedLogger.logger.Error($"WinLibrary/GetSomeDisplayIdentifiers: ERROR - The displays were still modified between GetDisplayConfigBufferSizes and QueryDisplayConfig, even though we tried twice. Something is wrong.");
throw new WinLibraryException($"The displays were still modified between GetDisplayConfigBufferSizes and QueryDisplayConfig, even though we tried twice. Something is wrong.");
}
else if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/GetSomeDisplayIdentifiers: ERROR - QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays again");
throw new WinLibraryException($"QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays again.");
}
}
else if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/GetSomeDisplayIdentifiers: ERROR - QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays");
throw new WinLibraryException($"QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays.");
}
foreach (var path in paths)
{
if (path.TargetInfo.TargetAvailable == false)
{
// We want to skip this one cause it's not valid
SharedLogger.logger.Trace($"WinLibrary/GetSomeDisplayIdentifiers: Skipping path due to TargetAvailable not existing in display #{path.TargetInfo.Id}");
continue;
}
// get display source name
var sourceInfo = new DISPLAYCONFIG_SOURCE_DEVICE_NAME();
sourceInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
sourceInfo.Header.Size = (uint)Marshal.SizeOf<DISPLAYCONFIG_SOURCE_DEVICE_NAME>();
sourceInfo.Header.AdapterId = path.SourceInfo.AdapterId;
sourceInfo.Header.Id = path.SourceInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref sourceInfo);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/GetSomeDisplayIdentifiers: Successfully got the source info from {path.SourceInfo.Id}.");
}
else
{
SharedLogger.logger.Warn($"WinLibrary/GetSomeDisplayIdentifiers: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the target info for display #{path.SourceInfo.Id}");
}
// get display target name
var targetInfo = new DISPLAYCONFIG_TARGET_DEVICE_NAME();
targetInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
targetInfo.Header.Size = (uint)Marshal.SizeOf<DISPLAYCONFIG_TARGET_DEVICE_NAME>();
targetInfo.Header.AdapterId = path.TargetInfo.AdapterId;
targetInfo.Header.Id = path.TargetInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref targetInfo);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/GetSomeDisplayIdentifiers: Successfully got the target info from {path.TargetInfo.Id}.");
}
else
{
SharedLogger.logger.Warn($"WinLibrary/GetSomeDisplayIdentifiers: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the target info for display #{path.TargetInfo.Id}");
}
// get display adapter name
var adapterInfo = new DISPLAYCONFIG_ADAPTER_NAME();
adapterInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME;
adapterInfo.Header.Size = (uint)Marshal.SizeOf<DISPLAYCONFIG_ADAPTER_NAME>();
adapterInfo.Header.AdapterId = path.TargetInfo.AdapterId;
adapterInfo.Header.Id = path.TargetInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref adapterInfo);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/GetSomeDisplayIdentifiers: Successfully got the display name info from {path.TargetInfo.Id}.");
}
else
{
SharedLogger.logger.Warn($"WinLibrary/GetSomeDisplayIdentifiers: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the target info for display #{path.TargetInfo.Id}");
}
// Create an array of all the important display info we need to record
List<string> displayInfo = new List<string>();
displayInfo.Add("WINAPI");
try
{
displayInfo.Add(adapterInfo.AdapterDevicePath.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"WinLibrary/GetSomeDisplayIdentifiers: Exception getting Windows Display Adapter Device Path from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(targetInfo.OutputTechnology.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"WinLibrary/GetSomeDisplayIdentifiers: Exception getting Windows Display Connector Instance from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(targetInfo.EdidManufactureId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"WinLibrary/GetSomeDisplayIdentifiers: Exception getting Windows Display EDID Manufacturer Code from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(targetInfo.EdidProductCodeId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"WinLibrary/GetSomeDisplayIdentifiers: Exception getting Windows Display EDID Product Code from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(targetInfo.MonitorFriendlyDeviceName.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"WinLibrary/GetSomeDisplayIdentifiers: Exception getting Windows Display Target Friendly name from video card. Substituting with a # instead");
displayInfo.Add("#");
}
// Create a display identifier out of it
string displayIdentifier = String.Join("|", displayInfo);
// Add it to the list of display identifiers so we can return it
// but only add it if it doesn't already exist. Otherwise we get duplicates :/
if (!displayIdentifiers.Contains(displayIdentifier))
{
displayIdentifiers.Add(displayIdentifier);
SharedLogger.logger.Debug($"ProfileRepository/GenerateProfileDisplayIdentifiers: DisplayIdentifier: {displayIdentifier}");
}
}
// Sort the display identifiers
displayIdentifiers.Sort();
return displayIdentifiers;
}
public List<string> GetCurrentPCIVideoCardVendors()
{
SharedLogger.logger.Trace($"WinLibrary/GetCurrentPCIVideoCardVendors: Getting the current PCI vendor ids for the videocards reported to Windows");
List<string> videoCardVendorIds = new List<string>();
SharedLogger.logger.Trace($"WinLibrary/GetCurrentPCIVideoCardVendors: Testing whether the display configuration is valid (allowing tweaks).");
// Get the size of the largest Active Paths and Modes arrays
int pathCount = 0;
int modeCount = 0;
WIN32STATUS err = CCDImport.GetDisplayConfigBufferSizes(QDC.QDC_ONLY_ACTIVE_PATHS, out pathCount, out modeCount);
if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/GetCurrentPCIVideoCardVendors: ERROR - GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes");
throw new WinLibraryException($"GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes");
}
SharedLogger.logger.Trace($"WinLibrary/GetSomeDisplayIdentifiers: Getting the current Display Config path and mode arrays");
var paths = new DISPLAYCONFIG_PATH_INFO[pathCount];
var modes = new DISPLAYCONFIG_MODE_INFO[modeCount];
err = CCDImport.QueryDisplayConfig(QDC.QDC_ONLY_ACTIVE_PATHS, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero);
if (err == WIN32STATUS.ERROR_INSUFFICIENT_BUFFER)
{
SharedLogger.logger.Warn($"WinLibrary/GetCurrentPCIVideoCardVendors: The displays were modified between GetDisplayConfigBufferSizes and QueryDisplayConfig so we need to get the buffer sizes again.");
SharedLogger.logger.Trace($"WinLibrary/GetCurrentPCIVideoCardVendors: Getting the size of the largest Active Paths and Modes arrays");
// Screen changed in between GetDisplayConfigBufferSizes and QueryDisplayConfig, so we need to get buffer sizes again
// as per https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-querydisplayconfig
err = CCDImport.GetDisplayConfigBufferSizes(QDC.QDC_ONLY_ACTIVE_PATHS, out pathCount, out modeCount);
if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/GetCurrentPCIVideoCardVendors: ERROR - GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes again");
throw new WinLibraryException($"GetDisplayConfigBufferSizes returned WIN32STATUS {err} when trying to get the maximum path and mode sizes again");
}
SharedLogger.logger.Trace($"WinLibrary/GetSomeDisplayIdentifiers: Getting the current Display Config path and mode arrays");
paths = new DISPLAYCONFIG_PATH_INFO[pathCount];
modes = new DISPLAYCONFIG_MODE_INFO[modeCount];
err = CCDImport.QueryDisplayConfig(QDC.QDC_ONLY_ACTIVE_PATHS, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero);
if (err == WIN32STATUS.ERROR_INSUFFICIENT_BUFFER)
{
SharedLogger.logger.Error($"WinLibrary/GetCurrentPCIVideoCardVendors: ERROR - The displays were still modified between GetDisplayConfigBufferSizes and QueryDisplayConfig, even though we tried twice. Something is wrong.");
throw new WinLibraryException($"The displays were still modified between GetDisplayConfigBufferSizes and QueryDisplayConfig, even though we tried twice. Something is wrong.");
}
else if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/GetCurrentPCIVideoCardVendors: ERROR - QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays again");
throw new WinLibraryException($"QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays again.");
}
}
else if (err != WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Error($"WinLibrary/GetCurrentPCIVideoCardVendors: ERROR - QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays");
throw new WinLibraryException($"QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays.");
}
foreach (var path in paths)
{
if (path.TargetInfo.TargetAvailable == false)
{
// We want to skip this one cause it's not valid
SharedLogger.logger.Trace($"WinLibrary/GetCurrentPCIVideoCardVendors: Skipping path due to TargetAvailable not existing in display #{path.TargetInfo.Id}");
continue;
}
// get display adapter name
var adapterInfo = new DISPLAYCONFIG_ADAPTER_NAME();
adapterInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME;
adapterInfo.Header.Size = (uint)Marshal.SizeOf<DISPLAYCONFIG_ADAPTER_NAME>();
adapterInfo.Header.AdapterId = path.TargetInfo.AdapterId;
adapterInfo.Header.Id = path.TargetInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref adapterInfo);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/GetCurrentPCIVideoCardVendors: Successfully got the display name info from {path.TargetInfo.Id}.");
}
else
{
SharedLogger.logger.Warn($"WinLibrary/GetCurrentPCIVideoCardVendors: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the target info for display #{path.TargetInfo.Id}");
}
try
{
// The AdapterDevicePath is something like "\\\\?\\PCI#VEN_10DE&DEV_2482&SUBSYS_408E1458&REV_A1#4&2283f625&0&0019#{5b45201d-f2f2-4f3b-85bb-30ff1f953599}"
// We only want the vendor ID
SharedLogger.logger.Trace($"WinLibrary/GetCurrentPCIVideoCardVendors: The AdapterDevicePath for this path is :{adapterInfo.AdapterDevicePath}");
// Match against the vendor ID
string pattern = @"VEN_([\d\w]{4})&";
Match match = Regex.Match(adapterInfo.AdapterDevicePath, pattern);
if (match.Success)
{
string VendorId = match.Groups[1].Value;
SharedLogger.logger.Trace($"WinLibrary/GetCurrentPCIVideoCardVendors: The matched PCI Vendor ID is :{VendorId }");
if (!videoCardVendorIds.Contains(VendorId))
{
videoCardVendorIds.Add(VendorId);
SharedLogger.logger.Trace($"WinLibrary/GetCurrentPCIVideoCardVendors: Stored PCI vendor ID {VendorId} as we haven't already got it");
}
}
else
{
SharedLogger.logger.Trace($"WinLibrary/GetCurrentPCIVideoCardVendors: The PCI Vendor ID pattern wasn't matched so we didn't record a vendor ID.");
}
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"WinLibrary/GetCurrentPCIVideoCardVendors: Exception getting PCI Vendor ID from Display Adapter {path.SourceInfo.AdapterId}.");
}
}
return videoCardVendorIds;
}
}
[global::System.Serializable]
public class WinLibraryException : Exception
{
public WinLibraryException() { }
public WinLibraryException(string message) : base(message) { }
public WinLibraryException(string message, Exception inner) : base(message, inner) { }
protected WinLibraryException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}
}