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 { 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 { public Dictionary DisplayAdapters; public DISPLAYCONFIG_PATH_INFO[] DisplayConfigPaths; public DISPLAYCONFIG_MODE_INFO[] DisplayConfigModes; public ADVANCED_HDR_INFO_PER_PATH[] DisplayHDRStates; public Dictionary DisplaySources; public List 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 currentAdapterMap) { Dictionary adapterOldToNewMap = new Dictionary(); SharedLogger.logger.Trace("WinLibrary/PatchAdapterIDs: Going through the list of adapters we stored in the config to figure out the old adapterIDs"); foreach (KeyValuePair savedAdapter in savedDisplayConfig.DisplayAdapters) { foreach (KeyValuePair 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(); windowsDisplayConfig.DisplayHDRStates = new ADVANCED_HDR_INFO_PER_PATH[pathCount]; windowsDisplayConfig.DisplaySources = new Dictionary(); // 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(); 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(); 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(); 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(); 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 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 DisplaySources = new Dictionary(); // 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(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); 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 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 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 GetAllConnectedDisplayIdentifiers() { SharedLogger.logger.Error($"WinLibrary/GetAllConnectedDisplayIdentifiers: Getting all the display identifiers that can possibly be used"); return GetSomeDisplayIdentifiers(QDC.QDC_ALL_PATHS); } private List GetSomeDisplayIdentifiers(QDC selector = QDC.QDC_ONLY_ACTIVE_PATHS) { SharedLogger.logger.Debug($"WinLibrary/GetCurrentDisplayIdentifiers: Generating the unique Display Identifiers for the currently active configuration"); List displayIdentifiers = new List(); 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(); 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(); 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(); 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 displayInfo = new List(); 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 GetCurrentPCIVideoCardVendors() { SharedLogger.logger.Trace($"WinLibrary/GetCurrentPCIVideoCardVendors: Getting the current PCI vendor ids for the videocards reported to Windows"); List videoCardVendorIds = new List(); 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(); 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) { } } }