mirror of
https://github.com/terrymacdonald/DisplayMagician.git
synced 2024-08-30 18:32:20 +00:00
bc6242a8bb
Latest versions based on tests from NVIDIAInfo
1134 lines
76 KiB
C#
1134 lines
76 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 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];
|
|
|
|
// 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 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;
|
|
}
|
|
|
|
|
|
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.Error($"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) { }
|
|
}
|
|
} |