[WIP] initial library integration into DM

Have almost integrated the new CCD, AMD and NVIDIA
libraries into DIsplayMagician. The CCD library is working
fine. The AMD library is partially completed, but is awaiting
some help from AMD, as it appears one of their driver functions
is broken (or at least incorrectly documented). The NVIDIA
library is currently still under development, but I've still copied
it across so that I could work on the additional profile objects
that need to be prepared in order for this to work.

As I am waiting on a response from AMD, the plan is now that
I will swap over to an NVIDIA based video card in my test machines
and I will start work on the NVIDIA library. The NVIDIA library seems
straight forward compared to AMD, so that hopefully won't take too
long to do. Once that library is compete, I'll test it within NVIDIAInfo
application until its working, and then I'll port it back over to
DisplayMagician. That will then let me complete the last bits of the
integration so that I can complete the last of the NVIDIA tests.
Hopefully by the time all this happens I will have heard back from
AMD and I will be able to continue work with that section of code.
This commit is contained in:
Terry MacDonald
2021-07-24 16:05:38 +12:00
parent c9f2cffe0a
commit 0123e061e0
14 changed files with 5878 additions and 5755 deletions

View File

@ -602,7 +602,7 @@ namespace DisplayMagician {
{ {
Console.WriteLine("Program/ApplyProfile : Applying AMD Profile " + profile.Name); Console.WriteLine("Program/ApplyProfile : Applying AMD Profile " + profile.Name);
AMDProfileItem amdProfile = (AMDProfileItem)profile; AMDProfileItem amdProfile = (AMDProfileItem)profile;
if (!AMDLibrary.GetLibrary().SetActiveProfile(amdProfile.ProfileData)) if (!AMDLibrary.GetLibrary().SetActiveConfig(amdProfile.DisplayConfig))
{ {
// Somehow return that this profile topology didn't apply // Somehow return that this profile topology didn't apply
throw new ApplyTopologyException("Program/ApplyProfile: amdApplyProfileTask: Error applying the AMD Profile!"); throw new ApplyTopologyException("Program/ApplyProfile: amdApplyProfileTask: Error applying the AMD Profile!");

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -9,13 +9,13 @@ using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using IWshRuntimeLibrary; using IWshRuntimeLibrary;
using ATI.ADL; //using ATI.ADL;
//using WK.Libraries.HotkeyListenerNS; //using WK.Libraries.HotkeyListenerNS;
namespace DisplayMagicianShared.AMD namespace DisplayMagicianShared.AMD
{ {
// Struct to be used as the AMD Profile /*// Struct to be used as the AMD Profile
[JsonObject(MemberSerialization.Fields)] [JsonObject(MemberSerialization.Fields)]
public struct AMDProfile public struct AMDProfile
{ {
@ -47,7 +47,7 @@ namespace DisplayMagicianShared.AMD
public bool HDREnabled; public bool HDREnabled;
public bool IsEyefinity; public bool IsEyefinity;
} }*/
public class AMDProfileItem : ProfileItem, IComparable public class AMDProfileItem : ProfileItem, IComparable
{ {
@ -56,7 +56,7 @@ namespace DisplayMagicianShared.AMD
private Bitmap _profileBitmap, _profileShortcutBitmap; private Bitmap _profileBitmap, _profileShortcutBitmap;
private List<string> _profileDisplayIdentifiers = new List<string>(); private List<string> _profileDisplayIdentifiers = new List<string>();
private List<ScreenPosition> _screens; private List<ScreenPosition> _screens;
private AMDProfile _profileData = new AMDProfile(); private AMD_DISPLAY_CONFIG _displayConfig = new AMD_DISPLAY_CONFIG();
private static readonly string uuidV4Regex = @"(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$"; private static readonly string uuidV4Regex = @"(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$";
private string _uuid = ""; private string _uuid = "";
@ -107,15 +107,15 @@ namespace DisplayMagicianShared.AMD
//public Topology.Path[] Paths { get; set; } = new Topology.Path[0]; //public Topology.Path[] Paths { get; set; } = new Topology.Path[0];
[JsonRequired] [JsonRequired]
public AMDProfile ProfileData public AMD_DISPLAY_CONFIG DisplayConfig
{ {
get get
{ {
return _profileData; return _displayConfig;
} }
set set
{ {
_profileData = value; _displayConfig = value;
} }
} }
@ -126,7 +126,7 @@ namespace DisplayMagicianShared.AMD
{ {
if (_profileDisplayIdentifiers.Count == 0) if (_profileDisplayIdentifiers.Count == 0)
{ {
_profileDisplayIdentifiers = AMDLibrary.GetLibrary().GenerateProfileDisplayIdentifiers(); _profileDisplayIdentifiers = AMDLibrary.GetLibrary().GetCurrentDisplayIdentifiers();
} }
return _profileDisplayIdentifiers; return _profileDisplayIdentifiers;
} }
@ -213,7 +213,7 @@ namespace DisplayMagicianShared.AMD
ProfileTightestBitmap is Bitmap && ProfileTightestBitmap is Bitmap &&
ProfileDisplayIdentifiers.Count > 0) ProfileDisplayIdentifiers.Count > 0)
{ {
if (ProfileData.Adapters.Count > 0) if (DisplayConfig.AdapterConfigs.Count > 0)
return true; return true;
else else
return false; return false;
@ -234,7 +234,7 @@ namespace DisplayMagicianShared.AMD
// Copy all our profile data over to the other profile // Copy all our profile data over to the other profile
profile.Name = Name; profile.Name = Name;
profile.ProfileData = ProfileData; profile.DisplayConfig = DisplayConfig;
profile.ProfileIcon = ProfileIcon; profile.ProfileIcon = ProfileIcon;
profile.SavedProfileIconCacheFilename = SavedProfileIconCacheFilename; profile.SavedProfileIconCacheFilename = SavedProfileIconCacheFilename;
profile.ProfileBitmap = ProfileBitmap; profile.ProfileBitmap = ProfileBitmap;
@ -249,7 +249,7 @@ namespace DisplayMagicianShared.AMD
// Prepare our profile data for saving // Prepare our profile data for saving
if (_profileDisplayIdentifiers.Count == 0) if (_profileDisplayIdentifiers.Count == 0)
{ {
_profileDisplayIdentifiers = AMDLibrary.GetLibrary().GenerateProfileDisplayIdentifiers(); _profileDisplayIdentifiers = AMDLibrary.GetLibrary().GetCurrentDisplayIdentifiers();
} }
// Return if it is valid and we should continue // Return if it is valid and we should continue
@ -299,7 +299,7 @@ namespace DisplayMagicianShared.AMD
if (amdLibrary.IsInstalled) if (amdLibrary.IsInstalled)
{ {
// Create the profile data from the current config // Create the profile data from the current config
_profileData = amdLibrary.GetActiveProfile(); _displayConfig = amdLibrary.GetActiveConfig();
// Now, since the ActiveProfile has changed, we need to regenerate screen positions // Now, since the ActiveProfile has changed, we need to regenerate screen positions
_screens = GetScreenPositions(); _screens = GetScreenPositions();
@ -326,9 +326,9 @@ namespace DisplayMagicianShared.AMD
// Now we create the screens structure from the AMD profile information // Now we create the screens structure from the AMD profile information
_screens = new List<ScreenPosition>(); _screens = new List<ScreenPosition>();
if ( _profileData.Adapters.Count > 0) if ( _displayConfig.AdapterConfigs.Count > 0)
{ {
foreach ( var adapter in _profileData.Adapters) foreach ( var adapter in _displayConfig.AdapterConfigs)
{ {
foreach (var display in adapter.Displays) foreach (var display in adapter.Displays)
{ {
@ -422,7 +422,8 @@ namespace DisplayMagicianShared.AMD
if (this.GetType() != other.GetType()) if (this.GetType() != other.GetType())
return false; return false;
if (ProfileData.Adapters.Count != other.ProfileData.Adapters.Count) // If the DisplayConfig's equal each other
if (DisplayConfig.Equals(other.DisplayConfig))
return false; return false;
// Check if the profile identifiers are not the same, then return false // Check if the profile identifiers are not the same, then return false
@ -510,7 +511,7 @@ namespace DisplayMagicianShared.AMD
int hashIds = ProfileDisplayIdentifiers == null ? 0 : ProfileDisplayIdentifiers.GetHashCode(); int hashIds = ProfileDisplayIdentifiers == null ? 0 : ProfileDisplayIdentifiers.GetHashCode();
// Get ProfileData too // Get ProfileData too
int hashProfileData = ProfileData.GetHashCode(); int hashProfileData = DisplayConfig.GetHashCode();
// Calculate the hash code for the product. // Calculate the hash code for the product.
return (hashIds, hashProfileData).GetHashCode(); return (hashIds, hashProfileData).GetHashCode();
@ -559,10 +560,7 @@ namespace DisplayMagicianShared.AMD
//Check whether any of the compared objects is null. //Check whether any of the compared objects is null.
if (x is null || y is null) if (x is null || y is null)
return false; return false;
if (x.ProfileData.Adapters.Count != y.ProfileData.Adapters.Count)
return false;
// Check if the profile identifiers are not the same, then return false // Check if the profile identifiers are not the same, then return false
int foundDICount = 0; int foundDICount = 0;
foreach (string profileDI in x.ProfileDisplayIdentifiers) foreach (string profileDI in x.ProfileDisplayIdentifiers)
@ -591,92 +589,8 @@ namespace DisplayMagicianShared.AMD
return false; return false;
// Check whether the profiles' properties are equal // Now we need to check the Display Configs themselves
// We need to exclude the name as the name is solely for saving to disk if (x.DisplayConfig.Equals(y.DisplayConfig))
// and displaying to the user.
// Two profiles are equal only when they have the same viewport data
int foundDisplayCount = 0;
int foundOtherDisplayCount = 0;
foreach (AMDAdapter xadapter in x.ProfileData.Adapters)
{
foreach (AMDDisplay xdisplay in xadapter.Displays)
{
foreach (AMDAdapter yadapter in y.ProfileData.Adapters)
{
foreach (AMDDisplay ydisplay in yadapter.Displays)
{
if (ydisplay.Equals(xdisplay))
{
foreach (var ydisplaymode in ydisplay.DisplayModes)
{
foreach (var xdisplaymode in xdisplay.DisplayModes)
{
if (ydisplaymode.Equals(xdisplaymode))
{
foundDisplayCount++;
continue;
}
}
}
}
}
}
}
}
foreach (AMDAdapter yadapter in y.ProfileData.Adapters)
{
foreach (AMDDisplay ydisplay in yadapter.Displays)
{
foreach (AMDAdapter xadapter in x.ProfileData.Adapters)
{
foreach (AMDDisplay xdisplay in xadapter.Displays)
{
if (xdisplay.Equals(ydisplay))
{
foreach (var xdisplaymode in xdisplay.DisplayModes)
{
foreach (var ydisplaymode in ydisplay.DisplayModes)
{
if (xdisplaymode.Equals(ydisplaymode))
{
foundOtherDisplayCount++;
continue;
}
}
}
}
}
}
}
}
/*foreach (AMDAdapter yadapter in y.ProfileData.Adapters)
{
foreach (AMDDisplay ydisplay in yadapter.Displays)
{
foreach (AMDAdapter xadapter in x.ProfileData.Adapters)
{
if (xadapter.Displays.Contains(ydisplay))
{
foundOtherDisplayCount++;
continue;
}
}
}
}*/
// If this matches then there are an additional screen or not enough screens
if (foundDisplayCount != foundOtherDisplayCount)
return false;
// Now we need to check the location of the screens
if (!x.ProfileData.Equals(y.ProfileData))
return false; return false;
return true; return true;
@ -708,7 +622,7 @@ namespace DisplayMagicianShared.AMD
int hashIds = profile.ProfileDisplayIdentifiers == null ? 0 : profile.ProfileDisplayIdentifiers.GetHashCode(); int hashIds = profile.ProfileDisplayIdentifiers == null ? 0 : profile.ProfileDisplayIdentifiers.GetHashCode();
// Get hash code for the Paths // Get hash code for the Paths
int hashProfileData = profile.ProfileData.GetHashCode(); int hashProfileData = profile.DisplayConfig.GetHashCode();
//Calculate the hash code for the product. //Calculate the hash code for the product.
return (hashIds, hashProfileData).GetHashCode(); return (hashIds, hashProfileData).GetHashCode();

View File

@ -54,6 +54,7 @@
<Compile Include="AMD\ADL.cs" /> <Compile Include="AMD\ADL.cs" />
<Compile Include="AMD\AMDLibrary.cs" /> <Compile Include="AMD\AMDLibrary.cs" />
<Compile Include="AMD\AMDProfileItem.cs" /> <Compile Include="AMD\AMDProfileItem.cs" />
<Compile Include="NVIDIA\NVAPI.cs" />
<Compile Include="NVIDIA\NVIDIALibrary.cs" /> <Compile Include="NVIDIA\NVIDIALibrary.cs" />
<Compile Include="NVIDIA\NVIDIAProfileItem.cs" /> <Compile Include="NVIDIA\NVIDIAProfileItem.cs" />
<Compile Include="SharedLogger.cs" /> <Compile Include="SharedLogger.cs" />
@ -64,11 +65,11 @@
</Compile> </Compile>
<Compile Include="ResizeDrawing.cs" /> <Compile Include="ResizeDrawing.cs" />
<Compile Include="ScanLineOrdering.cs" /> <Compile Include="ScanLineOrdering.cs" />
<Compile Include="NVIDIA\SurroundHelper.cs" /> <None Include="NVIDIA\SurroundHelper.cs" />
<Compile Include="NVIDIA\SurroundTopologyDisplay.cs" /> <None Include="NVIDIA\SurroundTopologyDisplay.cs" />
<Compile Include="PixelShift.cs" /> <Compile Include="PixelShift.cs" />
<Compile Include="ProfileItem.cs" /> <Compile Include="ProfileItem.cs" />
<Compile Include="NVIDIA\SurroundTopology.cs" /> <None Include="NVIDIA\SurroundTopology.cs" />
<Compile Include="DisplayMagicianStartupAction.cs" /> <Compile Include="DisplayMagicianStartupAction.cs" />
<Compile Include="ProfileIcon.cs" /> <Compile Include="ProfileIcon.cs" />
<Compile Include="Rotation.cs" /> <Compile Include="Rotation.cs" />
@ -90,8 +91,9 @@
<Compile Include="UserControls\DisplayView.Designer.cs"> <Compile Include="UserControls\DisplayView.Designer.cs">
<DependentUpon>DisplayView.cs</DependentUpon> <DependentUpon>DisplayView.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Windows\WinProfileItem.cs" />
<Compile Include="Windows\CCD.cs" /> <Compile Include="Windows\CCD.cs" />
<Compile Include="Windows\WindowsLibrary.cs" /> <Compile Include="Windows\WinLibrary.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Properties\Resources.resx"> <EmbeddedResource Include="Properties\Resources.resx">

View File

@ -0,0 +1,612 @@
using System;
using System.Runtime.InteropServices;
using FARPROC = System.IntPtr;
using HMODULE = System.IntPtr;
namespace DisplayMagicianShared.NVIDIA
{
//public delegate IntPtr ADL_Main_Memory_Alloc_Delegate(int size);
public enum NVAPI_STATUS : int
{
// Result Codes
NVAPI_OK = 0, //!< Success. Request is completed.
NVAPI_ERROR = -1, //!< Generic error
NVAPI_LIBRARY_NOT_FOUND = -2, //!< NVAPI support library cannot be loaded.
NVAPI_NO_IMPLEMENTATION = -3, //!< not implemented in current driver installation
NVAPI_API_NOT_INITIALIZED = -4, //!< NvAPI_Initialize has not been called (successfully)
NVAPI_INVALID_ARGUMENT = -5, //!< The argument/parameter value is not valid or NULL.
NVAPI_NVIDIA_DEVICE_NOT_FOUND = -6, //!< No NVIDIA display driver, or NVIDIA GPU driving a display, was found.
NVAPI_END_ENUMERATION = -7, //!< No more items to enumerate
NVAPI_INVALID_HANDLE = -8, //!< Invalid handle
NVAPI_INCOMPATIBLE_STRUCT_VERSION = -9, //!< An argument's structure version is not supported
NVAPI_HANDLE_INVALIDATED = -10, //!< The handle is no longer valid (likely due to GPU or display re-configuration)
NVAPI_OPENGL_CONTEXT_NOT_CURRENT = -11, //!< No NVIDIA OpenGL context is current (but needs to be)
NVAPI_INVALID_POINTER = -14, //!< An invalid pointer, usually NULL, was passed as a parameter
NVAPI_NO_GL_EXPERT = -12, //!< OpenGL Expert is not supported by the current drivers
NVAPI_INSTRUMENTATION_DISABLED = -13, //!< OpenGL Expert is supported, but driver instrumentation is currently disabled
NVAPI_NO_GL_NSIGHT = -15, //!< OpenGL does not support Nsight
NVAPI_EXPECTED_LOGICAL_GPU_HANDLE = -100, //!< Expected a logical GPU handle for one or more parameters
NVAPI_EXPECTED_PHYSICAL_GPU_HANDLE = -101, //!< Expected a physical GPU handle for one or more parameters
NVAPI_EXPECTED_DISPLAY_HANDLE = -102, //!< Expected an NV display handle for one or more parameters
NVAPI_INVALID_COMBINATION = -103, //!< The combination of parameters is not valid.
NVAPI_NOT_SUPPORTED = -104, //!< Requested feature is not supported in the selected GPU
NVAPI_PORTID_NOT_FOUND = -105, //!< No port ID was found for the I2C transaction
NVAPI_EXPECTED_UNATTACHED_DISPLAY_HANDLE = -106, //!< Expected an unattached display handle as one of the input parameters.
NVAPI_INVALID_PERF_LEVEL = -107, //!< Invalid perf level
NVAPI_DEVICE_BUSY = -108, //!< Device is busy; request not fulfilled
NVAPI_NV_PERSIST_FILE_NOT_FOUND = -109, //!< NV persist file is not found
NVAPI_PERSIST_DATA_NOT_FOUND = -110, //!< NV persist data is not found
NVAPI_EXPECTED_TV_DISPLAY = -111, //!< Expected a TV output display
NVAPI_EXPECTED_TV_DISPLAY_ON_DCONNECTOR = -112, //!< Expected a TV output on the D Connector - HDTV_EIAJ4120.
NVAPI_NO_ACTIVE_SLI_TOPOLOGY = -113, //!< SLI is not active on this device.
NVAPI_SLI_RENDERING_MODE_NOTALLOWED = -114, //!< Setup of SLI rendering mode is not possible right now.
NVAPI_EXPECTED_DIGITAL_FLAT_PANEL = -115, //!< Expected a digital flat panel.
NVAPI_ARGUMENT_EXCEED_MAX_SIZE = -116, //!< Argument exceeds the expected size.
NVAPI_DEVICE_SWITCHING_NOT_ALLOWED = -117, //!< Inhibit is ON due to one of the flags in NV_GPU_DISPLAY_CHANGE_INHIBIT or SLI active.
NVAPI_TESTING_CLOCKS_NOT_SUPPORTED = -118, //!< Testing of clocks is not supported.
NVAPI_UNKNOWN_UNDERSCAN_CONFIG = -119, //!< The specified underscan config is from an unknown source (e.g. INF)
NVAPI_TIMEOUT_RECONFIGURING_GPU_TOPO = -120, //!< Timeout while reconfiguring GPUs
NVAPI_DATA_NOT_FOUND = -121, //!< Requested data was not found
NVAPI_EXPECTED_ANALOG_DISPLAY = -122, //!< Expected an analog display
NVAPI_NO_VIDLINK = -123, //!< No SLI video bridge is present
NVAPI_REQUIRES_REBOOT = -124, //!< NVAPI requires a reboot for the settings to take effect
NVAPI_INVALID_HYBRID_MODE = -125, //!< The function is not supported with the current Hybrid mode.
NVAPI_MIXED_TARGET_TYPES = -126, //!< The target types are not all the same
NVAPI_SYSWOW64_NOT_SUPPORTED = -127, //!< The function is not supported from 32-bit on a 64-bit system.
NVAPI_IMPLICIT_SET_GPU_TOPOLOGY_CHANGE_NOT_ALLOWED = -128, //!< There is no implicit GPU topology active. Use NVAPI_SetHybridMode to change topology.
NVAPI_REQUEST_USER_TO_CLOSE_NON_MIGRATABLE_APPS = -129, //!< Prompt the user to close all non-migratable applications.
NVAPI_OUT_OF_MEMORY = -130, //!< Could not allocate sufficient memory to complete the call.
NVAPI_WAS_STILL_DRAWING = -131, //!< The previous operation that is transferring information to or from this surface is incomplete.
NVAPI_FILE_NOT_FOUND = -132, //!< The file was not found.
NVAPI_TOO_MANY_UNIQUE_STATE_OBJECTS = -133, //!< There are too many unique instances of a particular type of state object.
NVAPI_INVALID_CALL = -134, //!< The method call is invalid. For example, a method's parameter may not be a valid pointer.
NVAPI_D3D10_1_LIBRARY_NOT_FOUND = -135, //!< d3d10_1.dll cannot be loaded.
NVAPI_FUNCTION_NOT_FOUND = -136, //!< Couldn't find the function in the loaded DLL.
NVAPI_INVALID_USER_PRIVILEGE = -137, //!< The application will require Administrator privileges to access this API.
//!< The application can be elevated to a higher permission level by selecting "Run as Administrator".
NVAPI_EXPECTED_NON_PRIMARY_DISPLAY_HANDLE = -138, //!< The handle corresponds to GDIPrimary.
NVAPI_EXPECTED_COMPUTE_GPU_HANDLE = -139, //!< Setting Physx GPU requires that the GPU is compute-capable.
NVAPI_STEREO_NOT_INITIALIZED = -140, //!< The Stereo part of NVAPI failed to initialize completely. Check if the stereo driver is installed.
NVAPI_STEREO_REGISTRY_ACCESS_FAILED = -141, //!< Access to stereo-related registry keys or values has failed.
NVAPI_STEREO_REGISTRY_PROFILE_TYPE_NOT_SUPPORTED = -142, //!< The given registry profile type is not supported.
NVAPI_STEREO_REGISTRY_VALUE_NOT_SUPPORTED = -143, //!< The given registry value is not supported.
NVAPI_STEREO_NOT_ENABLED = -144, //!< Stereo is not enabled and the function needed it to execute completely.
NVAPI_STEREO_NOT_TURNED_ON = -145, //!< Stereo is not turned on and the function needed it to execute completely.
NVAPI_STEREO_INVALID_DEVICE_INTERFACE = -146, //!< Invalid device interface.
NVAPI_STEREO_PARAMETER_OUT_OF_RANGE = -147, //!< Separation percentage or JPEG image capture quality is out of [0-100] range.
NVAPI_STEREO_FRUSTUM_ADJUST_MODE_NOT_SUPPORTED = -148, //!< The given frustum adjust mode is not supported.
NVAPI_TOPO_NOT_POSSIBLE = -149, //!< The mosaic topology is not possible given the current state of the hardware.
NVAPI_MODE_CHANGE_FAILED = -150, //!< An attempt to do a display resolution mode change has failed.
NVAPI_D3D11_LIBRARY_NOT_FOUND = -151, //!< d3d11.dll/d3d11_beta.dll cannot be loaded.
NVAPI_INVALID_ADDRESS = -152, //!< Address is outside of valid range.
NVAPI_STRING_TOO_SMALL = -153, //!< The pre-allocated string is too small to hold the result.
NVAPI_MATCHING_DEVICE_NOT_FOUND = -154, //!< The input does not match any of the available devices.
NVAPI_DRIVER_RUNNING = -155, //!< Driver is running.
NVAPI_DRIVER_NOTRUNNING = -156, //!< Driver is not running.
NVAPI_ERROR_DRIVER_RELOAD_REQUIRED = -157, //!< A driver reload is required to apply these settings.
NVAPI_SET_NOT_ALLOWED = -158, //!< Intended setting is not allowed.
NVAPI_ADVANCED_DISPLAY_TOPOLOGY_REQUIRED = -159, //!< Information can't be returned due to "advanced display topology".
NVAPI_SETTING_NOT_FOUND = -160, //!< Setting is not found.
NVAPI_SETTING_SIZE_TOO_LARGE = -161, //!< Setting size is too large.
NVAPI_TOO_MANY_SETTINGS_IN_PROFILE = -162, //!< There are too many settings for a profile.
NVAPI_PROFILE_NOT_FOUND = -163, //!< Profile is not found.
NVAPI_PROFILE_NAME_IN_USE = -164, //!< Profile name is duplicated.
NVAPI_PROFILE_NAME_EMPTY = -165, //!< Profile name is empty.
NVAPI_EXECUTABLE_NOT_FOUND = -166, //!< Application not found in the Profile.
NVAPI_EXECUTABLE_ALREADY_IN_USE = -167, //!< Application already exists in the other profile.
NVAPI_DATATYPE_MISMATCH = -168, //!< Data Type mismatch
NVAPI_PROFILE_REMOVED = -169, //!< The profile passed as parameter has been removed and is no longer valid.
NVAPI_UNREGISTERED_RESOURCE = -170, //!< An unregistered resource was passed as a parameter.
NVAPI_ID_OUT_OF_RANGE = -171, //!< The DisplayId corresponds to a display which is not within the normal outputId range.
NVAPI_DISPLAYCONFIG_VALIDATION_FAILED = -172, //!< Display topology is not valid so the driver cannot do a mode set on this configuration.
NVAPI_DPMST_CHANGED = -173, //!< Display Port Multi-Stream topology has been changed.
NVAPI_INSUFFICIENT_BUFFER = -174, //!< Input buffer is insufficient to hold the contents.
NVAPI_ACCESS_DENIED = -175, //!< No access to the caller.
NVAPI_MOSAIC_NOT_ACTIVE = -176, //!< The requested action cannot be performed without Mosaic being enabled.
NVAPI_SHARE_RESOURCE_RELOCATED = -177, //!< The surface is relocated away from video memory.
NVAPI_REQUEST_USER_TO_DISABLE_DWM = -178, //!< The user should disable DWM before calling NvAPI.
NVAPI_D3D_DEVICE_LOST = -179, //!< D3D device status is D3DERR_DEVICELOST or D3DERR_DEVICENOTRESET - the user has to reset the device.
NVAPI_INVALID_CONFIGURATION = -180, //!< The requested action cannot be performed in the current state.
NVAPI_STEREO_HANDSHAKE_NOT_DONE = -181, //!< Call failed as stereo handshake not completed.
NVAPI_EXECUTABLE_PATH_IS_AMBIGUOUS = -182, //!< The path provided was too short to determine the correct NVDRS_APPLICATION
NVAPI_DEFAULT_STEREO_PROFILE_IS_NOT_DEFINED = -183, //!< Default stereo profile is not currently defined
NVAPI_DEFAULT_STEREO_PROFILE_DOES_NOT_EXIST = -184, //!< Default stereo profile does not exist
NVAPI_CLUSTER_ALREADY_EXISTS = -185, //!< A cluster is already defined with the given configuration.
NVAPI_DPMST_DISPLAY_ID_EXPECTED = -186, //!< The input display id is not that of a multi stream enabled connector or a display device in a multi stream topology
NVAPI_INVALID_DISPLAY_ID = -187, //!< The input display id is not valid or the monitor associated to it does not support the current operation
NVAPI_STREAM_IS_OUT_OF_SYNC = -188, //!< While playing secure audio stream, stream goes out of sync
NVAPI_INCOMPATIBLE_AUDIO_DRIVER = -189, //!< Older audio driver version than required
NVAPI_VALUE_ALREADY_SET = -190, //!< Value already set, setting again not allowed.
NVAPI_TIMEOUT = -191, //!< Requested operation timed out
NVAPI_GPU_WORKSTATION_FEATURE_INCOMPLETE = -192, //!< The requested workstation feature set has incomplete driver internal allocation resources
NVAPI_STEREO_INIT_ACTIVATION_NOT_DONE = -193, //!< Call failed because InitActivation was not called.
NVAPI_SYNC_NOT_ACTIVE = -194, //!< The requested action cannot be performed without Sync being enabled.
NVAPI_SYNC_MASTER_NOT_FOUND = -195, //!< The requested action cannot be performed without Sync Master being enabled.
NVAPI_INVALID_SYNC_TOPOLOGY = -196, //!< Invalid displays passed in the NV_GSYNC_DISPLAY pointer.
NVAPI_ECID_SIGN_ALGO_UNSUPPORTED = -197, //!< The specified signing algorithm is not supported. Either an incorrect value was entered or the current installed driver/hardware does not support the input value.
NVAPI_ECID_KEY_VERIFICATION_FAILED = -198, //!< The encrypted public key verification has failed.
NVAPI_FIRMWARE_OUT_OF_DATE = -199, //!< The device's firmware is out of date.
NVAPI_FIRMWARE_REVISION_NOT_SUPPORTED = -200, //!< The device's firmware is not supported.
NVAPI_LICENSE_CALLER_AUTHENTICATION_FAILED = -201, //!< The caller is not authorized to modify the License.
NVAPI_D3D_DEVICE_NOT_REGISTERED = -202, //!< The user tried to use a deferred context without registering the device first
NVAPI_RESOURCE_NOT_ACQUIRED = -203, //!< Head or SourceId was not reserved for the VR Display before doing the Modeset.
NVAPI_TIMING_NOT_SUPPORTED = -204, //!< Provided timing is not supported.
NVAPI_HDCP_ENCRYPTION_FAILED = -205, //!< HDCP Encryption Failed for the device. Would be applicable when the device is HDCP Capable.
NVAPI_PCLK_LIMITATION_FAILED = -206, //!< Provided mode is over sink device pclk limitation.
NVAPI_NO_CONNECTOR_FOUND = -207, //!< No connector on GPU found.
NVAPI_HDCP_DISABLED = -208, //!< When a non-HDCP capable HMD is connected, we would inform user by this code.
NVAPI_API_IN_USE = -209, //!< Atleast an API is still being called
NVAPI_NVIDIA_DISPLAY_NOT_FOUND = -210, //!< No display found on Nvidia GPU(s).
NVAPI_PRIV_SEC_VIOLATION = -211, //!< Priv security violation, improper access to a secured register.
NVAPI_INCORRECT_VENDOR = -212, //!< NVAPI cannot be called by this vendor
NVAPI_DISPLAY_IN_USE = -213, //!< DirectMode Display is already in use
NVAPI_UNSUPPORTED_CONFIG_NON_HDCP_HMD = -214, //!< The Config is having Non-NVidia GPU with Non-HDCP HMD connected
NVAPI_MAX_DISPLAY_LIMIT_REACHED = -215, //!< GPU's Max Display Limit has Reached
NVAPI_INVALID_DIRECT_MODE_DISPLAY = -216, //!< DirectMode not Enabled on the Display
NVAPI_GPU_IN_DEBUG_MODE = -217, //!< GPU is in debug mode, OC is NOT allowed.
NVAPI_D3D_CONTEXT_NOT_FOUND = -218, //!< No NvAPI context was found for this D3D object
NVAPI_STEREO_VERSION_MISMATCH = -219, //!< there is version mismatch between stereo driver and dx driver
NVAPI_GPU_NOT_POWERED = -220, //!< GPU is not powered and so the request cannot be completed.
NVAPI_ERROR_DRIVER_RELOAD_IN_PROGRESS = -221, //!< The display driver update in progress.
NVAPI_WAIT_FOR_HW_RESOURCE = -222, //!< Wait for HW resources allocation
NVAPI_REQUIRE_FURTHER_HDCP_ACTION = -223, //!< operation requires further HDCP action
NVAPI_DISPLAY_MUX_TRANSITION_FAILED = -224, //!< Dynamic Mux transition failure
NVAPI_INVALID_DSC_VERSION = -225, //!< Invalid DSC version
NVAPI_INVALID_DSC_SLICECOUNT = -226, //!< Invalid DSC slice count
NVAPI_INVALID_DSC_OUTPUT_BPP = -227, //!< Invalid DSC output BPP
NVAPI_FAILED_TO_LOAD_FROM_DRIVER_STORE = -228, //!< There was an error while loading nvapi.dll from the driver store.
NVAPI_NO_VULKAN = -229, //!< OpenGL does not export Vulkan fake extensions
NVAPI_REQUEST_PENDING = -230, //!< A request for NvTOPPs telemetry CData has already been made and is pending a response.
NVAPI_RESOURCE_IN_USE = -231, //!< Operation cannot be performed because the resource is in use.
}
public enum NV_DISPLAYCONFIG_FLAGS : uint
{
NV_DISPLAYCONFIG_VALIDATE_ONLY = 0x00000001,
NV_DISPLAYCONFIG_SAVE_TO_PERSISTENCE = 0x00000002,
NV_DISPLAYCONFIG_DRIVER_RELOAD_ALLOWED = 0x00000004, //!< Driver reload is permitted if necessary
NV_DISPLAYCONFIG_FORCE_MODE_ENUMERATION = 0x00000008, //!< Refresh OS mode list.
NV_FORCE_COMMIT_VIDPN = 0x00000010, //!< Tell OS to avoid optimizing CommitVidPn call during a modeset
}
public enum NV_ROTATE : uint
{
NV_ROTATE_0 = 0,
NV_ROTATE_90 = 1,
NV_ROTATE_180 = 2,
NV_ROTATE_270 = 3,
NV_ROTATE_IGNORED = 4,
}
public enum NV_FORMAT : uint
{
NV_FORMAT_UNKNOWN = 0, //!< unknown. Driver will choose one as following value.
NV_FORMAT_P8 = 41, //!< for 8bpp mode
NV_FORMAT_R5G6B5 = 23, //!< for 16bpp mode
NV_FORMAT_A8R8G8B8 = 21, //!< for 32bpp mode
NV_FORMAT_A16B16G16R16F = 113, //!< for 64bpp(floating point) mode.
}
public enum NV_SCALING : uint
{
NV_SCALING_DEFAULT = 0, //!< No change
// New Scaling Declarations
NV_SCALING_GPU_SCALING_TO_CLOSEST = 1, //!< Balanced - Full Screen
NV_SCALING_GPU_SCALING_TO_NATIVE = 2, //!< Force GPU - Full Screen
NV_SCALING_GPU_SCANOUT_TO_NATIVE = 3, //!< Force GPU - Centered\No Scaling
NV_SCALING_GPU_SCALING_TO_ASPECT_SCANOUT_TO_NATIVE = 5, //!< Force GPU - Aspect Ratio
NV_SCALING_GPU_SCALING_TO_ASPECT_SCANOUT_TO_CLOSEST = 6, //!< Balanced - Aspect Ratio
NV_SCALING_GPU_SCANOUT_TO_CLOSEST = 7, //!< Balanced - Centered\No Scaling
NV_SCALING_GPU_INTEGER_ASPECT_SCALING = 8, //!< Force GPU - Integer Scaling
// Legacy Declarations
NV_SCALING_MONITOR_SCALING = NV_SCALING_GPU_SCALING_TO_CLOSEST,
NV_SCALING_ADAPTER_SCALING = NV_SCALING_GPU_SCALING_TO_NATIVE,
NV_SCALING_CENTERED = NV_SCALING_GPU_SCANOUT_TO_NATIVE,
NV_SCALING_ASPECT_SCALING = NV_SCALING_GPU_SCALING_TO_ASPECT_SCANOUT_TO_NATIVE,
NV_SCALING_CUSTOMIZED = 255 //!< For future use
}
public enum NV_TARGET_VIEW_MODE : uint
{
NV_VIEW_MODE_STANDARD = 0,
NV_VIEW_MODE_CLONE = 1,
NV_VIEW_MODE_HSPAN = 2,
NV_VIEW_MODE_VSPAN = 3,
NV_VIEW_MODE_DUALVIEW = 4,
NV_VIEW_MODE_MULTIVIEW = 5,
}
public enum NV_DISPLAY_TV_FORMAT : uint
{
NV_DISPLAY_TV_FORMAT_NONE = 0,
NV_DISPLAY_TV_FORMAT_SD_NTSCM = 0x00000001,
NV_DISPLAY_TV_FORMAT_SD_NTSCJ = 0x00000002,
NV_DISPLAY_TV_FORMAT_SD_PALM = 0x00000004,
NV_DISPLAY_TV_FORMAT_SD_PALBDGH = 0x00000008,
NV_DISPLAY_TV_FORMAT_SD_PALN = 0x00000010,
NV_DISPLAY_TV_FORMAT_SD_PALNC = 0x00000020,
NV_DISPLAY_TV_FORMAT_SD_576i = 0x00000100,
NV_DISPLAY_TV_FORMAT_SD_480i = 0x00000200,
NV_DISPLAY_TV_FORMAT_ED_480p = 0x00000400,
NV_DISPLAY_TV_FORMAT_ED_576p = 0x00000800,
NV_DISPLAY_TV_FORMAT_HD_720p = 0x00001000,
NV_DISPLAY_TV_FORMAT_HD_1080i = 0x00002000,
NV_DISPLAY_TV_FORMAT_HD_1080p = 0x00004000,
NV_DISPLAY_TV_FORMAT_HD_720p50 = 0x00008000,
NV_DISPLAY_TV_FORMAT_HD_1080p24 = 0x00010000,
NV_DISPLAY_TV_FORMAT_HD_1080i50 = 0x00020000,
NV_DISPLAY_TV_FORMAT_HD_1080p50 = 0x00040000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp30 = 0x00080000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp30_3840 = NV_DISPLAY_TV_FORMAT_UHD_4Kp30,
NV_DISPLAY_TV_FORMAT_UHD_4Kp25 = 0x00100000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp25_3840 = NV_DISPLAY_TV_FORMAT_UHD_4Kp25,
NV_DISPLAY_TV_FORMAT_UHD_4Kp24 = 0x00200000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp24_3840 = NV_DISPLAY_TV_FORMAT_UHD_4Kp24,
NV_DISPLAY_TV_FORMAT_UHD_4Kp24_SMPTE = 0x00400000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp50_3840 = 0x00800000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp60_3840 = 0x00900000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp30_4096 = 0x00A00000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp25_4096 = 0x00B00000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp24_4096 = 0x00C00000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp50_4096 = 0x00D00000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp60_4096 = 0x00E00000,
NV_DISPLAY_TV_FORMAT_UHD_8Kp24_7680 = 0x01000000,
NV_DISPLAY_TV_FORMAT_UHD_8Kp25_7680 = 0x02000000,
NV_DISPLAY_TV_FORMAT_UHD_8Kp30_7680 = 0x04000000,
NV_DISPLAY_TV_FORMAT_UHD_8Kp48_7680 = 0x08000000,
NV_DISPLAY_TV_FORMAT_UHD_8Kp50_7680 = 0x09000000,
NV_DISPLAY_TV_FORMAT_UHD_8Kp60_7680 = 0x0A000000,
NV_DISPLAY_TV_FORMAT_UHD_8Kp100_7680 = 0x0B000000,
NV_DISPLAY_TV_FORMAT_UHD_8Kp120_7680 = 0x0C000000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp48_3840 = 0x0D000000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp48_4096 = 0x0E000000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp100_4096 = 0x0F000000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp100_3840 = 0x10000000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp120_4096 = 0x11000000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp120_3840 = 0x12000000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp100_5120 = 0x13000000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp120_5120 = 0x14000000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp24_5120 = 0x15000000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp25_5120 = 0x16000000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp30_5120 = 0x17000000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp48_5120 = 0x18000000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp50_5120 = 0x19000000,
NV_DISPLAY_TV_FORMAT_UHD_4Kp60_5120 = 0x20000000,
NV_DISPLAY_TV_FORMAT_UHD_10Kp24_10240 = 0x21000000,
NV_DISPLAY_TV_FORMAT_UHD_10Kp25_10240 = 0x22000000,
NV_DISPLAY_TV_FORMAT_UHD_10Kp30_10240 = 0x23000000,
NV_DISPLAY_TV_FORMAT_UHD_10Kp48_10240 = 0x24000000,
NV_DISPLAY_TV_FORMAT_UHD_10Kp50_10240 = 0x25000000,
NV_DISPLAY_TV_FORMAT_UHD_10Kp60_10240 = 0x26000000,
NV_DISPLAY_TV_FORMAT_UHD_10Kp100_10240 = 0x27000000,
NV_DISPLAY_TV_FORMAT_UHD_10Kp120_10240 = 0x28000000,
NV_DISPLAY_TV_FORMAT_SD_OTHER = 0x30000000,
NV_DISPLAY_TV_FORMAT_ED_OTHER = 0x40000000,
NV_DISPLAY_TV_FORMAT_HD_OTHER = 0x50000000,
NV_DISPLAY_TV_FORMAT_ANY = 0x80000000,
}
public enum NV_GPU_CONNECTOR_TYPE : uint
{
NVAPI_GPU_CONNECTOR_VGA_15_PIN = 0x00000000,
NVAPI_GPU_CONNECTOR_TV_COMPOSITE = 0x00000010,
NVAPI_GPU_CONNECTOR_TV_SVIDEO = 0x00000011,
NVAPI_GPU_CONNECTOR_TV_HDTV_COMPONENT = 0x00000013,
NVAPI_GPU_CONNECTOR_TV_SCART = 0x00000014,
NVAPI_GPU_CONNECTOR_TV_COMPOSITE_SCART_ON_EIAJ4120 = 0x00000016,
NVAPI_GPU_CONNECTOR_TV_HDTV_EIAJ4120 = 0x00000017,
NVAPI_GPU_CONNECTOR_PC_POD_HDTV_YPRPB = 0x00000018,
NVAPI_GPU_CONNECTOR_PC_POD_SVIDEO = 0x00000019,
NVAPI_GPU_CONNECTOR_PC_POD_COMPOSITE = 0x0000001A,
NVAPI_GPU_CONNECTOR_DVI_I_TV_SVIDEO = 0x00000020,
NVAPI_GPU_CONNECTOR_DVI_I_TV_COMPOSITE = 0x00000021,
NVAPI_GPU_CONNECTOR_DVI_I = 0x00000030,
NVAPI_GPU_CONNECTOR_DVI_D = 0x00000031,
NVAPI_GPU_CONNECTOR_ADC = 0x00000032,
NVAPI_GPU_CONNECTOR_LFH_DVI_I_1 = 0x00000038,
NVAPI_GPU_CONNECTOR_LFH_DVI_I_2 = 0x00000039,
NVAPI_GPU_CONNECTOR_SPWG = 0x00000040,
NVAPI_GPU_CONNECTOR_OEM = 0x00000041,
NVAPI_GPU_CONNECTOR_DISPLAYPORT_EXTERNAL = 0x00000046,
NVAPI_GPU_CONNECTOR_DISPLAYPORT_INTERNAL = 0x00000047,
NVAPI_GPU_CONNECTOR_DISPLAYPORT_MINI_EXT = 0x00000048,
NVAPI_GPU_CONNECTOR_HDMI_A = 0x00000061,
NVAPI_GPU_CONNECTOR_HDMI_C_MINI = 0x00000063,
NVAPI_GPU_CONNECTOR_LFH_DISPLAYPORT_1 = 0x00000064,
NVAPI_GPU_CONNECTOR_LFH_DISPLAYPORT_2 = 0x00000065,
NVAPI_GPU_CONNECTOR_VIRTUAL_WFD = 0x00000070,
NVAPI_GPU_CONNECTOR_USB_C = 0x00000071,
NVAPI_GPU_CONNECTOR_UNKNOWN = 0xFFFFFFFF,
}
public enum NV_TIMING_OVERRIDE : uint
{
NV_TIMING_OVERRIDE_CURRENT = 0, //!< get the current timing
NV_TIMING_OVERRIDE_AUTO, //!< the timing the driver will use based the current policy
NV_TIMING_OVERRIDE_EDID, //!< EDID timing
NV_TIMING_OVERRIDE_DMT, //!< VESA DMT timing
NV_TIMING_OVERRIDE_DMT_RB, //!< VESA DMT timing with reduced blanking
NV_TIMING_OVERRIDE_CVT, //!< VESA CVT timing
NV_TIMING_OVERRIDE_CVT_RB, //!< VESA CVT timing with reduced blanking
NV_TIMING_OVERRIDE_GTF, //!< VESA GTF timing
NV_TIMING_OVERRIDE_EIA861, //!< EIA 861x pre-defined timing
NV_TIMING_OVERRIDE_ANALOG_TV, //!< analog SD/HDTV timing
NV_TIMING_OVERRIDE_CUST, //!< NV custom timings
NV_TIMING_OVERRIDE_NV_PREDEFINED, //!< NV pre-defined timing (basically the PsF timings)
NV_TIMING_OVERRIDE_NV_PSF = NV_TIMING_OVERRIDE_NV_PREDEFINED,
NV_TIMING_OVERRIDE_NV_ASPR,
NV_TIMING_OVERRIDE_SDI, //!< Override for SDI timing
NV_TIMING_OVRRIDE_MAX,
}
[StructLayout(LayoutKind.Sequential)]
public struct DisplayHandle
{
private readonly IntPtr ptr;
}
[StructLayout(LayoutKind.Sequential)]
public struct UnAttachedDisplayHandle
{
public readonly IntPtr ptr;
}
[StructLayout(LayoutKind.Sequential)]
public struct PhysicalGpuHandle
{
private readonly IntPtr ptr;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct NV_TIMINGEXT
{
public uint flag; //!< Reserved for NVIDIA hardware-based enhancement, such as double-scan.
public ushort rr; //!< Logical refresh rate to present
public uint rrx1k; //!< Physical vertical refresh rate in 0.001Hz
public uint aspect; //!< Display aspect ratio Hi(aspect):horizontal-aspect, Low(aspect):vertical-aspect
public ushort rep; //!< Bit-wise pixel repetition factor: 0x1:no pixel repetition; 0x2:each pixel repeats twice horizontally,..
public uint status; //!< Timing standard
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
public string name; //!< Timing name
}
[StructLayout(LayoutKind.Sequential)]
public struct NV_TIMING
{
// VESA scan out timing parameters:
public ushort HVisible; //!< horizontal visible
public ushort HBorder; //!< horizontal border
public ushort HFrontPorch; //!< horizontal front porch
public ushort HSyncWidth; //!< horizontal sync width
public ushort HTotal; //!< horizontal total
public byte HSyncPol; //!< horizontal sync polarity: 1-negative, 0-positive
public ushort VVisible; //!< vertical visible
public ushort VBorder; //!< vertical border
public ushort VFrontPorch; //!< vertical front porch
public ushort VSyncWidth; //!< vertical sync width
public ushort VTotal; //!< vertical total
public byte VSyncPol; //!< vertical sync polarity: 1-negative, 0-positive
public ushort interlaced; //!< 1-interlaced, 0-progressive
public uint pclk; //!< pixel clock in 10 kHz
//other timing related extras
NV_TIMINGEXT etc;
}
[StructLayout(LayoutKind.Sequential)]
public struct NV_POSITION
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
public struct NV_RESOLUTION
{
public uint width;
public uint height;
public uint colorDepth;
}
[StructLayout(LayoutKind.Sequential)]
public struct NV_VIEWPORTF
{
public float x; //!< x-coordinate of the viewport top-left point
public float y; //!< y-coordinate of the viewport top-left point
public float w; //!< Width of the viewport
public float h; //!< Height of the viewport
}
[StructLayout(LayoutKind.Sequential)]
public struct NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO
{
public uint version;
// Rotation and Scaling
public NV_ROTATE rotation; //!< (IN) rotation setting.
public NV_SCALING scaling; //!< (IN) scaling setting.
// Refresh Rate
public uint refreshRate1K; //!< (IN) Non-interlaced Refresh Rate of the mode, multiplied by 1000, 0 = ignored
//!< This is the value which driver reports to the OS.
// Flags
//public uint interlaced:1; //!< (IN) Interlaced mode flag, ignored if refreshRate == 0
//public uint primary:1; //!< (IN) Declares primary display in clone configuration. This is *NOT* GDI Primary.
//!< Only one target can be primary per source. If no primary is specified, the first
//!< target will automatically be primary.
//public uint isPanAndScanTarget:1; //!< Whether on this target Pan and Scan is enabled or has to be enabled. Valid only
//!< when the target is part of clone topology.
//public uint disableVirtualModeSupport:1;
//public uint isPreferredUnscaledTarget:1;
//public uint reserved:27;
// TV format information
public NV_GPU_CONNECTOR_TYPE connector; //!< Specify connector type. For TV only, ignored if tvFormat == NV_DISPLAY_TV_FORMAT_NONE
public NV_DISPLAY_TV_FORMAT tvFormat; //!< (IN) to choose the last TV format set this value to NV_DISPLAY_TV_FORMAT_NONE
//!< In case of NvAPI_DISP_GetDisplayConfig(), this field will indicate the currently applied TV format;
//!< if no TV format is applied, this field will have NV_DISPLAY_TV_FORMAT_NONE value.
//!< In case of NvAPI_DISP_SetDisplayConfig(), this field should only be set in case of TVs;
//!< for other displays this field will be ignored and resolution & refresh rate specified in input will be used to apply the TV format.
// Backend (raster) timing standard
public NV_TIMING_OVERRIDE timingOverride; //!< Ignored if timingOverride == NV_TIMING_OVERRIDE_CURRENT
public NV_TIMING timing; //!< Scan out timing, valid only if timingOverride == NV_TIMING_OVERRIDE_CUST
//!< The value NV_TIMING::NV_TIMINGEXT::rrx1k is obtained from the EDID. The driver may
//!< tweak this value for HDTV, stereo, etc., before reporting it to the OS.
}
[StructLayout(LayoutKind.Sequential)]
public struct NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2
{
public uint displayId; //!< Display ID
NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO[] details; //!< May be NULL if no advanced settings are required
public uint targetId; //!< Windows CCD target ID. Must be present only for non-NVIDIA adapter, for NVIDIA adapter this parameter is ignored.
}
[StructLayout(LayoutKind.Sequential)]
public struct NV_DISPLAYCONFIG_PATH_INFO_V2
{
public uint Version;
public uint SourceId; //!< Identifies sourceId used by Windows CCD. This can be optionally set.
public uint TargetInfoCount; //!< Number of elements in targetInfo array
public NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2[] TargetInfo;
public NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1[] sourceModeInfo; //!< May be NULL if mode info is not important
//public uint IsNonNVIDIAAdapter : 1; //!< True for non-NVIDIA adapter.
//public uint reserved : 31; //!< Must be 0
//public LUID pOSAdapterID; //!< Used by Non-NVIDIA adapter for pointer to OS Adapter of LUID
//!< type, type casted to void *.
}
[StructLayout(LayoutKind.Sequential)]
public struct NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1
{
public NV_RESOLUTION resolution;
public NV_FORMAT colorFormat; //!< Ignored at present, must be NV_FORMAT_UNKNOWN (0)
public NV_POSITION position; //!< Is all positions are 0 or invalid, displays will be automatically
//!< positioned from left to right with GDI Primary at 0,0, and all
//!< other displays in the order of the path array.
//public NV_DISPLAYCONFIG_SPANNING_ORIENTATION spanningOrientation; //!< Spanning is only supported on XP
//public uint bGDIPrimary : 1;
//public uint bSLIFocus : 1;
//public uint reserved : 30; //!< Must be 0
}
[StructLayout(LayoutKind.Sequential)]
public struct NV_DISPLAYCONFIG_PATH_TARGET_INFO
{
public uint displayId; //!< Display ID
public NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO[] details; //!< May be NULL if no advanced settings are required
public uint targetId; //!< Windows CCD target ID. Must be present only for non-NVIDIA adapter, for NVIDIA adapter this parameter is ignored.
}
class NVImport
{
public const uint NV_MAX_HEADS = 4;
public const uint NV_MAX_VID_PROFILES = 4;
public const uint NV_MAX_VID_STREAMS = 4;
public const uint NV_ADVANCED_DISPLAY_HEADS = 4;
public const uint NV_GENERIC_STRING_MAX = 4096;
public const uint NV_LONG_STRING_MAX = 256;
public const uint NV_MAX_ACPI_IDS = 16;
public const uint NV_MAX_AUDIO_DEVICES = 16;
public const uint NV_MAX_AVAILABLE_CPU_TOPOLOGIES = 256;
public const uint NV_MAX_AVAILABLE_SLI_GROUPS = 256;
public const uint NV_MAX_AVAILABLE_DISPLAY_HEADS = 2;
public const uint NV_MAX_DISPLAYS = NV_PHYSICAL_GPUS * NV_ADVANCED_DISPLAY_HEADS;
public const uint NV_MAX_GPU_PER_TOPOLOGY = 8;
public const uint NV_MAX_GPU_TOPOLOGIES = NV_MAX_PHYSICAL_GPUS;
public const uint NV_MAX_HEADS_PER_GPU = 32;
public const uint NV_MAX_LOGICAL_GPUS = 64;
public const uint NV_MAX_PHYSICAL_BRIDGES = 100;
public const uint NV_MAX_PHYSICAL_GPUS = 64;
public const uint NV_MAX_VIEW_MODES = 8;
public const uint NV_PHYSICAL_GPUS = 32;
public const uint NV_SHORT_STRING_MAX = 64;
public const uint NV_SYSTEM_HWBC_INVALID_ID = 0xffffffff;
public const uint NV_SYSTEM_MAX_DISPLAYS = NV_MAX_PHYSICAL_GPUS * NV_MAX_HEADS;
public const uint NV_SYSTEM_MAX_HWBCS = 128;
#region Internal Constant
/// <summary> Nvapi64_FileName </summary>
public const string NVAPI_DLL = "nvapi64.dll";
/// <summary> Kernel32_FileName </summary>
public const string Kernel32_FileName = "kernel32.dll";
#endregion Internal Constant
#region DLLImport
[DllImport(Kernel32_FileName)]
public static extern HMODULE GetModuleHandle(string moduleName);
// This function initializes the NvAPI library (if not already initialized) but always increments the ref-counter.
// This must be called before calling other NvAPI_ functions. Note: It is now mandatory to call NvAPI_Initialize before calling any other NvAPI. NvAPI_Unload should be called to unload the NVAPI Library.
[DllImport(NVAPI_DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern NVAPI_STATUS NvAPI_Initialize();
//DESCRIPTION: Decrements the ref-counter and when it reaches ZERO, unloads NVAPI library.This must be called in pairs with NvAPI_Initialize.
// If the client wants unload functionality, it is recommended to always call NvAPI_Initialize and NvAPI_Unload in pairs.
// Unloading NvAPI library is not supported when the library is in a resource locked state.
// Some functions in the NvAPI library initiates an operation or allocates certain resources and there are corresponding functions available, to complete the operation or free the allocated resources.
// All such function pairs are designed to prevent unloading NvAPI library. For example, if NvAPI_Unload is called after NvAPI_XXX which locks a resource, it fails with NVAPI_ERROR.
// Developers need to call the corresponding NvAPI_YYY to unlock the resources, before calling NvAPI_Unload again.
[DllImport(NVAPI_DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern NVAPI_STATUS NvAPI_Unload();
// This is used to get a string containing the NVAPI version
[DllImport(NVAPI_DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern NVAPI_STATUS NvAPI_GetInterfaceVersionStringEx(out string description);
// NVAPI SESSION HANDLING FUNCTIONS
// This is used to get a session handle to use to maintain state across multiple NVAPI calls
[DllImport(NVAPI_DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern NVAPI_STATUS NvAPI_DRS_CreateSession(out IntPtr session);
// This is used to destroy a session handle to used to maintain state across multiple NVAPI calls
[DllImport(NVAPI_DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern NVAPI_STATUS NvAPI_DRS_DestorySession(IntPtr session);
// This API lets caller retrieve the current global display configuration.
// USAGE: The caller might have to call this three times to fetch all the required configuration details as follows:
// First Pass: Caller should Call NvAPI_DISP_GetDisplayConfig() with pathInfo set to NULL to fetch pathInfoCount.
// Second Pass: Allocate memory for pathInfo with respect to the number of pathInfoCount(from First Pass) to fetch targetInfoCount. If sourceModeInfo is needed allocate memory or it can be initialized to NULL.
// Third Pass(Optional, only required if target information is required): Allocate memory for targetInfo with respect to number of targetInfoCount(from Second Pass).
[DllImport(NVAPI_DLL, CallingConvention = CallingConvention.Cdecl)]
public static extern NVAPI_STATUS NvAPI_DISP_GetDisplayConfig(ref ulong pathInfoCount, out NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 pathInfo);
#endregion DLLImport
/*public static ADL_Main_Memory_Alloc_Delegate ADL_Main_Memory_Alloc = ADL_Main_Memory_Alloc_Function;
/// <summary> Build in memory allocation function</summary>
/// <param name="size">input size</param>
/// <returns>return the memory buffer</returns>
public static IntPtr ADL_Main_Memory_Alloc_Function(int size)
{
//Console.WriteLine($"\nCallback called with param: {size}");
IntPtr result = Marshal.AllocCoTaskMem(size);
return result;
}*/
}
}

File diff suppressed because it is too large Load Diff

View File

@ -95,7 +95,7 @@ namespace DisplayMagicianShared.NVIDIA
{ {
if (_profileDisplayIdentifiers.Count == 0) if (_profileDisplayIdentifiers.Count == 0)
{ {
_profileDisplayIdentifiers = NVIDIALibrary.GetLibrary().GenerateProfileDisplayIdentifiers(); _profileDisplayIdentifiers = NVIDIALibrary.GetLibrary().GetCurrentDisplayIdentifiers();
} }
return _profileDisplayIdentifiers; return _profileDisplayIdentifiers;
} }
@ -168,7 +168,7 @@ namespace DisplayMagicianShared.NVIDIA
// Prepare our profile data for saving // Prepare our profile data for saving
if (_profileDisplayIdentifiers.Count == 0) if (_profileDisplayIdentifiers.Count == 0)
{ {
_profileDisplayIdentifiers = NVIDIALibrary.GetLibrary().GenerateProfileDisplayIdentifiers(); _profileDisplayIdentifiers = NVIDIALibrary.GetLibrary().GetCurrentDisplayIdentifiers();
} }
// Return if it is valid and we should continue // Return if it is valid and we should continue

View File

@ -245,7 +245,7 @@ namespace DisplayMagicianShared
{ {
if (_profileDisplayIdentifiers.Count == 0) if (_profileDisplayIdentifiers.Count == 0)
{ {
_profileDisplayIdentifiers = ProfileRepository.GenerateProfileDisplayIdentifiers(); _profileDisplayIdentifiers = ProfileRepository.GetCurrentDisplayIdentifiers();
} }
return _profileDisplayIdentifiers; return _profileDisplayIdentifiers;
} }
@ -363,7 +363,7 @@ namespace DisplayMagicianShared
// Prepare our profile data for saving // Prepare our profile data for saving
if (_profileDisplayIdentifiers.Count == 0) if (_profileDisplayIdentifiers.Count == 0)
{ {
_profileDisplayIdentifiers = ProfileRepository.GenerateProfileDisplayIdentifiers(); _profileDisplayIdentifiers = ProfileRepository.GetCurrentDisplayIdentifiers();
} }
// Return if it is valid and we should continue // Return if it is valid and we should continue

View File

@ -14,6 +14,7 @@ using System.Text.RegularExpressions;
using NvAPIWrapper.Native.GPU; using NvAPIWrapper.Native.GPU;
using DisplayMagicianShared.AMD; using DisplayMagicianShared.AMD;
using DisplayMagicianShared.NVIDIA; using DisplayMagicianShared.NVIDIA;
using DisplayMagicianShared.Windows;
using System.Windows.Forms; using System.Windows.Forms;
namespace DisplayMagicianShared namespace DisplayMagicianShared
@ -168,7 +169,7 @@ namespace DisplayMagicianShared
{ {
if (_connectedDisplayIdentifiers.Count == 0) if (_connectedDisplayIdentifiers.Count == 0)
// Load the Profiles from storage if they need to be // Load the Profiles from storage if they need to be
_connectedDisplayIdentifiers = GenerateAllAvailableDisplayIdentifiers(); _connectedDisplayIdentifiers = GetAllConnectedDisplayIdentifiers();
return _connectedDisplayIdentifiers; return _connectedDisplayIdentifiers;
@ -574,14 +575,28 @@ namespace DisplayMagicianShared
SharedLogger.logger.Debug($"ProfileRepository/UpdateActiveProfile: Updating the profile currently active (in use now)."); SharedLogger.logger.Debug($"ProfileRepository/UpdateActiveProfile: Updating the profile currently active (in use now).");
SharedLogger.logger.Debug($"ProfileRepository/UpdateActiveProfile: Trying to access things using the AMD video card driver"); SharedLogger.logger.Debug($"ProfileRepository/UpdateActiveProfile: Attempting to access configuration through NVIDIA, then AMD, then Windows CCD interfaces, in that order.");
// If we're using the AMD library if (NVIDIALibrary.GetLibrary().IsInstalled)
AMDLibrary amdLibrary = AMDLibrary.GetLibrary(); {
if (amdLibrary.IsInstalled) SharedLogger.logger.Debug($"ProfileRepository/UpdateActiveProfile: NVIDIA NVAPI Driver is installed, so using that for this display profile.");
{ NVIDIAProfileItem nvidiaProfile = new NVIDIAProfileItem
{
Name = "Current NVIDIA Display Profile",
//ProfileData = amdLibrary.GetActiveProfile(),
//Screens = amdLibrary.GenerateScreenPositions()
//ProfileDisplayIdentifiers = ProfileRepository.GenerateProfileDisplayIdentifiers()
};
//activeProfile.ProfileIcon = new ProfileIcon(activeProfile);
//activeProfile.ProfileBitmap = activeProfile.ProfileIcon.ToBitmap(256, 256);
nvidiaProfile.CreateProfileFromCurrentDisplaySettings();
activeProfile = nvidiaProfile;
}
else if (AMDLibrary.GetLibrary().IsInstalled)
{
SharedLogger.logger.Debug($"ProfileRepository/UpdateActiveProfile: NVIDIA is not installed but the AMD ADL Driver IS installed, so using that for this display profile.");
AMDProfileItem amdProfile = new AMDProfileItem AMDProfileItem amdProfile = new AMDProfileItem
{ {
Name = "Current Display Profile" , Name = "Current AMD Display Profile" ,
//ProfileData = amdLibrary.GetActiveProfile(), //ProfileData = amdLibrary.GetActiveProfile(),
//Screens = amdLibrary.GenerateScreenPositions() //Screens = amdLibrary.GenerateScreenPositions()
//ProfileDisplayIdentifiers = ProfileRepository.GenerateProfileDisplayIdentifiers() //ProfileDisplayIdentifiers = ProfileRepository.GenerateProfileDisplayIdentifiers()
@ -592,16 +607,18 @@ namespace DisplayMagicianShared
activeProfile = amdProfile; activeProfile = amdProfile;
} }
else { else {
SharedLogger.logger.Debug($"ProfileRepository/UpdateActiveProfile: Trying to access things using the NVIDIA video card driver"); SharedLogger.logger.Debug($"ProfileRepository/UpdateActiveProfile: Neither NVIDIA NVAPI or AMD ADL Drivers are installed, so using the built in Windows CCD library interface for this display profile.");
activeProfile = new NVIDIAProfileItem WinProfileItem winProfile = new WinProfileItem
{ {
Name = "Current Display Profile", Name = "Current Windows Display Profile",
Paths = PathInfo.GetActivePaths().Select(info => new DisplayMagicianShared.Topology.Path(info)).ToArray(), //Paths = PathInfo.GetActivePaths().Select(info => new DisplayMagicianShared.Topology.Path(info)).ToArray(),
//ProfileDisplayIdentifiers = ProfileRepository.GenerateProfileDisplayIdentifiers() //ProfileDisplayIdentifiers = ProfileRepository.GenerateProfileDisplayIdentifiers()
}; };
activeProfile.ProfileIcon = new ProfileIcon(activeProfile); //WinProfile.ProfileIcon = new ProfileIcon(activeProfile);
activeProfile.ProfileBitmap = activeProfile.ProfileIcon.ToBitmap(256, 256); //activeProfile.ProfileBitmap = activeProfile.ProfileIcon.ToBitmap(256, 256);
winProfile.CreateProfileFromCurrentDisplaySettings();
activeProfile = winProfile;
} }
@ -826,7 +843,7 @@ namespace DisplayMagicianShared
{ {
// We need to refresh the cached answer // We need to refresh the cached answer
// Get the list of connected devices // Get the list of connected devices
ConnectedDisplayIdentifiers = GenerateAllAvailableDisplayIdentifiers(); ConnectedDisplayIdentifiers = GetAllConnectedDisplayIdentifiers();
if (_profilesLoaded && _allProfiles.Count > 0) if (_profilesLoaded && _allProfiles.Count > 0)
{ {
@ -837,696 +854,41 @@ namespace DisplayMagicianShared
} }
public static List<string> GenerateProfileDisplayIdentifiers() public static List<string> GetAllConnectedDisplayIdentifiers()
{ {
SharedLogger.logger.Debug($"ProfileRepository/GenerateProfileDisplayIdentifiers: Generating the unique Display Identifiers for the currently active profile"); if (NVIDIALibrary.GetLibrary().IsInstalled)
List<string> displayIdentifiers = new List<string>();
bool isNvidia = false;
//bool isAMD = false;
// If the Video Card is an NVidia, then we should generate specific NVidia displayIdentifiers
NvAPIWrapper.GPU.PhysicalGPU[] myPhysicalGPUs = null;
try
{ {
myPhysicalGPUs = NvAPIWrapper.GPU.PhysicalGPU.GetPhysicalGPUs(); return NVIDIALibrary.GetLibrary().GetAllConnectedDisplayIdentifiers();
isNvidia = true;
SharedLogger.logger.Debug($"ProfileRepository/GenerateProfileDisplayIdentifiers: The video card is a NVIDIA video card.");
} }
catch (Exception ex) else if (AMDLibrary.GetLibrary().IsInstalled)
{ {
SharedLogger.logger.Debug(ex, "ProfileRepository/GenerateProfileDisplayIdentifiers: Attemped to get GetPhysicalCPUs through NvAPIWrapper library but got exception. This means the video card isn't compatible with the NvAPIWrapper library we use. It is unlikely to be an NVIDIA video card."); return AMDLibrary.GetLibrary().GetAllConnectedDisplayIdentifiers();
} }
if (isNvidia && myPhysicalGPUs != null && myPhysicalGPUs.Length > 0) else
//if (false)
{ {
SharedLogger.logger.Debug($"ProfileRepository/GenerateProfileDisplayIdentifiers: We were able to GetPhysicalCPUs through NvAPIWrapper library. There are {myPhysicalGPUs.Length} Physical GPUs detected"); return WinLibrary.GetLibrary().GetAllConnectedDisplayIdentifiers();
foreach (NvAPIWrapper.GPU.PhysicalGPU myPhysicalGPU in myPhysicalGPUs)
{
// get a list of all physical outputs attached to the GPUs
NvAPIWrapper.GPU.GPUOutput[] myGPUOutputs = myPhysicalGPU.ActiveOutputs;
foreach (NvAPIWrapper.GPU.GPUOutput aGPUOutput in myGPUOutputs)
{
SharedLogger.logger.Debug($"ProfileRepository/GenerateProfileDisplayIdentifiers: We were able to detect {myGPUOutputs.Length} outputs");
// Figure out the displaydevice attached to the output
NvAPIWrapper.Display.DisplayDevice aConnectedDisplayDevice = myPhysicalGPU.GetDisplayDeviceByOutput(aGPUOutput);
// Create an array of all the important display info we need to record
List<string> displayInfo = new List<string>();
displayInfo.Add("NVIDIA");
try
{
displayInfo.Add(myPhysicalGPU.ArchitectInformation.ShortName.ToString());
}
catch(Exception ex)
{
SharedLogger.logger.Warn(ex,$"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Architecture ShortName from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.ArchitectInformation.Revision.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Architecture Revision from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.Board.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Board details from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.Foundry.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Foundry from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.GPUId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA GPUId from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.GPUType.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA GPUType from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(aConnectedDisplayDevice.ConnectionType.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Connection from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(aConnectedDisplayDevice.DisplayId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA DisplayID 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
displayIdentifiers.Add(displayIdentifier);
SharedLogger.logger.Debug($"ProfileRepository/GenerateProfileDisplayIdentifiers: DisplayIdentifier: {displayIdentifier}");
}
}
} }
// else if there is an AMD video card then we use that mode
else if (AMDLibrary.IsInstalled)
{
//isAMD = true;
SharedLogger.logger.Debug($"ProfileRepository/GenerateProfileDisplayIdentifiers: The video card is an AMD video card.");
// Needs a lot of work here! We need to check if the AMD returned the right stuff, and then use Windows if there is an error.
return AMDLibrary.GenerateProfileDisplayIdentifiers();
}
// else video card is not NVIDIA or AMD so we just use the standard WindowsAPI access method
else
{
// Then go through the adapters we have running using the WindowsDisplayAPI
List<Display> attachedDisplayDevices = Display.GetDisplays().ToList();
SharedLogger.logger.Debug($"ProfileRepository/GenerateProfileDisplayIdentifiers: We are using the standard Windows Display API to figure out what display devices are attached and available. There are {attachedDisplayDevices.Count} display devices detected.");
foreach (Display attachedDisplay in attachedDisplayDevices)
{
DisplayAdapter displayAdapter = null;
PathDisplayAdapter pathDisplayAdapter = null;
PathDisplaySource pathDisplaySource = null;
PathDisplayTarget pathDisplayTarget = null;
try
{
// We keep these lines here to detect if there is an exception so we can report it
// nicely to the user.
displayAdapter = attachedDisplay.Adapter;
pathDisplayAdapter = displayAdapter.ToPathDisplayAdapter();
pathDisplaySource = attachedDisplay.ToPathDisplaySource();
pathDisplayTarget = attachedDisplay.ToPathDisplayTarget();
// This line is just to force an EDID lookup first up so that we can deterine if there is an issue
// with the Monitor, and then tell the user
string EDIDManufacturerId = pathDisplayTarget.EDIDManufactureId.ToString();
// print some trace messages so we can figure out issues if needed later
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADDN : {attachedDisplay.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADDFN : {attachedDisplay.DisplayFullName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADDIN : {attachedDisplay.DisplayName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADDIN : {attachedDisplay.IsAvailable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADDIGP : {attachedDisplay.IsGDIPrimary}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADDIV : {attachedDisplay.IsValid}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSCD : {attachedDisplay.CurrentSetting.ColorDepth}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSF : {attachedDisplay.CurrentSetting.Frequency}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSIE : {attachedDisplay.CurrentSetting.IsEnable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSII : {attachedDisplay.CurrentSetting.IsInterlaced}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSO : {attachedDisplay.CurrentSetting.Orientation}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSOSM : {attachedDisplay.CurrentSetting.OutputScalingMode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSP : {attachedDisplay.CurrentSetting.Position}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSR : {attachedDisplay.CurrentSetting.Resolution}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: DP : {displayAdapter.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: DK : {displayAdapter.DeviceKey}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: DN : {displayAdapter.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: DK : {displayAdapter.DeviceKey}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: AI : {pathDisplayAdapter.AdapterId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: AIDP : {pathDisplayAdapter.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: AIII : {pathDisplayAdapter.IsInvalid}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: DDA : {displayAdapter.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDSA : {pathDisplaySource.Adapter}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDSCDS : {pathDisplaySource.CurrentDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDSDN : {pathDisplaySource.DisplayName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDSMDS : {pathDisplaySource.MaximumDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDSRDS : {pathDisplaySource.RecommendedDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDSSI : {pathDisplaySource.SourceId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTA : {pathDisplayTarget.Adapter}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTCI : {pathDisplayTarget.ConnectorInstance}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTDP : {pathDisplayTarget.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTEMC : {pathDisplayTarget.EDIDManufactureCode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTEMI : {pathDisplayTarget.EDIDManufactureId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTEPC : {pathDisplayTarget.EDIDProductCode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTFN : {pathDisplayTarget.FriendlyName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTIA : {pathDisplayTarget.IsAvailable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTPR : {pathDisplayTarget.PreferredResolution}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTPSM : {pathDisplayTarget.PreferredSignalMode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTTI : {pathDisplayTarget.TargetId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTVRS : {pathDisplayTarget.VirtualResolutionSupport}");
}
catch (WindowsDisplayAPI.Exceptions.InvalidEDIDInformation ex)
{
SharedLogger.logger.Error(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception while trying to get information from your monitor {attachedDisplay.DisplayFullName} about it's configuration. DisplayMagician may not be able to use this monitor!");
if (!notifiedEDIDErrorToUser)
{
MessageBox.Show(
$"Your monitor {attachedDisplay.DisplayFullName} is not responding when we ask about it's configuration. DisplayMagician may not be able to use this monitor!", @"DisplayMagician cannot talk to your monitor",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
notifiedEDIDErrorToUser = true;
}
}
catch (WindowsDisplayAPI.Exceptions.TargetNotAvailableException ex)
{
SharedLogger.logger.Error(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception while we were trying to access the DisplayTarget to gather information about your display configuration.");
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception accessing one of the WindowsDisplayAPI items to print it out during a TRACE session");
}
// 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(displayAdapter.DeviceName.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display Adapter Device name from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayAdapter.AdapterId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display Adapter ID from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.ConnectorInstance.ToString());
}
catch (WindowsDisplayAPI.Exceptions.TargetNotAvailableException ex)
{
SharedLogger.logger.Error(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception2 while we were trying to access the DisplayTarget to gather information about your display configuration.");
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display Target Connector Instance from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.FriendlyName);
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display Target Friendly name from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.EDIDManufactureCode.ToString());
}
catch (WindowsDisplayAPI.Exceptions.InvalidEDIDInformation ex)
{
SharedLogger.logger.Error(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers2: Exception while trying to get information from your monitor {attachedDisplay.DisplayFullName} about it's configuration. DisplayMagician may not be able to use this monitor!");
}
catch (WindowsDisplayAPI.Exceptions.TargetNotAvailableException ex)
{
SharedLogger.logger.Error(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers2: Exception while we were trying to access the DisplayTarget to gather information about your display configuration.");
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers2: Exception getting Windows Display EDID Manufacturer Code from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.EDIDManufactureId.ToString());
}
catch (WindowsDisplayAPI.Exceptions.InvalidEDIDInformation ex)
{
SharedLogger.logger.Error(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers3: Exception while trying to get information from your monitor {attachedDisplay.DisplayFullName} about it's configuration. DisplayMagician may not be able to use this monitor!");
}
catch (WindowsDisplayAPI.Exceptions.TargetNotAvailableException ex)
{
SharedLogger.logger.Error(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers3: Exception while we were trying to access the DisplayTarget to gather information about your display configuration.");
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers3: Exception getting Windows Display EDID Manufacturer ID from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.EDIDProductCode.ToString());
}
catch (WindowsDisplayAPI.Exceptions.InvalidEDIDInformation ex)
{
SharedLogger.logger.Error(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers4: Exception while trying to get information from your monitor {attachedDisplay.DisplayFullName} about it's configuration. DisplayMagician may not be able to use this monitor!");
}
catch (WindowsDisplayAPI.Exceptions.TargetNotAvailableException ex)
{
SharedLogger.logger.Error(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers4: Exception while we were trying to access the DisplayTarget to gather information about your display configuration.");
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers4: Exception getting Windows Display EDID Product Code from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.TargetId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display Target ID 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
displayIdentifiers.Add(displayIdentifier);
SharedLogger.logger.Debug($"ProfileRepository/GenerateProfileDisplayIdentifiers: DisplayIdentifier: {displayIdentifier}");
}
}
// Sort the display identifiers
displayIdentifiers.Sort();
return displayIdentifiers;
} }
public static List<string> GenerateAllAvailableDisplayIdentifiers() public static List<string> GetCurrentDisplayIdentifiers()
{ {
SharedLogger.logger.Debug($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: Generating all the Display Identifiers currently active now"); if (NVIDIALibrary.GetLibrary().IsInstalled)
List<string> displayIdentifiers = new List<string>();
// If the Video Card is an NVidia, then we should generate specific NVidia displayIdentifiers
bool isNvidia = false;
NvAPIWrapper.GPU.PhysicalGPU[] myPhysicalGPUs = null;
try
{ {
myPhysicalGPUs = NvAPIWrapper.GPU.PhysicalGPU.GetPhysicalGPUs(); return NVIDIALibrary.GetLibrary().GetCurrentDisplayIdentifiers();
isNvidia = true;
SharedLogger.logger.Debug($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: The video card is a NVIDIA video card.");
} }
catch (Exception ex) else if (AMDLibrary.GetLibrary().IsInstalled)
{ {
SharedLogger.logger.Debug(ex, "ProfileRepository/GenerateAllAvailableDisplayIdentifiers: Attemped to get GetPhysicalCPUs through NvAPIWrapper library but got exception. This means the video card isn't compatible with the NvAPIWrapper library we use. It is unlikely to be an NVIDIA video card."); return AMDLibrary.GetLibrary().GetCurrentDisplayIdentifiers();
} }
// If the Video Card is an AMD, then we should generate specific AMD displayIdentifiers
AMD.AMDLibrary thingy = new AMD.AMDLibrary();
if (isNvidia && myPhysicalGPUs != null && myPhysicalGPUs.Length > 0)
//if (false)
{
SharedLogger.logger.Debug($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: We were able to GetPhysicalCPUs through NvAPIWrapper library. There are {myPhysicalGPUs.Length} Physical GPUs detected");
foreach (NvAPIWrapper.GPU.PhysicalGPU myPhysicalGPU in myPhysicalGPUs)
{
// get a list of all physical outputs attached to the GPUs
NvAPIWrapper.Display.DisplayDevice[] allDisplayDevices = myPhysicalGPU.GetConnectedDisplayDevices(ConnectedIdsFlag.None);
SharedLogger.logger.Debug($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: We were able to detect {allDisplayDevices.Length} connected devices");
foreach (NvAPIWrapper.Display.DisplayDevice aDisplayDevice in allDisplayDevices)
{
if (aDisplayDevice.IsAvailable== true)
{
// Create an array of all the important display info we need to record
List<string> displayInfo = new List<string>();
displayInfo.Add("NVIDIA");
try
{
displayInfo.Add(myPhysicalGPU.ArchitectInformation.ShortName.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Architecture ShortName from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.ArchitectInformation.Revision.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Architecture Revision from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.Board.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Board details from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.Foundry.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Foundry from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.GPUId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA GPUId from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.GPUType.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA GPUType from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(aDisplayDevice.ConnectionType.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Connection from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(aDisplayDevice.DisplayId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA DisplayID 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
displayIdentifiers.Add(displayIdentifier);
SharedLogger.logger.Debug($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DisplayIdentifier: {displayIdentifier}");
}
}
}
}
// else if there is an AMD video card then we use that mode
else if (AMDLibrary.IsInstalled)
{
//isAMD = true;
SharedLogger.logger.Debug($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: The video card is an AMD video card.");
// Needs a lot of work here! We need to check if the AMD returned the right stuff, and then use Windows if there is an error.
return AMDLibrary.GenerateAllAvailableDisplayIdentifiers();
}
// else video card is not NVIDIA or AMD so we just use the standard WindowsAPI access method
else else
{ {
return WinLibrary.GetLibrary().GetCurrentDisplayIdentifiers();
// Then go through the adapters we have running using the WindowsDisplayAPI
List<Display> attachedDisplayDevices = Display.GetDisplays().ToList();
List<UnAttachedDisplay> unattachedDisplayDevices = UnAttachedDisplay.GetUnAttachedDisplays().ToList();
SharedLogger.logger.Debug($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: We are using the standard Windows Display API to figure out what display devices are attached and available. There are {attachedDisplayDevices.Count} display devices attached and {unattachedDisplayDevices.Count} devices unattached.");
foreach (Display attachedDisplay in attachedDisplayDevices)
{
DisplayAdapter displayAdapter = attachedDisplay.Adapter;
PathDisplayAdapter pathDisplayAdapter = displayAdapter.ToPathDisplayAdapter();
PathDisplaySource pathDisplaySource = attachedDisplay.ToPathDisplaySource();
PathDisplayTarget pathDisplayTarget = attachedDisplay.ToPathDisplayTarget();
try
{
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDN : {attachedDisplay.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDFN : {attachedDisplay.DisplayFullName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDIN : {attachedDisplay.DisplayName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDIN : {attachedDisplay.IsAvailable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDIGP : {attachedDisplay.IsGDIPrimary}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDIV : {attachedDisplay.IsValid}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSCD : {attachedDisplay.CurrentSetting.ColorDepth}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSF : {attachedDisplay.CurrentSetting.Frequency}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSIE : {attachedDisplay.CurrentSetting.IsEnable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSII : {attachedDisplay.CurrentSetting.IsInterlaced}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSO : {attachedDisplay.CurrentSetting.Orientation}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSOSM : {attachedDisplay.CurrentSetting.OutputScalingMode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSP : {attachedDisplay.CurrentSetting.Position}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSR : {attachedDisplay.CurrentSetting.Resolution}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DP : {displayAdapter.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DK : {displayAdapter.DeviceKey}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DN : {displayAdapter.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DK : {displayAdapter.DeviceKey}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: AI : {pathDisplayAdapter.AdapterId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: AIDP : {pathDisplayAdapter.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: AIII : {pathDisplayAdapter.IsInvalid}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DDA : {displayAdapter.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSA : {pathDisplaySource.Adapter}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSCDS : {pathDisplaySource.CurrentDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSDN : {pathDisplaySource.DisplayName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSMDS : {pathDisplaySource.MaximumDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSRDS : {pathDisplaySource.RecommendedDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSSI : {pathDisplaySource.SourceId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTA : {pathDisplayTarget.Adapter}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTCI : {pathDisplayTarget.ConnectorInstance}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTDP : {pathDisplayTarget.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTEMC : {pathDisplayTarget.EDIDManufactureCode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTEMI : {pathDisplayTarget.EDIDManufactureId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTEPC : {pathDisplayTarget.EDIDProductCode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTFN : {pathDisplayTarget.FriendlyName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTIA : {pathDisplayTarget.IsAvailable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTPR : {pathDisplayTarget.PreferredResolution}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTPSM : {pathDisplayTarget.PreferredSignalMode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTTI : {pathDisplayTarget.TargetId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTVRS : {pathDisplayTarget.VirtualResolutionSupport}");
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: Exception accessing one of the WindowsDisplayAPI items to print it out during a TRACE session");
}
// 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(displayAdapter.DeviceName.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: Exception getting Windows Display Adapter Device name from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayAdapter.AdapterId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: Exception getting Windows Display Adapter ID from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.ConnectorInstance.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: Exception getting Windows Display Target Connector Instance from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.FriendlyName);
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: Exception getting Windows Display Target Friendly name from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.EDIDManufactureCode.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: Exception getting Windows Display EDID Manufacturer Code from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.EDIDManufactureId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: Exception getting Windows Display EDID Manufacturer ID from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.EDIDProductCode.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: Exception getting Windows Display EDID Product Code from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.TargetId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: Exception getting Windows Display Target ID 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
displayIdentifiers.Add(displayIdentifier);
SharedLogger.logger.Debug($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: Attached DisplayIdentifier: {displayIdentifier}");
}
foreach (UnAttachedDisplay unattachedDisplay in unattachedDisplayDevices)
{
DisplayAdapter displayAdapter = unattachedDisplay.Adapter;
PathDisplayAdapter pathDisplayAdapter = displayAdapter.ToPathDisplayAdapter();
PathDisplaySource pathDisplaySource = unattachedDisplay.ToPathDisplaySource();
PathDisplayTarget pathDisplayTarget = unattachedDisplay.ToPathDisplayTarget();
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDN : {unattachedDisplay.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDFN : {unattachedDisplay.DisplayFullName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDIN : {unattachedDisplay.DisplayName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDIN : {unattachedDisplay.IsAvailable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDIV : {unattachedDisplay.IsValid}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DP : {displayAdapter.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DK : {displayAdapter.DeviceKey}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DN : {displayAdapter.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DK : {displayAdapter.DeviceKey}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: AI : {pathDisplayAdapter.AdapterId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: AIDP : {pathDisplayAdapter.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: AIII : {pathDisplayAdapter.IsInvalid}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSA : {pathDisplaySource.Adapter}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSCDS : {pathDisplaySource.CurrentDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSDN : {pathDisplaySource.DisplayName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSMDS : {pathDisplaySource.MaximumDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSRDS : {pathDisplaySource.RecommendedDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSSI : {pathDisplaySource.SourceId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTA : {pathDisplayTarget.Adapter}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTCI : {pathDisplayTarget.ConnectorInstance}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTDP : {pathDisplayTarget.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTEMC : {pathDisplayTarget.EDIDManufactureCode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTEMI : {pathDisplayTarget.EDIDManufactureId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTEPC : {pathDisplayTarget.EDIDProductCode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTFN : {pathDisplayTarget.FriendlyName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTIA : {pathDisplayTarget.IsAvailable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTPR : {pathDisplayTarget.PreferredResolution}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTPSM : {pathDisplayTarget.PreferredSignalMode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTTI : {pathDisplayTarget.TargetId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTVRS : {pathDisplayTarget.VirtualResolutionSupport}");
// Create an array of all the important display info we need to record
string[] displayInfo = {
"WINAPI",
displayAdapter.DeviceName.ToString(),
pathDisplayAdapter.AdapterId.ToString(),
pathDisplayTarget.ConnectorInstance.ToString(),
pathDisplayTarget.FriendlyName,
pathDisplayTarget.EDIDManufactureCode.ToString(),
pathDisplayTarget.EDIDManufactureId.ToString(),
pathDisplayTarget.EDIDProductCode.ToString(),
pathDisplayTarget.TargetId.ToString(),
};
// 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
displayIdentifiers.Add(displayIdentifier);
SharedLogger.logger.Debug($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: Unattached DisplayIdentifier: {displayIdentifier}");
}
} }
// Sort the display identifiers
displayIdentifiers.Sort();
return displayIdentifiers;
} }
public static bool ApplyNVIDIAGridTopology(NVIDIAProfileItem profile)
/* public static bool ApplyNVIDIAGridTopology(NVIDIAProfileItem profile)
{ {
SharedLogger.logger.Debug($"ProfileRepository/ApplyNVIDIAGridTopology: Attempting to apply NVIDIA Grid Topology"); SharedLogger.logger.Debug($"ProfileRepository/ApplyNVIDIAGridTopology: Attempting to apply NVIDIA Grid Topology");
@ -1595,7 +957,7 @@ namespace DisplayMagicianShared
return false; return false;
} }
} }*/
public static bool IsValidFilename(string testName) public static bool IsValidFilename(string testName)
{ {

View File

@ -7,7 +7,8 @@ using System.Threading.Tasks;
namespace DisplayMagicianShared.Windows namespace DisplayMagicianShared.Windows
{ {
public enum WIN32STATUS
public enum WIN32STATUS : uint
{ {
ERROR_SUCCESS = 0, ERROR_SUCCESS = 0,
ERROR_ACCESS_DENIED = 5, ERROR_ACCESS_DENIED = 5,
@ -15,10 +16,12 @@ namespace DisplayMagicianShared.Windows
ERROR_GEN_FAILURE = 31, ERROR_GEN_FAILURE = 31,
ERROR_INVALID_PARAMETER = 87, ERROR_INVALID_PARAMETER = 87,
ERROR_INSUFFICIENT_BUFFER = 122, ERROR_INSUFFICIENT_BUFFER = 122,
ERROR_BAD_CONFIGURATION = 1610,
} }
public enum DISPLAYCONFIG_DEVICE_INFO_TYPE public enum DISPLAYCONFIG_DEVICE_INFO_TYPE : uint
{ {
Zero = 0,
DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1, DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2, DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3, DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3,
@ -32,7 +35,8 @@ namespace DisplayMagicianShared.Windows
DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL = 11, DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL = 11,
} }
public enum DISPLAYCONFIG_COLOR_ENCODING [Flags]
public enum DISPLAYCONFIG_COLOR_ENCODING : uint
{ {
DISPLAYCONFIG_COLOR_ENCODING_RGB = 0, DISPLAYCONFIG_COLOR_ENCODING_RGB = 0,
DISPLAYCONFIG_COLOR_ENCODING_YCBCR444 = 1, DISPLAYCONFIG_COLOR_ENCODING_YCBCR444 = 1,
@ -41,26 +45,34 @@ namespace DisplayMagicianShared.Windows
DISPLAYCONFIG_COLOR_ENCODING_INTENSITY = 4, DISPLAYCONFIG_COLOR_ENCODING_INTENSITY = 4,
} }
public enum DISPLAYCONFIG_SCALING [Flags]
public enum DISPLAYCONFIG_SCALING : uint
{ {
Zero = 0,
DISPLAYCONFIG_SCALING_IDENTITY = 1, DISPLAYCONFIG_SCALING_IDENTITY = 1,
DISPLAYCONFIG_SCALING_CENTERED = 2, DISPLAYCONFIG_SCALING_CENTERED = 2,
DISPLAYCONFIG_SCALING_STRETCHED = 3, DISPLAYCONFIG_SCALING_STRETCHED = 3,
DISPLAYCONFIG_SCALING_ASPECTRATIOCENTEREDMAX = 4, DISPLAYCONFIG_SCALING_ASPECTRATIOCENTEREDMAX = 4,
DISPLAYCONFIG_SCALING_CUSTOM = 5, DISPLAYCONFIG_SCALING_CUSTOM = 5,
DISPLAYCONFIG_SCALING_PREFERRED = 128, DISPLAYCONFIG_SCALING_PREFERRED = 128,
DISPLAYCONFIG_SCALING_FORCEUINT32 = 0xFFFFFFFF,
} }
public enum DISPLAYCONFIG_ROTATION [Flags]
public enum DISPLAYCONFIG_ROTATION : uint
{ {
Zero = 0,
DISPLAYCONFIG_ROTATION_IDENTITY = 1, DISPLAYCONFIG_ROTATION_IDENTITY = 1,
DISPLAYCONFIG_ROTATION_ROTATE90 = 2, DISPLAYCONFIG_ROTATION_ROTATE90 = 2,
DISPLAYCONFIG_ROTATION_ROTATE180 = 3, DISPLAYCONFIG_ROTATION_ROTATE180 = 3,
DISPLAYCONFIG_ROTATION_ROTATE270 = 4,
DISPLAYCONFIG_ROTATION_FORCEUINT32 = 0xFFFFFFFF,
} }
public enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY [Flags]
public enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY : uint
{ {
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER = -1, DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER = 4294967295, // - 1
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15 = 0, DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15 = 0,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SVIDEO = 1, DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SVIDEO = 1,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPOSITE_VIDEO = 2, DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPOSITE_VIDEO = 2,
@ -78,31 +90,41 @@ namespace DisplayMagicianShared.Windows
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_MIRACAST = 15, DISPLAYCONFIG_OUTPUT_TECHNOLOGY_MIRACAST = 15,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_WIRED = 16, DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_WIRED = 16,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_VIRTUAL = 17, DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_VIRTUAL = 17,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL = unchecked((int)0x80000000), DISPLAYCONFIG_OUTPUT_TECHNOLOGY_public = 0x80000000,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_FORCEUINT32 = 0xFFFFFFFF,
} }
public enum DISPLAYCONFIG_TOPOLOGY_ID [Flags]
public enum DISPLAYCONFIG_TOPOLOGY_ID : uint
{ {
DISPLAYCONFIG_TOPOLOGY_INTERNAL = 0x00000001, Zero = 0x0,
DISPLAYCONFIG_TOPOLOGY_public = 0x00000001,
DISPLAYCONFIG_TOPOLOGY_CLONE = 0x00000002, DISPLAYCONFIG_TOPOLOGY_CLONE = 0x00000002,
DISPLAYCONFIG_TOPOLOGY_EXTEND = 0x00000004, DISPLAYCONFIG_TOPOLOGY_EXTEND = 0x00000004,
DISPLAYCONFIG_TOPOLOGY_EXTERNAL = 0x00000008, DISPLAYCONFIG_TOPOLOGY_EXTERNAL = 0x00000008,
DISPLAYCONFIG_TOPOLOGY_FORCEUINT32 = 0xFFFFFFFF,
} }
public enum DISPLAYCONFIG_PATH [Flags]
public enum DISPLAYCONFIG_PATH : uint
{ {
Zero = 0x0,
DISPLAYCONFIG_PATH_ACTIVE = 0x00000001, DISPLAYCONFIG_PATH_ACTIVE = 0x00000001,
DISPLAYCONFIG_PATH_PREFERRED_UNSCALED = 0x00000004, DISPLAYCONFIG_PATH_PREFERRED_UNSCALED = 0x00000004,
DISPLAYCONFIG_PATH_SUPPORT_VIRTUAL_MODE = 0x00000008, DISPLAYCONFIG_PATH_SUPPORT_VIRTUAL_MODE = 0x00000008,
} }
public enum DISPLAYCONFIG_SOURCE_FLAGS [Flags]
public enum DISPLAYCONFIG_SOURCE_FLAGS : uint
{ {
Zero = 0x0,
DISPLAYCONFIG_SOURCE_IN_USE = 0x00000001, DISPLAYCONFIG_SOURCE_IN_USE = 0x00000001,
} }
public enum DISPLAYCONFIG_TARGET_FLAGS [Flags]
public enum DISPLAYCONFIG_TARGET_FLAGS : uint
{ {
Zero = 0x0,
DISPLAYCONFIG_TARGET_IN_USE = 0x00000001, DISPLAYCONFIG_TARGET_IN_USE = 0x00000001,
DISPLAYCONFIG_TARGET_FORCIBLE = 0x00000002, DISPLAYCONFIG_TARGET_FORCIBLE = 0x00000002,
DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_BOOT = 0x00000004, DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_BOOT = 0x00000004,
@ -111,52 +133,139 @@ namespace DisplayMagicianShared.Windows
DISPLAYCONFIG_TARGET_IS_HMD = 0x00000020, DISPLAYCONFIG_TARGET_IS_HMD = 0x00000020,
} }
public enum QDC [Flags]
public enum QDC : uint
{ {
Zero = 0x0,
QDC_ALL_PATHS = 0x00000001, // Get all paths QDC_ALL_PATHS = 0x00000001, // Get all paths
QDC_ONLY_ACTIVE_PATHS = 0x00000002, // Get only the active paths currently in use QDC_ONLY_ACTIVE_PATHS = 0x00000002, // Get only the active paths currently in use
QDC_DATABASE_CURRENT = 0x00000004, // Get the current paths in the display database QDC_DATABASE_CURRENT = 0x00000004, // Get the currently active paths as stored in the display database
QDC_VIRTUAL_MODE_AWARE = 0x00000010, // Get the virtual mode aware paths QDC_VIRTUAL_MODE_AWARE = 0x00000010, // Get the virtual mode aware paths
QDC_INCLUDE_HMD = 0x00000020, QDC_INCLUDE_HMD = 0x00000020,
} }
public enum DISPLAYCONFIG_SCANLINE_ORDERING [Flags]
public enum SDC : uint
{
Zero = 0x0,
SDC_TOPOLOGY_public = 0x00000001,
SDC_TOPOLOGY_CLONE = 0x00000002,
SDC_TOPOLOGY_EXTEND = 0x00000004,
SDC_TOPOLOGY_EXTERNAL = 0x00000008,
SDC_TOPOLOGY_SUPPLIED = 0x00000010,
SDC_USE_DATABASE_CURRENT = (SDC_TOPOLOGY_public | SDC_TOPOLOGY_CLONE | SDC_TOPOLOGY_EXTEND | SDC_TOPOLOGY_EXTERNAL),
SDC_USE_SUPPLIED_DISPLAY_CONFIG = 0x00000020,
SDC_VALIDATE = 0x00000040,
SDC_APPLY = 0x00000080,
SDC_NO_OPTIMIZATION = 0x00000100,
SDC_SAVE_TO_DATABASE = 0x00000200,
SDC_ALLOW_CHANGES = 0x00000400,
SDC_PATH_PERSIST_IF_REQUIRED = 0x00000800,
SDC_FORCE_MODE_ENUMERATION = 0x00001000,
SDC_ALLOW_PATH_ORDER_CHANGES = 0x00002000,
SDC_VIRTUAL_MODE_AWARE = 0x00008000,
// Special common combinations (only set in this library)
TEST_IF_VALID_DISPLAYCONFIG = (SDC_VALIDATE | SDC_USE_SUPPLIED_DISPLAY_CONFIG),
TEST_IF_VALID_DISPLAYCONFIG_WITH_TWEAKS = (SDC_VALIDATE | SDC_USE_SUPPLIED_DISPLAY_CONFIG | SDC_ALLOW_CHANGES),
SET_DISPLAYCONFIG_AND_SAVE = (SDC_APPLY | SDC_USE_SUPPLIED_DISPLAY_CONFIG | SDC_SAVE_TO_DATABASE),
SET_DISPLAYCONFIG_WITH_TWEAKS_AND_SAVE = (SDC_APPLY | SDC_USE_SUPPLIED_DISPLAY_CONFIG | SDC_ALLOW_CHANGES | SDC_SAVE_TO_DATABASE),
DISPLAYMAGICIAN_SET = (SDC_APPLY | SDC_USE_SUPPLIED_DISPLAY_CONFIG | SDC_ALLOW_CHANGES | SDC_SAVE_TO_DATABASE),
DISPLAYMAGICIAN_VALIDATE = (SDC_VALIDATE | SDC_USE_SUPPLIED_DISPLAY_CONFIG | SDC_ALLOW_CHANGES | SDC_SAVE_TO_DATABASE),
//DISPLAYMAGICIAN_SET = (SDC_APPLY | SDC_TOPOLOGY_SUPPLIED | SDC_ALLOW_CHANGES | SDC_ALLOW_PATH_ORDER_CHANGES ),
//DISPLAYMAGICIAN_VALIDATE = (SDC_VALIDATE | SDC_TOPOLOGY_SUPPLIED | SDC_ALLOW_CHANGES | SDC_ALLOW_PATH_ORDER_CHANGES ),
SET_DISPLAYCONFIG_BUT_NOT_SAVE = (SDC_APPLY | SDC_USE_SUPPLIED_DISPLAY_CONFIG),
TEST_IF_CLONE_VALID = (SDC_VALIDATE | SDC_TOPOLOGY_CLONE),
SET_CLONE_TOPOLOGY = (SDC_APPLY | SDC_TOPOLOGY_CLONE),
SET_CLONE_TOPOLOGY_WITH_PATH_PERSISTENCE = (SDC_APPLY | SDC_TOPOLOGY_CLONE | SDC_PATH_PERSIST_IF_REQUIRED),
RESET_DISPLAYCONFIG_TO_LAST_SAVED = (SDC_APPLY | SDC_USE_DATABASE_CURRENT),
SET_DISPLAYCONFIG_USING_PATHS_ONLY_AND_SAVE = (SDC_APPLY | SDC_TOPOLOGY_SUPPLIED | SDC_ALLOW_PATH_ORDER_CHANGES),
}
[Flags]
public enum DISPLAYCONFIG_SCANLINE_ORDERING : uint
{ {
DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0, DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0,
DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1, DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1,
DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED = 2, DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED = 2,
DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_UPPERFIELDFIRST = DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED, DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_UPPERFIELDFIRST = DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED,
DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_LOWERFIELDFIRST = 3, DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_LOWERFIELDFIRST = 3,
DISPLAYCONFIG_SCANLINE_ORDERING_FORCEUINT32 = 0xFFFFFFFF,
} }
public enum DISPLAYCONFIG_PIXELFORMAT [Flags]
public enum DISPLAYCONFIG_PIXELFORMAT : uint
{ {
Zero = 0x0,
DISPLAYCONFIG_PIXELFORMAT_8BPP = 1, DISPLAYCONFIG_PIXELFORMAT_8BPP = 1,
DISPLAYCONFIG_PIXELFORMAT_16BPP = 2, DISPLAYCONFIG_PIXELFORMAT_16BPP = 2,
DISPLAYCONFIG_PIXELFORMAT_24BPP = 3, DISPLAYCONFIG_PIXELFORMAT_24BPP = 3,
DISPLAYCONFIG_PIXELFORMAT_32BPP = 4, DISPLAYCONFIG_PIXELFORMAT_32BPP = 4,
DISPLAYCONFIG_PIXELFORMAT_NONGDI = 5, DISPLAYCONFIG_PIXELFORMAT_NONGDI = 5,
DISPLAYCONFIG_PIXELFORMAT_FORCEUINT32 = 0xFFFFFFFF,
} }
public enum DISPLAYCONFIG_MODE_INFO_TYPE [Flags]
public enum DISPLAYCONFIG_MODE_INFO_TYPE : uint
{ {
Zero = 0x0,
DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1, DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1,
DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2, DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2,
DISPLAYCONFIG_MODE_INFO_TYPE_DESKTOP_IMAGE = 3, DISPLAYCONFIG_MODE_INFO_TYPE_DESKTOP_IMAGE = 3,
DISPLAYCONFIG_MODE_INFO_TYPE_FORCEUINT32 = 0xFFFFFFFF,
}
[Flags]
public enum D3D_VIDEO_SIGNAL_STANDARD : uint
{
Uninitialized = 0,
VesaDmt = 1,
VesaGtf = 2,
VesaCvt = 3,
Ibm = 4,
Apple = 5,
NtscM = 6,
NtscJ = 7,
Ntsc443 = 8,
PalB = 9,
PalB1 = 10,
PalG = 11,
PalH = 12,
PalI = 13,
PalD = 14,
PalN = 15,
PalNc = 16,
SecamB = 17,
SecamD = 18,
SecamG = 19,
SecamH = 20,
SecamK = 21,
SecamK1 = 22,
SecamL = 23,
SecamL1 = 24,
Eia861 = 25,
Eia861A = 26,
Eia861B = 27,
PalK = 28,
PalK1 = 29,
PalL = 30,
PalM = 31,
Other = 255
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_DEVICE_INFO_HEADER : IEquatable<DISPLAYCONFIG_DEVICE_INFO_HEADER> public struct DISPLAYCONFIG_DEVICE_INFO_HEADER : IEquatable<DISPLAYCONFIG_DEVICE_INFO_HEADER>
{ {
public DISPLAYCONFIG_DEVICE_INFO_TYPE Type; public DISPLAYCONFIG_DEVICE_INFO_TYPE Type;
public int Size; public uint Size;
public LUID AdapterId; public LUID AdapterId;
public uint Id; public uint Id;
public bool Equals(DISPLAYCONFIG_DEVICE_INFO_HEADER other) public bool Equals(DISPLAYCONFIG_DEVICE_INFO_HEADER other)
=> Type == other.Type && => Type == other.Type &&
Size == other.Size && Size == other.Size &&
AdapterId.Equals(other.AdapterId) && // AdapterId.Equals(other.AdapterId) && // Removed the AdapterId from the Equals, as it changes after reboot.
Id == other.Id; Id == other.Id;
public override int GetHashCode() public override int GetHashCode()
@ -171,9 +280,11 @@ namespace DisplayMagicianShared.Windows
public struct DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO : IEquatable<DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO> public struct DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO : IEquatable<DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO>
{ {
public DISPLAYCONFIG_DEVICE_INFO_HEADER Header; public DISPLAYCONFIG_DEVICE_INFO_HEADER Header;
//[MarshalAs(UnmanagedType.U4)]
public uint Value; public uint Value;
public DISPLAYCONFIG_COLOR_ENCODING ColorEncoding; public DISPLAYCONFIG_COLOR_ENCODING ColorEncoding;
public int BitsPerColorChannel; //[MarshalAs(UnmanagedType.U4)]
public uint BitsPerColorChannel;
public bool AdvancedColorSupported => (Value & 0x1) == 0x1; public bool AdvancedColorSupported => (Value & 0x1) == 0x1;
public bool AdvancedColorEnabled => (Value & 0x2) == 0x2; public bool AdvancedColorEnabled => (Value & 0x2) == 0x2;
@ -216,16 +327,17 @@ namespace DisplayMagicianShared.Windows
public struct LUID : IEquatable<LUID> public struct LUID : IEquatable<LUID>
{ {
public uint LowPart; public uint LowPart;
public int HighPart; public uint HighPart;
public long Value => ((long)HighPart << 32) | LowPart; public ulong Value => ((ulong)HighPart << 32) | LowPart;
public bool Equals(LUID other) public bool Equals(LUID other)
=> Value == other.Value; => LowPart == other.LowPart &&
HighPart == other.HighPart;
public override int GetHashCode() public override int GetHashCode()
{ {
return Value.GetHashCode(); return (LowPart, HighPart).GetHashCode();
} }
public override string ToString() => Value.ToString(); public override string ToString() => Value.ToString();
@ -292,8 +404,8 @@ namespace DisplayMagicianShared.Windows
public struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO : IEquatable<DISPLAYCONFIG_DESKTOP_IMAGE_INFO> public struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO : IEquatable<DISPLAYCONFIG_DESKTOP_IMAGE_INFO>
{ {
public POINTL PathSourceSize; public POINTL PathSourceSize;
public RECT DesktopImageRegion; public RECTL DesktopImageRegion;
public RECT DesktopImageClip; public RECTL DesktopImageClip;
public bool Equals(DISPLAYCONFIG_DESKTOP_IMAGE_INFO other) public bool Equals(DISPLAYCONFIG_DESKTOP_IMAGE_INFO other)
=> PathSourceSize.Equals(other.PathSourceSize) && => PathSourceSize.Equals(other.PathSourceSize) &&
@ -316,7 +428,7 @@ namespace DisplayMagicianShared.Windows
public DISPLAYCONFIG_RATIONAL VSyncFreq; public DISPLAYCONFIG_RATIONAL VSyncFreq;
public DISPLAYCONFIG_2DREGION ActiveSize; public DISPLAYCONFIG_2DREGION ActiveSize;
public DISPLAYCONFIG_2DREGION TotalSize; public DISPLAYCONFIG_2DREGION TotalSize;
public uint VideoStandard; public D3D_VIDEO_SIGNAL_STANDARD VideoStandard;
public DISPLAYCONFIG_SCANLINE_ORDERING ScanLineOrdering; public DISPLAYCONFIG_SCANLINE_ORDERING ScanLineOrdering;
public bool Equals(DISPLAYCONFIG_VIDEO_SIGNAL_INFO other) public bool Equals(DISPLAYCONFIG_VIDEO_SIGNAL_INFO other)
@ -353,47 +465,31 @@ namespace DisplayMagicianShared.Windows
} }
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct DISPLAYCONFIG_MODE_INFO_union : IEquatable<DISPLAYCONFIG_MODE_INFO_union>
{
[FieldOffset(0)]
public DISPLAYCONFIG_TARGET_MODE TargetMode;
[FieldOffset(0)]
public DISPLAYCONFIG_SOURCE_MODE SourceMode;
[FieldOffset(0)]
public DISPLAYCONFIG_DESKTOP_IMAGE_INFO DesktopImageInfo;
public bool Equals(DISPLAYCONFIG_MODE_INFO_union other)
=> TargetMode.Equals(other.TargetMode) &&
SourceMode.Equals(other.SourceMode) &&
DesktopImageInfo.Equals(other.DesktopImageInfo);
public override int GetHashCode()
{
return (TargetMode, SourceMode, DesktopImageInfo).GetHashCode();
}
//public override string ToString() => $"{type.ToString("G")}";
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_PATH_SOURCE_INFO : IEquatable<DISPLAYCONFIG_PATH_SOURCE_INFO> public struct DISPLAYCONFIG_PATH_SOURCE_INFO : IEquatable<DISPLAYCONFIG_PATH_SOURCE_INFO>
{ {
[FieldOffset(0)]
public LUID AdapterId; public LUID AdapterId;
[FieldOffset(8)]
public uint Id; public uint Id;
[FieldOffset(12)]
public uint ModeInfoIdx; public uint ModeInfoIdx;
[FieldOffset(12)]
public ushort cloneGroupId;
[FieldOffset(14)]
public ushort sourceModeInfoIdx;
[FieldOffset(16)]
public DISPLAYCONFIG_SOURCE_FLAGS StatusFlags; public DISPLAYCONFIG_SOURCE_FLAGS StatusFlags;
public bool Equals(DISPLAYCONFIG_PATH_SOURCE_INFO other) public bool Equals(DISPLAYCONFIG_PATH_SOURCE_INFO other)
=> AdapterId.Equals(other.AdapterId) && => // AdapterId.Equals(other.AdapterId) && // Removed the AdapterId from the Equals, as it changes after a reboot.
Id == other.Id && Id == other.Id &&
ModeInfoIdx == other.ModeInfoIdx && ModeInfoIdx == other.ModeInfoIdx &&
StatusFlags.Equals(other.StatusFlags); StatusFlags.Equals(other.StatusFlags);
public override int GetHashCode() public override int GetHashCode()
{ {
return (AdapterId, ModeInfoIdx, StatusFlags).GetHashCode(); //return (AdapterId, Id, ModeInfoIdx, StatusFlags).GetHashCode();
return (ModeInfoIdx, Id, StatusFlags).GetHashCode();
} }
//public override string ToString() => $"{type.ToString("G")}"; //public override string ToString() => $"{type.ToString("G")}";
@ -411,10 +507,25 @@ namespace DisplayMagicianShared.Windows
public DISPLAYCONFIG_RATIONAL RefreshRate; public DISPLAYCONFIG_RATIONAL RefreshRate;
public DISPLAYCONFIG_SCANLINE_ORDERING ScanLineOrdering; public DISPLAYCONFIG_SCANLINE_ORDERING ScanLineOrdering;
public bool TargetAvailable; public bool TargetAvailable;
public DISPLAYCONFIG_TARGET_FLAGS StatusFlags; public uint StatusFlags;
public bool TargetInUse => (StatusFlags & 0x1) == 0x1;
public bool TargetForcible => (StatusFlags & 0x2) == 0x2;
public bool ForcedAvailabilityBoot => (StatusFlags & 0x4) == 0x4;
public bool ForcedAvailabilityPath => (StatusFlags & 0x8) == 0x8;
public bool ForcedAvailabilitySystem => (StatusFlags & 0x10) == 0x10;
public bool IsHMD => (StatusFlags & 0x20) == 0x20;
/* DISPLAYCONFIG_TARGET_IN_USE = 0x00000001,
DISPLAYCONFIG_TARGET_FORCIBLE = 0x00000002,
DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_BOOT = 0x00000004,
DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_PATH = 0x00000008,
DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_SYSTEM = 0x00000010,
DISPLAYCONFIG_TARGET_IS_HMD = 0x00000020,*/
public bool Equals(DISPLAYCONFIG_PATH_TARGET_INFO other) public bool Equals(DISPLAYCONFIG_PATH_TARGET_INFO other)
=> AdapterId.Equals(other.AdapterId) && => // AdapterId.Equals(other.AdapterId) && // Removed the AdapterId from the Equals, as it changes after reboot.
Id == other.Id && Id == other.Id &&
ModeInfoIdx == other.ModeInfoIdx && ModeInfoIdx == other.ModeInfoIdx &&
OutputTechnology.Equals(other.OutputTechnology) && OutputTechnology.Equals(other.OutputTechnology) &&
@ -438,7 +549,7 @@ namespace DisplayMagicianShared.Windows
{ {
public DISPLAYCONFIG_PATH_SOURCE_INFO SourceInfo; public DISPLAYCONFIG_PATH_SOURCE_INFO SourceInfo;
public DISPLAYCONFIG_PATH_TARGET_INFO TargetInfo; public DISPLAYCONFIG_PATH_TARGET_INFO TargetInfo;
public DISPLAYCONFIG_PATH Flags; public uint Flags;
public bool Equals(DISPLAYCONFIG_PATH_INFO other) public bool Equals(DISPLAYCONFIG_PATH_INFO other)
=> SourceInfo.Equals(other.SourceInfo) && => SourceInfo.Equals(other.SourceInfo) &&
@ -453,36 +564,78 @@ namespace DisplayMagicianShared.Windows
//public override string ToString() => $"{type.ToString("G")}"; //public override string ToString() => $"{type.ToString("G")}";
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Explicit)]
public struct DISPLAYCONFIG_MODE_INFO : IEquatable<DISPLAYCONFIG_MODE_INFO> public struct DISPLAYCONFIG_MODE_INFO : IEquatable<DISPLAYCONFIG_MODE_INFO>
{ {
[FieldOffset((0))]
public DISPLAYCONFIG_MODE_INFO_TYPE InfoType; public DISPLAYCONFIG_MODE_INFO_TYPE InfoType;
[FieldOffset(4)]
public uint Id; public uint Id;
[FieldOffset(8)]
public LUID AdapterId; public LUID AdapterId;
public DISPLAYCONFIG_MODE_INFO_union Info;
// These 3 fields are all a C union in wingdi.dll
[FieldOffset(16)]
public DISPLAYCONFIG_TARGET_MODE TargetMode;
[FieldOffset(16)]
public DISPLAYCONFIG_SOURCE_MODE SourceMode;
[FieldOffset(16)]
public DISPLAYCONFIG_DESKTOP_IMAGE_INFO DesktopImageInfo;
public bool Equals(DISPLAYCONFIG_MODE_INFO other) public bool Equals(DISPLAYCONFIG_MODE_INFO other)
=> InfoType == other.InfoType && {
Id == other.Id && if (InfoType != other.InfoType)
AdapterId.Equals(other.AdapterId) && return false;
Info.Equals(other.Info);
if (InfoType == DISPLAYCONFIG_MODE_INFO_TYPE.DISPLAYCONFIG_MODE_INFO_TYPE_TARGET &&
Id == other.Id &&
TargetMode.Equals(other.TargetMode))
return true;
if (InfoType == DISPLAYCONFIG_MODE_INFO_TYPE.DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE &&
Id == other.Id &&
SourceMode.Equals(other.SourceMode))
return true;
if (InfoType == DISPLAYCONFIG_MODE_INFO_TYPE.DISPLAYCONFIG_MODE_INFO_TYPE_DESKTOP_IMAGE &&
Id == other.Id &&
DesktopImageInfo.Equals(other.DesktopImageInfo))
return true;
return false;
}
public override int GetHashCode() public override int GetHashCode()
{ {
return (InfoType, Id, AdapterId, Info).GetHashCode(); if (InfoType == DISPLAYCONFIG_MODE_INFO_TYPE.DISPLAYCONFIG_MODE_INFO_TYPE_TARGET)
return (InfoType, Id, TargetMode).GetHashCode();
if (InfoType == DISPLAYCONFIG_MODE_INFO_TYPE.DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE)
return (InfoType, Id, SourceMode).GetHashCode();
if (InfoType == DISPLAYCONFIG_MODE_INFO_TYPE.DISPLAYCONFIG_MODE_INFO_TYPE_DESKTOP_IMAGE)
return (InfoType, Id, DesktopImageInfo).GetHashCode();
// otherwise we return everything
return (InfoType, Id, TargetMode, SourceMode, DesktopImageInfo).GetHashCode();
} }
//public override string ToString() => $"{type.ToString("G")}"; //public override string ToString() => $"{type.ToString("G")}";
} }
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DISPLAYCONFIG_GET_SOURCE_NAME : IEquatable<DISPLAYCONFIG_GET_SOURCE_NAME> public struct DISPLAYCONFIG_SOURCE_DEVICE_NAME : IEquatable<DISPLAYCONFIG_SOURCE_DEVICE_NAME>
{ {
public DISPLAYCONFIG_DEVICE_INFO_HEADER Header; public DISPLAYCONFIG_DEVICE_INFO_HEADER Header;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string ViewGdiDeviceName; public string ViewGdiDeviceName;
public bool Equals(DISPLAYCONFIG_GET_SOURCE_NAME other) public bool Equals(DISPLAYCONFIG_SOURCE_DEVICE_NAME other)
=> Header.Equals(other.Header) && => Header.Equals(other.Header) &&
ViewGdiDeviceName == other.ViewGdiDeviceName; ViewGdiDeviceName == other.ViewGdiDeviceName;
@ -502,7 +655,7 @@ namespace DisplayMagicianShared.Windows
public bool Equals(DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS other) public bool Equals(DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS other)
=> Value == other.Value; => Value == other.Value;
public bool FriendlyNameFromEdid => (Value & 0x1) == 0x1; public bool FriendlyNameFromEdid => (Value & 0x1) == 0x1; // Might be this broken?
public bool FriendlyNameForced => (Value & 0x2) == 0x2; public bool FriendlyNameForced => (Value & 0x2) == 0x2;
public bool EdidIdsValid => (Value & 0x4) == 0x4; public bool EdidIdsValid => (Value & 0x4) == 0x4;
@ -515,7 +668,7 @@ namespace DisplayMagicianShared.Windows
} }
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DISPLAYCONFIG_GET_TARGET_NAME : IEquatable<DISPLAYCONFIG_GET_TARGET_NAME> public struct DISPLAYCONFIG_TARGET_DEVICE_NAME : IEquatable<DISPLAYCONFIG_TARGET_DEVICE_NAME>
{ {
public DISPLAYCONFIG_DEVICE_INFO_HEADER Header; public DISPLAYCONFIG_DEVICE_INFO_HEADER Header;
public DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS Flags; public DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS Flags;
@ -528,7 +681,7 @@ namespace DisplayMagicianShared.Windows
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string MonitorDevicePath; public string MonitorDevicePath;
public bool Equals(DISPLAYCONFIG_GET_TARGET_NAME other) public bool Equals(DISPLAYCONFIG_TARGET_DEVICE_NAME other)
=> Header.Equals(other.Header) && => Header.Equals(other.Header) &&
Flags.Equals(other.Flags) && Flags.Equals(other.Flags) &&
OutputTechnology.Equals(other.OutputTechnology) && OutputTechnology.Equals(other.OutputTechnology) &&
@ -548,14 +701,14 @@ namespace DisplayMagicianShared.Windows
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal struct DISPLAYCONFIG_GET_TARGET_PREFERRED_NAME : IEquatable<DISPLAYCONFIG_GET_TARGET_PREFERRED_NAME> public struct DISPLAYCONFIG_TARGET_PREFERRED_MODE : IEquatable<DISPLAYCONFIG_TARGET_PREFERRED_MODE>
{ {
public DISPLAYCONFIG_DEVICE_INFO_HEADER Header; public DISPLAYCONFIG_DEVICE_INFO_HEADER Header;
public uint Width; public uint Width;
public uint Height; public uint Height;
public DISPLAYCONFIG_TARGET_MODE TargetMode; public DISPLAYCONFIG_TARGET_MODE TargetMode;
public bool Equals(DISPLAYCONFIG_GET_TARGET_PREFERRED_NAME other) public bool Equals(DISPLAYCONFIG_TARGET_PREFERRED_MODE other)
=> Header.Equals(other.Header) && => Header.Equals(other.Header) &&
Width == other.Width && Width == other.Width &&
Height == other.Height && Height == other.Height &&
@ -570,13 +723,13 @@ namespace DisplayMagicianShared.Windows
} }
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct DISPLAYCONFIG_GET_ADAPTER_NAME : IEquatable<DISPLAYCONFIG_GET_ADAPTER_NAME> public struct DISPLAYCONFIG_ADAPTER_NAME : IEquatable<DISPLAYCONFIG_ADAPTER_NAME>
{ {
public DISPLAYCONFIG_DEVICE_INFO_HEADER Header; public DISPLAYCONFIG_DEVICE_INFO_HEADER Header;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string AdapterDevicePath; public string AdapterDevicePath;
public bool Equals(DISPLAYCONFIG_GET_ADAPTER_NAME other) public bool Equals(DISPLAYCONFIG_ADAPTER_NAME other)
=> Header.Equals(other.Header) && => Header.Equals(other.Header) &&
AdapterDevicePath == other.AdapterDevicePath; AdapterDevicePath == other.AdapterDevicePath;
@ -589,24 +742,23 @@ namespace DisplayMagicianShared.Windows
} }
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION : IEquatable<DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION> public struct DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION : IEquatable<DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION>
{ {
public DISPLAYCONFIG_DEVICE_INFO_HEADER Header; public DISPLAYCONFIG_DEVICE_INFO_HEADER Header;
[MarshalAs(UnmanagedType.U4)] public uint Value;
public uint DisableMonitorVirtualResolution;
public bool IsMonitorVirtualResolutionDisabled public bool IsMonitorVirtualResolutionDisabled
{ {
get => (DisableMonitorVirtualResolution & 0x1) == 0x1; get => (Value & 0x1) == 0x1;
} }
public bool Equals(DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION other) public bool Equals(DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION other)
=> Header.Equals(other.Header) && => Header.Equals(other.Header) &&
DisableMonitorVirtualResolution == other.DisableMonitorVirtualResolution; Value == other.Value;
public override int GetHashCode() public override int GetHashCode()
{ {
return (Header, DisableMonitorVirtualResolution).GetHashCode(); return (Header, Value).GetHashCode();
} }
//public override string ToString() => $"{type.ToString("G")}"; //public override string ToString() => $"{type.ToString("G")}";
@ -614,24 +766,23 @@ namespace DisplayMagicianShared.Windows
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal struct DISPLAYCONFIG_SET_TARGET_PERSISTENCE : IEquatable<DISPLAYCONFIG_SET_TARGET_PERSISTENCE> public struct DISPLAYCONFIG_SET_TARGET_PERSISTENCE : IEquatable<DISPLAYCONFIG_SET_TARGET_PERSISTENCE>
{ {
public DISPLAYCONFIG_DEVICE_INFO_HEADER Header; public DISPLAYCONFIG_DEVICE_INFO_HEADER Header;
[MarshalAs(UnmanagedType.U4)] public uint Value;
public uint BootPersistenceOn;
public bool IsBootPersistenceOn public bool IsBootPersistenceOn
{ {
get => (BootPersistenceOn & 0x1) == 0x1; get => (Value & 0x1) == 0x1;
} }
public bool Equals(DISPLAYCONFIG_SET_TARGET_PERSISTENCE other) public bool Equals(DISPLAYCONFIG_SET_TARGET_PERSISTENCE other)
=> Header.Equals(other.Header) && => Header.Equals(other.Header) &&
BootPersistenceOn == other.BootPersistenceOn; Value == other.Value;
public override int GetHashCode() public override int GetHashCode()
{ {
return (Header, BootPersistenceOn).GetHashCode(); return (Header, Value).GetHashCode();
} }
//public override string ToString() => $"{type.ToString("G")}"; //public override string ToString() => $"{type.ToString("G")}";
@ -639,13 +790,13 @@ namespace DisplayMagicianShared.Windows
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal struct DISPLAYCONFIG_GET_TARGET_BASE_TYPE : IEquatable<DISPLAYCONFIG_GET_TARGET_BASE_TYPE> public struct DISPLAYCONFIG_TARGET_BASE_TYPE : IEquatable<DISPLAYCONFIG_TARGET_BASE_TYPE>
{ {
public DISPLAYCONFIG_DEVICE_INFO_HEADER Header; public DISPLAYCONFIG_DEVICE_INFO_HEADER Header;
[MarshalAs(UnmanagedType.U4)] //[MarshalAs(UnmanagedType.U4)]
public DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY BaseOutputTechnology; public DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY BaseOutputTechnology;
public bool Equals(DISPLAYCONFIG_GET_TARGET_BASE_TYPE other) public bool Equals(DISPLAYCONFIG_TARGET_BASE_TYPE other)
=> Header.Equals(other.Header) && => Header.Equals(other.Header) &&
BaseOutputTechnology == other.BaseOutputTechnology; BaseOutputTechnology == other.BaseOutputTechnology;
@ -659,15 +810,25 @@ namespace DisplayMagicianShared.Windows
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal struct DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE : IEquatable<DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE> public struct DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE : IEquatable<DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE>
{ {
public DISPLAYCONFIG_DEVICE_INFO_HEADER Header; public DISPLAYCONFIG_DEVICE_INFO_HEADER Header;
[MarshalAs(UnmanagedType.U4)]
public uint Value; public uint Value;
public bool EnableAdvancedColor public bool EnableAdvancedColor
{ {
get => (Value & 0x1) == 0x1; get => (Value & 0x1) == 0x1;
set
{
if (value)
{
Value = 0x1;
}
else
{
Value = 0x0;
}
}
} }
public bool Equals(DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE other) public bool Equals(DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE other)
@ -683,13 +844,15 @@ namespace DisplayMagicianShared.Windows
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal struct DISPLAYCONFIG_SDR_WHITE_LEVEL : IEquatable<DISPLAYCONFIG_SDR_WHITE_LEVEL> public struct DISPLAYCONFIG_SDR_WHITE_LEVEL : IEquatable<DISPLAYCONFIG_SDR_WHITE_LEVEL>
{ {
public DISPLAYCONFIG_DEVICE_INFO_HEADER Header; public DISPLAYCONFIG_DEVICE_INFO_HEADER Header;
// SDRWhiteLevel represents a multiplier for standard SDR white // SDRWhiteLevel represents a multiplier for standard SDR white
// peak value i.e. 80 nits represented as fixed point. // peak value i.e. 80 nits represented as fixed point.
// To get value in nits use the following conversion // To get value in nits use the following conversion
// SDRWhiteLevel in nits = (SDRWhiteLevel / 1000 ) * 80 // SDRWhiteLevel in nits = (SDRWhiteLevel / 1000 ) * 80
// NOTE! Weirdly this is supposed to be a ulong, but there is an error in Win10 64-bit
// where it actually returns a uint! So had to engineer in a bug :(
public uint SDRWhiteLevel; public uint SDRWhiteLevel;
public bool Equals(DISPLAYCONFIG_SDR_WHITE_LEVEL other) public bool Equals(DISPLAYCONFIG_SDR_WHITE_LEVEL other)
@ -706,14 +869,14 @@ namespace DisplayMagicianShared.Windows
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct RECT : IEquatable<RECT> public struct RECTL : IEquatable<RECTL>
{ {
public int Left; public int Left;
public int Top; public int Top;
public int Right; public int Right;
public int Bottom; public int Bottom;
public bool Equals(RECT other) public bool Equals(RECTL other)
=> Left == other.Left && => Left == other.Left &&
Top == other.Top && Top == other.Top &&
Right == other.Right && Right == other.Right &&
@ -730,6 +893,10 @@ namespace DisplayMagicianShared.Windows
class CCDImport class CCDImport
{ {
// Set some useful constants
public const SDC SDC_CCD_TEST_IF_VALID = (SDC.SDC_VALIDATE | SDC.SDC_USE_SUPPLIED_DISPLAY_CONFIG);
// GetDisplayConfigBufferSizes // GetDisplayConfigBufferSizes
[DllImport("user32")] [DllImport("user32")]
public static extern WIN32STATUS GetDisplayConfigBufferSizes(QDC flags, out int numPathArrayElements, out int numModeInfoArrayElements); public static extern WIN32STATUS GetDisplayConfigBufferSizes(QDC flags, out int numPathArrayElements, out int numModeInfoArrayElements);
@ -743,22 +910,22 @@ namespace DisplayMagicianShared.Windows
// DisplayConfigGetDeviceInfo // DisplayConfigGetDeviceInfo
[DllImport("user32")] [DllImport("user32")]
public static extern WIN32STATUS DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_GET_SOURCE_NAME requestPacket); public static extern WIN32STATUS DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_SOURCE_DEVICE_NAME requestPacket);
[DllImport("user32")] [DllImport("user32")]
public static extern WIN32STATUS DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_GET_TARGET_NAME requestPacket); public static extern WIN32STATUS DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_TARGET_DEVICE_NAME requestPacket);
[DllImport("user32")] [DllImport("user32")]
public static extern WIN32STATUS DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_GET_TARGET_PREFERRED_NAME requestPacket); public static extern WIN32STATUS DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_TARGET_PREFERRED_MODE requestPacket);
[DllImport("user32")] [DllImport("user32")]
public static extern WIN32STATUS DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_GET_ADAPTER_NAME requestPacket); public static extern WIN32STATUS DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_ADAPTER_NAME requestPacket);
[DllImport("user32")] [DllImport("user32")]
public static extern WIN32STATUS DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_SET_TARGET_PERSISTENCE requestPacket); public static extern WIN32STATUS DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_SET_TARGET_PERSISTENCE requestPacket);
[DllImport("user32")] [DllImport("user32")]
public static extern WIN32STATUS DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_GET_TARGET_BASE_TYPE requestPacket); public static extern WIN32STATUS DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_TARGET_BASE_TYPE requestPacket);
[DllImport("user32")] [DllImport("user32")]
public static extern WIN32STATUS DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION requestPacket); public static extern WIN32STATUS DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION requestPacket);
@ -777,7 +944,11 @@ namespace DisplayMagicianShared.Windows
// DisplayConfigSetDeviceInfo // DisplayConfigSetDeviceInfo
[DllImport("user32")] [DllImport("user32")]
public static extern WIN32STATUS DisplayConfigSetDeviceInfo(ref DISPLAYCONFIG_SET_TARGET_PERSISTENCE targetPersistence); public static extern WIN32STATUS DisplayConfigSetDeviceInfo(ref DISPLAYCONFIG_SET_TARGET_PERSISTENCE requestPacket);
[DllImport("user32")]
public static extern WIN32STATUS DisplayConfigSetDeviceInfo(ref DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE requestPacket);
// Have disabled the DisplayConfigSetDeviceInfo options except for SET_TARGET_PERSISTENCE, as per the note // Have disabled the DisplayConfigSetDeviceInfo options except for SET_TARGET_PERSISTENCE, as per the note
// from https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-displayconfigsetdeviceinfo // from https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-displayconfigsetdeviceinfo
@ -787,7 +958,7 @@ namespace DisplayMagicianShared.Windows
// SetDisplayConfig // SetDisplayConfig
[DllImport("user32")] [DllImport("user32")]
public static extern WIN32STATUS SetDisplayConfig([In] uint pathArrayElements, [In] DISPLAYCONFIG_PATH_INFO[] pathArray, [In] uint modeInfoArrayElements, [In] DISPLAYCONFIG_MODE_INFO[] modeInfoArray, [In] QDC flags); public static extern WIN32STATUS SetDisplayConfig([In] uint numPathArrayElements, [In] DISPLAYCONFIG_PATH_INFO[] pathArray, [In] uint numModeInfoArrayElements, [In] DISPLAYCONFIG_MODE_INFO[] modeInfoArray, [In] SDC flags);
} }
} }

View File

@ -0,0 +1,986 @@
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;
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 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();
}
}
[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 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 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;
SharedLogger.logger.Trace("WinLibrary/WinLibrary: ADL2 library was initialised successfully");
}
~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;
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 = "";
// 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 IsPossibleConfig(WINDOWS_DISPLAY_CONFIG displayConfig)
{
// Get the all possible 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 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(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/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/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(QDC.QDC_ONLY_ACTIVE_PATHS, 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(QDC.QDC_ONLY_ACTIVE_PATHS, 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;
}
}
[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) { }
}
}

View File

@ -0,0 +1,632 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using DisplayMagicianShared.Resources;
using Newtonsoft.Json;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text.RegularExpressions;
using IWshRuntimeLibrary;
//using ATI.ADL;
//using WK.Libraries.HotkeyListenerNS;
namespace DisplayMagicianShared.Windows
{
/*// Struct to be used as the AMD Profile
[JsonObject(MemberSerialization.Fields)]
public struct AMDProfile
{
public List<AMDAdapter> Adapters;
}
// Struct to store the Display
[JsonObject(MemberSerialization.Fields)]
public struct AMDAdapter
{
public int AdapterIndex;
public string AdapterName;
public string DisplayName;
[JsonProperty]
public ADLAdapterInfoX2 AdapterInfoX2;
public List<AMDDisplay> Displays;
}
// Struct to store the Display
[JsonObject(MemberSerialization.Fields)]
public struct AMDDisplay
{
public string DisplayName;
public string DisplayConnector;
public string UDID;
[JsonRequired]
public List<ADLMode> DisplayModes;
public bool HDRSupported;
public bool HDREnabled;
public bool IsEyefinity;
}*/
public class WinProfileItem : ProfileItem, IComparable
{
private static List<WinProfileItem> _allSavedProfiles = new List<WinProfileItem>();
private ProfileIcon _profileIcon;
private Bitmap _profileBitmap, _profileShortcutBitmap;
private List<string> _profileDisplayIdentifiers = new List<string>();
private List<ScreenPosition> _screens;
private WINDOWS_DISPLAY_CONFIG _displayConfig = new WINDOWS_DISPLAY_CONFIG();
private static readonly string uuidV4Regex = @"(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$";
private string _uuid = "";
private bool _isPossible = false;
private Keys _hotkey = Keys.None;
public WinProfileItem()
{
}
public new static Version Version = new Version(2, 1);
#region Instance Properties
[JsonIgnore]
public override bool IsPossible
{
get
{
// Return the cached answer
return _isPossible;
}
set
{
_isPossible = value;
}
}
[JsonIgnore]
public override bool IsActive
{
get
{
if (this.Equals(ProfileRepository.CurrentProfile))
return true;
else
return false;
}
}
public override string Driver { get; } = "AMD";
public override string Name { get; set; }
//public Topology.Path[] Paths { get; set; } = new Topology.Path[0];
[JsonRequired]
public WINDOWS_DISPLAY_CONFIG DisplayConfig
{
get
{
return _displayConfig;
}
set
{
_displayConfig = value;
}
}
public override List<string> ProfileDisplayIdentifiers
{
get
{
if (_profileDisplayIdentifiers.Count == 0)
{
_profileDisplayIdentifiers = WinLibrary.GetLibrary().GetCurrentDisplayIdentifiers();
}
return _profileDisplayIdentifiers;
}
set
{
if (value is List<string>)
_profileDisplayIdentifiers = value;
}
}
[JsonIgnore]
public override List<ScreenPosition> Screens
{
get
{
if (_screens.Count == 0)
{
_screens = GetScreenPositions();
}
return _screens;
}
set
{
_screens = value;
}
}
//[JsonConverter(typeof(CustomBitmapConverter))]
[JsonIgnore]
public override Bitmap ProfileBitmap
{
get
{
/*if (!ProfileRepository.ProfilesLoaded)
return null;*/
if (_profileBitmap != null)
return _profileBitmap;
else
{
_profileBitmap = this.ProfileIcon.ToBitmap(256, 256);
return _profileBitmap;
}
}
set
{
_profileBitmap = value;
}
}
//[JsonConverter(typeof(CustomBitmapConverter))]
[JsonIgnore]
public override Bitmap ProfileTightestBitmap
{
get
{
if (_profileShortcutBitmap != null)
return _profileShortcutBitmap;
else
{
_profileShortcutBitmap = this.ProfileIcon.ToTightestBitmap();
return _profileShortcutBitmap;
}
}
set
{
_profileShortcutBitmap = value;
}
}
#endregion
public override bool IsValid()
{
if (ProfileIcon is ProfileIcon &&
System.IO.File.Exists(SavedProfileIconCacheFilename) &&
ProfileBitmap is Bitmap &&
ProfileTightestBitmap is Bitmap &&
ProfileDisplayIdentifiers.Count > 0)
{
if (DisplayConfig.displayConfigModes.Length > 0 && DisplayConfig.displayConfigPaths.Length > 0)
return true;
else
return false;
}
else
return false;
}
public bool CopyTo(WinProfileItem profile, bool overwriteId = true)
{
if (!(profile is WinProfileItem))
return false;
if (overwriteId == true)
profile.UUID = UUID;
// Copy all our profile data over to the other profile
profile.Name = Name;
profile.DisplayConfig = DisplayConfig;
profile.ProfileIcon = ProfileIcon;
profile.SavedProfileIconCacheFilename = SavedProfileIconCacheFilename;
profile.ProfileBitmap = ProfileBitmap;
profile.ProfileTightestBitmap = ProfileTightestBitmap;
profile.ProfileDisplayIdentifiers = ProfileDisplayIdentifiers;
//profile.Screens = Screens;
return true;
}
public override bool PreSave()
{
// Prepare our profile data for saving
if (_profileDisplayIdentifiers.Count == 0)
{
_profileDisplayIdentifiers = WinLibrary.GetLibrary().GetCurrentDisplayIdentifiers();
}
// Return if it is valid and we should continue
return IsValid();
}
public override void RefreshPossbility()
{
// Check each display in this profile and make sure it's currently available
int validDisplayCount = 0;
//validDisplayCount = (from connectedDisplay in ProfileRepository.ConnectedDisplayIdentifiers select connectedDisplay == profileDisplayIdentifier).Count();
foreach (string profileDisplayIdentifier in ProfileDisplayIdentifiers)
{
// If this profile has a display that isn't currently available then we need to say it's a no!
if (ProfileRepository.ConnectedDisplayIdentifiers.Any(s => profileDisplayIdentifier.Equals(s)))
{
SharedLogger.logger.Trace($"ProfileItem/RefreshPossbility: We found the display in the profile {Name} with profileDisplayIdentifier {profileDisplayIdentifier} is connected now.");
validDisplayCount++;
}
else
{
SharedLogger.logger.Warn($"ProfileItem/RefreshPossbility: We found the display in the profile {Name} with profileDisplayIdentifier {profileDisplayIdentifier} is NOT currently connected, so this profile cannot be used.");
}
}
if (validDisplayCount == ProfileDisplayIdentifiers.Count)
{
SharedLogger.logger.Debug($"ProfileRepository/IsPossibleRefresh: The profile {Name} is possible!");
_isPossible = true;
}
else
{
SharedLogger.logger.Debug($"ProfileRepository/IsPossibleRefresh: The profile {Name} is NOT possible!");
_isPossible = false;
}
}
public override bool CreateProfileFromCurrentDisplaySettings()
{
WinLibrary winLibrary = WinLibrary.GetLibrary();
if (winLibrary.IsInstalled)
{
// Create the profile data from the current config
_displayConfig = winLibrary.GetActiveConfig();
// Now, since the ActiveProfile has changed, we need to regenerate screen positions
_screens = GetScreenPositions();
return true;
}
else
{
return false;
}
}
public override bool PerformPostLoadingTasks()
{
// First thing we do is to set up the Screens
_screens = GetScreenPositions();
return true;
}
public override List<ScreenPosition> GetScreenPositions()
{
// Now we create the screens structure from the AMD profile information
_screens = new List<ScreenPosition>();
if ( _displayConfig.displayConfigModes.Length > 0 && _displayConfig.displayConfigPaths.Length > 0)
{
foreach ( var adapter in _displayConfig.AdapterConfigs)
{
foreach (var display in adapter.Displays)
{
foreach (var mode in display.DisplayModes)
{
ScreenPosition screen = new ScreenPosition();
screen.Library = "AMD";
screen.Name = display.DisplayName;
screen.DisplayConnector = display.DisplayConnector;
screen.ScreenX = mode.XPos;
screen.ScreenY = mode.YPos;
screen.ScreenWidth = mode.XRes;
screen.ScreenHeight = mode.YRes;
// If we're at the 0,0 coordinate then we're the primary monitor
if (screen.ScreenX == 0 && screen.ScreenY == 0)
{
screen.IsPrimary = true;
}
// HDR information
if (display.HDRSupported)
{
screen.HDRSupported = true;
if (display.HDREnabled)
{
screen.HDREnabled = true;
}
else
{
screen.HDREnabled = false;
}
}
else
{
screen.HDRSupported = false;
screen.HDREnabled = false;
}
// Spanned screen options
if (display.IsEyefinity)
{
screen.IsSpanned = true;
screen.Colour = Color.FromArgb(200, 237, 28, 36); // represents AMD Red
screen.SpannedName = "AMD Eyefinity";
}
else
{
screen.IsSpanned = false;
screen.Colour = Color.FromArgb(255, 195, 195, 195); // represents normal screen colour
}
// Figure out features
//ATI.ADL.ADL.ConvertDisplayModeFlags(mode.ModeValue);
//screen.Features = mode.ModeValue;
_screens.Add(screen);
}
}
}
}
return _screens;
}
// The public override for the Object.Equals
public override bool Equals(object obj)
{
return this.Equals(obj as WinProfileItem);
}
// Profiles are equal if their Viewports are equal
public bool Equals(WinProfileItem other)
{
// If parameter is null, return false.
if (other is null)
return false;
// Optimization for a common success case.
if (Object.ReferenceEquals(this, other))
return true;
// If run-time types are not exactly the same, return false.
if (this.GetType() != other.GetType())
return false;
// If the DisplayConfig's equal each other
if (DisplayConfig.Equals(other.DisplayConfig))
return false;
// Check if the profile identifiers are not the same, then return false
int foundDICount = 0;
foreach (string profileDI in ProfileDisplayIdentifiers)
{
if (other.ProfileDisplayIdentifiers.Contains(profileDI))
{
foundDICount++;
continue;
}
}
if (foundDICount != other.ProfileDisplayIdentifiers.Count)
return false;
foundDICount = 0;
foreach (string profileDI in other.ProfileDisplayIdentifiers)
{
if (ProfileDisplayIdentifiers.Contains(profileDI))
{
foundDICount++;
continue;
}
}
if (foundDICount != ProfileDisplayIdentifiers.Count)
return false;
// Check whether the profiles' properties are equal
// We need to exclude the name as the name is solely for saving to disk
// and displaying to the user.
// Two profiles are equal only when they have the same viewport data
// The data may be in different orders each run, so we need to compare them one by one
int foundPathsCount = 0;
int foundOtherPathsCount = 0;
// TODO: Make this work in AMD land
/*foreach (Topology.Path profilePath in Paths)
{
if (other.Paths.Contains(profilePath))
{
foundPathsCount++;
continue;
}
}
foreach (Topology.Path otherPath in other.Paths)
{
if (Paths.Contains(otherPath))
{
foundOtherPathsCount++;
continue;
}
}*/
if (foundPathsCount == foundOtherPathsCount)
return true;
else
return false;
}
// If Equals() returns true for this object compared to another
// then GetHashCode() must return the same value for these objects.
/*public override int GetHashCode()
{
// Get hash code for the Viewports field if it is not null.
int hashPaths = Paths == null ? 0 : Paths.GetHashCode();
//Calculate the hash code for the product.
return hashPaths;
}*/
public override int GetHashCode()
{
// Get hash code for the ProfileDisplayIdentifiers field if it is not null.
int hashIds = ProfileDisplayIdentifiers == null ? 0 : ProfileDisplayIdentifiers.GetHashCode();
// Get ProfileData too
int hashProfileData = DisplayConfig.GetHashCode();
// Calculate the hash code for the product.
return (hashIds, hashProfileData).GetHashCode();
}
public override string ToString()
{
return (Name ?? Language.UN_TITLED_PROFILE);
}
}
// Custom Equality comparer for the Profile class
// Allows us to use 'Contains'
class AMDProfileComparer : IEqualityComparer<WinProfileItem>
{
// Products are equal if their names and product numbers are equal.
/*public bool Equals(AMDProfileItem x, AMDProfileItem y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (x is null || y is null)
return false;
// Check whether the profiles' properties are equal
// We need to exclude the name as the name is solely for saving to disk
// and displaying to the user.
// Two profiles are equal only when they have the same viewport data
if (x.Paths.SequenceEqual(y.Paths))
return true;
else
return false;
}*/
public bool Equals(WinProfileItem x, WinProfileItem y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (x is null || y is null)
return false;
// Check if the profile identifiers are not the same, then return false
int foundDICount = 0;
foreach (string profileDI in x.ProfileDisplayIdentifiers)
{
if (y.ProfileDisplayIdentifiers.Contains(profileDI))
{
foundDICount++;
continue;
}
}
if (foundDICount != x.ProfileDisplayIdentifiers.Count)
return false;
foundDICount = 0;
foreach (string profileDI in y.ProfileDisplayIdentifiers)
{
if (x.ProfileDisplayIdentifiers.Contains(profileDI))
{
foundDICount++;
continue;
}
}
if (foundDICount != y.ProfileDisplayIdentifiers.Count)
return false;
// Now we need to check the Display Configs themselves
if (x.DisplayConfig.Equals(y.DisplayConfig))
return false;
return true;
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
/*public int GetHashCode(AMDProfileItem profile)
{
// Check whether the object is null
if (profile is null) return 0;
// Get hash code for the Viewports field if it is not null.
int hashPaths = profile.Paths == null ? 0 : profile.Paths.GetHashCode();
//Calculate the hash code for the product.
return hashPaths;
}*/
// Modified the GetHashCode to compare the displayidentifier
public int GetHashCode(WinProfileItem profile)
{
// Check whether the object is null
if (profile is null) return 0;
// Get hash code for the ProfileDisplayIdentifiers field if it is not null.
int hashIds = profile.ProfileDisplayIdentifiers == null ? 0 : profile.ProfileDisplayIdentifiers.GetHashCode();
// Get hash code for the Paths
int hashProfileData = profile.DisplayConfig.GetHashCode();
//Calculate the hash code for the product.
return (hashIds, hashProfileData).GetHashCode();
}
}
}

View File

@ -1,54 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace DisplayMagicianShared.Windows
{
class WindowsCCDLibrary
{
static void Main()
{
WIN32STATUS err = CCDImport.GetDisplayConfigBufferSizes(QDC.QDC_ONLY_ACTIVE_PATHS, out var pathCount, out var modeCount);
if (err != WIN32STATUS.ERROR_SUCCESS)
throw new Win32Exception((int)err);
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_SUCCESS)
throw new Win32Exception((int)err);
foreach (var path in paths)
{
// get display name
var info = new DISPLAYCONFIG_GET_TARGET_NAME();
info.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
info.Header.Size = Marshal.SizeOf<DISPLAYCONFIG_GET_TARGET_NAME>();
info.Header.AdapterId = path.TargetInfo.AdapterId;
info.Header.Id = path.TargetInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref info);
if (err != WIN32STATUS.ERROR_SUCCESS)
throw new Win32Exception((int)err);
var colorInfo = new DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO();
colorInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO;
colorInfo.Header.Size = Marshal.SizeOf<DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO>();
colorInfo.Header.AdapterId = path.TargetInfo.AdapterId;
colorInfo.Header.Id = path.TargetInfo.Id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref colorInfo);
if (err != WIN32STATUS.ERROR_SUCCESS)
throw new Win32Exception((int)err);
Console.WriteLine(info.MonitorFriendlyDeviceName);
Console.WriteLine(" Advanced Color Supported: " + colorInfo.AdvancedColorSupported);
Console.WriteLine(" Advanced Color Enabled : " + colorInfo.AdvancedColorEnabled);
Console.WriteLine();
}
}
}
}