diff --git a/DisplayMagician/Processes/ProcessUtils.cs b/DisplayMagician/Processes/ProcessUtils.cs
index 0de6ff7..b476e8c 100644
--- a/DisplayMagician/Processes/ProcessUtils.cs
+++ b/DisplayMagician/Processes/ProcessUtils.cs
@@ -601,6 +601,12 @@ namespace DisplayMagician.Processes
{
if (ex.ErrorCode == -2147467259)
{
+ if (runAsAdministrator)
+ {
+ logger.Error(ex, $"ProcessUtils/TryExecute: Exception while trying to start {executable} for a second time with administrative rights. Giving up.");
+ return false;
+ }
+
logger.Error(ex, $"ProcessUtils/TryExecute: Exception while trying to start {executable}. The process requires elevation. Attempting again with admin rights.");
if (TryExecute(executable, arguments, out processCreated, true, priorityClass, maxWaitMs))
{
diff --git a/DisplayMagician/Properties/AssemblyInfo.cs b/DisplayMagician/Properties/AssemblyInfo.cs
index deae989..00d8dce 100644
--- a/DisplayMagician/Properties/AssemblyInfo.cs
+++ b/DisplayMagician/Properties/AssemblyInfo.cs
@@ -26,8 +26,8 @@ using System.Resources;
[assembly: Guid("e4ceaf5e-ad01-4695-b179-31168eb74c48")]
// Version information
-[assembly: AssemblyVersion("2.2.0.250")]
-[assembly: AssemblyFileVersion("2.2.0.250")]
+[assembly: AssemblyVersion("2.2.0.251")]
+[assembly: AssemblyFileVersion("2.2.0.251")]
[assembly: NeutralResourcesLanguageAttribute( "en" )]
[assembly: CLSCompliant(true)]
diff --git a/DisplayMagicianShared/DisplayMagicianShared.csproj b/DisplayMagicianShared/DisplayMagicianShared.csproj
index bec17fa..2dd220d 100644
--- a/DisplayMagicianShared/DisplayMagicianShared.csproj
+++ b/DisplayMagicianShared/DisplayMagicianShared.csproj
@@ -82,7 +82,7 @@
True
-
+
UserControl
diff --git a/DisplayMagicianShared/NVIDIA/NVAPI.cs b/DisplayMagicianShared/NVIDIA/NVAPI.cs
index 006c733..b6bdb16 100644
--- a/DisplayMagicianShared/NVIDIA/NVAPI.cs
+++ b/DisplayMagicianShared/NVIDIA/NVAPI.cs
@@ -755,7 +755,7 @@ namespace DisplayMagicianShared.NVIDIA
// ==================================
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct DisplayHandle : IEquatable
+ public struct DisplayHandle : IEquatable, ICloneable
{
public IntPtr Ptr;
@@ -772,10 +772,16 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(DisplayHandle lhs, DisplayHandle rhs) => lhs.Equals(rhs);
public static bool operator !=(DisplayHandle lhs, DisplayHandle rhs) => !(lhs == rhs);
+
+ public object Clone()
+ {
+ DisplayHandle other = (DisplayHandle)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct UnAttachedDisplayHandle : IEquatable
+ public struct UnAttachedDisplayHandle : IEquatable, ICloneable
{
public IntPtr Ptr;
@@ -792,10 +798,16 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(UnAttachedDisplayHandle lhs, UnAttachedDisplayHandle rhs) => lhs.Equals(rhs);
public static bool operator !=(UnAttachedDisplayHandle lhs, UnAttachedDisplayHandle rhs) => !(lhs == rhs);
+
+ public object Clone()
+ {
+ UnAttachedDisplayHandle other = (UnAttachedDisplayHandle)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct PhysicalGpuHandle : IEquatable
+ public struct PhysicalGpuHandle : IEquatable, ICloneable
{
public IntPtr Ptr;
@@ -811,11 +823,17 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(PhysicalGpuHandle lhs, PhysicalGpuHandle rhs) => lhs.Equals(rhs);
public static bool operator !=(PhysicalGpuHandle lhs, PhysicalGpuHandle rhs) => !(lhs == rhs);
+
+ public object Clone()
+ {
+ PhysicalGpuHandle other = (PhysicalGpuHandle)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct LogicalGpuHandle : IEquatable
+ public struct LogicalGpuHandle : IEquatable, ICloneable
{
public IntPtr Ptr;
@@ -831,10 +849,48 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(LogicalGpuHandle lhs, LogicalGpuHandle rhs) => lhs.Equals(rhs);
public static bool operator !=(LogicalGpuHandle lhs, LogicalGpuHandle rhs) => !(lhs == rhs);
+
+ public object Clone()
+ {
+ LogicalGpuHandle other = (LogicalGpuHandle)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_BOARD_INFO_V1 : IEquatable // Note: Version 1 of NV_BOARD_INFO_V1 structure
+ public struct NV_LOGICAL_GPU_DATA_V1 : IEquatable, ICloneable // Note: Version 1 of NV_BOARD_INFO_V1 structure
+ {
+ public UInt32 Version; //!< structure version
+ public IntPtr OSAdapterId;
+ public UInt32 PhysicalGPUCount;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)NVImport.NVAPI_MAX_PHYSICAL_GPUS)]
+ public PhysicalGpuHandle[] PhysicalGPUHandles;
+ public UInt32 Reserved;
+
+ public override bool Equals(object obj) => obj is NV_LOGICAL_GPU_DATA_V1 other && this.Equals(other);
+
+ public bool Equals(NV_LOGICAL_GPU_DATA_V1 other)
+ => Version == other.Version &&
+ PhysicalGPUCount == other.PhysicalGPUCount &&
+ PhysicalGPUHandles.SequenceEqual(other.PhysicalGPUHandles);
+
+ public override Int32 GetHashCode()
+ {
+ return (Version, PhysicalGPUCount, PhysicalGPUHandles).GetHashCode();
+ }
+ public static bool operator ==(NV_LOGICAL_GPU_DATA_V1 lhs, NV_LOGICAL_GPU_DATA_V1 rhs) => lhs.Equals(rhs);
+
+ public static bool operator !=(NV_LOGICAL_GPU_DATA_V1 lhs, NV_LOGICAL_GPU_DATA_V1 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_LOGICAL_GPU_DATA_V1 other = (NV_LOGICAL_GPU_DATA_V1)MemberwiseClone();
+ return other;
+ }
+ }
+
+
+ [StructLayout(LayoutKind.Sequential, Pack = 8)]
+ public struct NV_BOARD_INFO_V1 : IEquatable, ICloneable // Note: Version 1 of NV_BOARD_INFO_V1 structure
{
public UInt32 Version; //!< structure version
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
@@ -853,10 +909,15 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_BOARD_INFO_V1 lhs, NV_BOARD_INFO_V1 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_BOARD_INFO_V1 lhs, NV_BOARD_INFO_V1 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_BOARD_INFO_V1 other = (NV_BOARD_INFO_V1)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_EDID_V3 : IEquatable // Note: Version 3 of NV_EDID_V3 structure
+ public struct NV_EDID_V3 : IEquatable, ICloneable // Note: Version 3 of NV_EDID_V3 structure
{
public UInt32 Version; //!< Structure version
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (Int32)NVImport.NV_EDID_DATA_SIZE)]
@@ -885,11 +946,17 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_EDID_V3 lhs, NV_EDID_V3 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_EDID_V3 lhs, NV_EDID_V3 rhs) => !(lhs == rhs);
+
+ public object Clone()
+ {
+ NV_EDID_V3 other = (NV_EDID_V3)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Ansi)]
- public struct NV_TIMING_EXTRA : IEquatable
+ public struct NV_TIMING_EXTRA : IEquatable, ICloneable
{
public UInt32 Flags; //!< Reserved for NVIDIA hardware-based enhancement, such as double-scan.
public ushort RefreshRate; //!< Logical refresh rate to present
@@ -921,10 +988,32 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_TIMING_EXTRA lhs, NV_TIMING_EXTRA rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_TIMING_EXTRA lhs, NV_TIMING_EXTRA rhs) => !(lhs == rhs);
+
+ public object Clone()
+ {
+ NV_TIMING_EXTRA other = (NV_TIMING_EXTRA)MemberwiseClone();
+ return other;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Ansi)]
+ public struct NV_TIMING_EXTRA_INTERNAL
+ {
+ public UInt32 Flags; //!< Reserved for NVIDIA hardware-based enhancement, such as double-scan.
+ public ushort RefreshRate; //!< Logical refresh rate to present
+ public UInt32 FrequencyInMillihertz; //!< Physical vertical refresh rate in 0.001Hz
+ public ushort VerticalAspect; //!< Display aspect ratio Hi(aspect):horizontal-aspect, Low(aspect):vertical-aspect
+ public ushort HorizontalAspect; //!< Display aspect ratio Hi(aspect):horizontal-aspect, Low(aspect):vertical-aspect
+ public ushort HorizontalPixelRepetition; //!< Bit-wise pixel repetition factor: 0x1:no pixel repetition; 0x2:each pixel repeats twice horizontally,..
+ public UInt32 TimingStandard; //!< Timing standard
+ //[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
+ public string Name; //!< Timing name
+
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_TIMING : IEquatable
+ public struct NV_TIMING : IEquatable, ICloneable
{
// VESA scan out timing parameters:
public ushort HVisible; //!< horizontal visible
@@ -973,10 +1062,43 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_TIMING lhs, NV_TIMING rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_TIMING lhs, NV_TIMING rhs) => !(lhs == rhs);
+
+ public object Clone()
+ {
+ NV_TIMING other = (NV_TIMING)MemberwiseClone();
+ other.Extra = (NV_TIMING_EXTRA)Extra.Clone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_RECT : IEquatable
+ public struct NV_TIMING_INTERNAL
+ {
+ // 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 TIMING_HORIZONTAL_SYNC_POLARITY 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 TIMING_VERTICAL_SYNC_POLARITY VSyncPol; //!< vertical sync polarity: 1-negative, 0-positive
+
+ public TIMING_SCAN_MODE ScanMode; //!< 1-Int32erlaced, 0-progressive
+ public UInt32 Pclk; //!< pixel clock in 10 kHz
+
+ //other timing related extras - points to a NV_TIMING_EXTRA_INTERNAL
+ public IntPtr Extra;
+
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 8)]
+ public struct NV_RECT : IEquatable, ICloneable
{
public UInt32 Left;
public UInt32 Top;
@@ -998,10 +1120,16 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_RECT lhs, NV_RECT rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_RECT lhs, NV_RECT rhs) => !(lhs == rhs);
+
+ public object Clone()
+ {
+ NV_RECT other = (NV_RECT)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_LUID : IEquatable
+ public struct NV_LUID : IEquatable, ICloneable
{
public UInt32 LowPart;
public UInt32 HighPart;
@@ -1019,11 +1147,17 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_LUID lhs, NV_LUID rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_LUID lhs, NV_LUID rhs) => !(lhs == rhs);
+
+ public object Clone()
+ {
+ NV_LUID other = (NV_LUID)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_POSITION : IEquatable
+ public struct NV_POSITION : IEquatable, ICloneable
{
public Int32 X;
public Int32 Y;
@@ -1041,11 +1175,23 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_POSITION lhs, NV_POSITION rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_POSITION lhs, NV_POSITION rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_POSITION other = (NV_POSITION)MemberwiseClone();
+ return other;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 8)]
+ public struct NV_POSITION_INTERNAL
+ {
+ public Int32 X;
+ public Int32 Y;
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_RESOLUTION : IEquatable
+ public struct NV_RESOLUTION : IEquatable, ICloneable
{
public UInt32 Width;
public UInt32 Height;
@@ -1065,10 +1211,25 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_RESOLUTION lhs, NV_RESOLUTION rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_RESOLUTION lhs, NV_RESOLUTION rhs) => !(lhs == rhs);
+
+ public object Clone()
+ {
+ NV_RESOLUTION other = (NV_RESOLUTION)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_VIEWPORTF : IEquatable
+ public struct NV_RESOLUTION_INTERNAL
+ {
+ public UInt32 Width;
+ public UInt32 Height;
+ public UInt32 ColorDepth;
+ }
+
+
+ [StructLayout(LayoutKind.Sequential, Pack = 8)]
+ public struct NV_VIEWPORTF : IEquatable, ICloneable
{
public float X; //!< x-coordinate of the viewport top-left point
public float Y; //!< y-coordinate of the viewport top-left point
@@ -1104,10 +1265,16 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_VIEWPORTF lhs, NV_VIEWPORTF rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_VIEWPORTF lhs, NV_VIEWPORTF rhs) => !(lhs == rhs);
+
+ public object Clone()
+ {
+ NV_VIEWPORTF other = (NV_VIEWPORTF)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO : IEquatable // Requires Version 1
+ public struct NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1 : IEquatable, ICloneable // Requires Version 1
{
public UInt32 Version;
@@ -1143,9 +1310,9 @@ namespace DisplayMagicianShared.NVIDIA
//!< 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.
- public override bool Equals(object obj) => obj is NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO other && this.Equals(other);
+ public override bool Equals(object obj) => obj is NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1 other && this.Equals(other);
- public bool Equals(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO other)
+ public bool Equals(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1 other)
=> Version == other.Version &&
Rotation == other.Rotation &&
Scaling == other.Scaling &&
@@ -1160,16 +1327,63 @@ namespace DisplayMagicianShared.NVIDIA
{
return (Version, Rotation, Scaling, RefreshRateInMillihertz, Flags, ConnectorType, TvFormat, TimingOverride, Timing).GetHashCode();
}
- public static bool operator ==(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO lhs, NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO rhs) => lhs.Equals(rhs);
+ public static bool operator ==(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1 lhs, NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1 rhs) => lhs.Equals(rhs);
- public static bool operator !=(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO lhs, NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO rhs) => !(lhs == rhs);
+ public static bool operator !=(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1 lhs, NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1 rhs) => !(lhs == rhs);
+
+ public object Clone()
+ {
+ NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1 other = (NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1)MemberwiseClone();
+ other.Timing = (NV_TIMING)Timing.Clone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 : IEquatable
+ public struct NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1_INTERNAL
+ {
+ public UInt32 Version;
+
+ // Rotation and Scaling
+ public NV_ROTATE Rotation; //!< (IN) rotation setting.
+ public NV_SCALING Scaling; //!< (IN) scaling setting.
+
+ // Refresh Rate
+ public UInt32 RefreshRateInMillihertz; //!< (IN) Non-Int32erlaced Refresh Rate of the mode, multiplied by 1000, 0 = ignored
+ //!< This is the value which driver reports to the OS.
+ // Flags
+ //public UInt32 Int32erlaced:1; //!< (IN) Interlaced mode flag, ignored if refreshRate == 0
+ //public UInt32 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 UInt32 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 UInt32 disableVirtualModeSupport:1;
+ //public UInt32 isPreferredUnscaledTarget:1;
+ //public UInt32 reserved:27;
+ public UInt32 Flags;
+ // TV format information
+ public NV_GPU_CONNECTOR_TYPE ConnectorType; //!< 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 IntPtr Timing; // Points to a NV_TIMING_INTERNAL object
+ //!< 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, Pack = 8)]
+ public struct NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 : IEquatable, ICloneable
{
public UInt32 DisplayId; //!< Display ID
- public NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO Details; //!< May be NULL if no advanced settings are required
+ public NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1 Details; //!< NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO - May be NULL if no advanced settings are required
public UInt32 WindowsCCDTargetId; //!< Windows CCD target ID. Must be present only for non-NVIDIA adapter, for NVIDIA adapter this parameter is ignored.
public override bool Equals(object obj) => obj is NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 other && this.Equals(other);
@@ -1186,13 +1400,21 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 lhs, NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 lhs, NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 rhs) => !(lhs == rhs);
+
+ public object Clone()
+ {
+ NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 otherTargetInfo = (NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2)MemberwiseClone();
+ otherTargetInfo.Details = (NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1)Details.Clone();
+ return otherTargetInfo;
+ }
}
+
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_DISPLAYCONFIG_PATH_TARGET_INFO_V1 : IEquatable
+ public struct NV_DISPLAYCONFIG_PATH_TARGET_INFO_V1 : IEquatable, ICloneable
{
public UInt32 DisplayId; //!< Display ID
- public NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO Details; //!< May be NULL if no advanced settings are required
+ public NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1 Details; //!< May be NULL if no advanced settings are required
public override bool Equals(object obj) => obj is NV_DISPLAYCONFIG_PATH_TARGET_INFO_V1 other && this.Equals(other);
@@ -1207,18 +1429,25 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_DISPLAYCONFIG_PATH_TARGET_INFO_V1 lhs, NV_DISPLAYCONFIG_PATH_TARGET_INFO_V1 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_DISPLAYCONFIG_PATH_TARGET_INFO_V1 lhs, NV_DISPLAYCONFIG_PATH_TARGET_INFO_V1 rhs) => !(lhs == rhs);
+
+ public object Clone()
+ {
+ NV_DISPLAYCONFIG_PATH_TARGET_INFO_V1 other = (NV_DISPLAYCONFIG_PATH_TARGET_INFO_V1)MemberwiseClone();
+ other.Details = (NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1)Details.Clone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_DISPLAYCONFIG_PATH_INFO_V2 : IEquatable // Version is 2
+ public struct NV_DISPLAYCONFIG_PATH_INFO_V2 : IEquatable, ICloneable // Version is 2
{
public UInt32 Version;
public UInt32 SourceId; //!< Identifies sourceId used by Windows CCD. This can be optionally set.
public UInt32 TargetInfoCount; //!< Number of elements in targetInfo array
//[MarshalAs(UnmanagedType.ByValArray)]
- public IntPtr TargetInfo;
- public IntPtr SourceModeInfo; //!< May be NULL if mode info is not important
+ 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 IntPtr SourceModeInfo; //!< May be NULL if mode info is not important
//public UInt32 IsNonNVIDIAAdapter : 1; //!< True for non-NVIDIA adapter.
//public UInt32 reserved : 31; //!< Must be 0
@@ -1235,7 +1464,7 @@ namespace DisplayMagicianShared.NVIDIA
=> Version == other.Version &&
SourceId == other.SourceId &&
TargetInfoCount == other.TargetInfoCount &&
- TargetInfo.Equals(other.TargetInfo) &&
+ TargetInfo.SequenceEqual(other.TargetInfo) &&
SourceModeInfo.Equals(other.SourceModeInfo) &&
Flags == other.Flags;
@@ -1246,10 +1475,50 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_DISPLAYCONFIG_PATH_INFO_V2 lhs, NV_DISPLAYCONFIG_PATH_INFO_V2 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_DISPLAYCONFIG_PATH_INFO_V2 lhs, NV_DISPLAYCONFIG_PATH_INFO_V2 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_DISPLAYCONFIG_PATH_INFO_V2 other = (NV_DISPLAYCONFIG_PATH_INFO_V2)MemberwiseClone();
+ other.TargetInfo = new NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2[TargetInfoCount];
+ for (int x = 0; x < (int)TargetInfoCount; x++)
+ {
+ other.TargetInfo[x] = (NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2)TargetInfo[x].Clone();
+ }
+ other.SourceModeInfo = (NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1)SourceModeInfo.Clone(); ;
+ return other;
+ }
}
+ [StructLayout(LayoutKind.Sequential, Pack = 8)]
+ public struct NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL // Version is 2 - This is for processing pass 2 only!
+ {
+ public UInt32 Version;
+ public UInt32 SourceId; //!< Identifies sourceId used by Windows CCD. This can be optionally set.
+ public UInt32 TargetInfoCount; //!< Number of elements in targetInfo array
+ public IntPtr TargetInfo;
+ public IntPtr SourceModeInfo; //!< May be NULL if mode info is not important
+ //public UInt32 IsNonNVIDIAAdapter : 1; //!< True for non-NVIDIA adapter.
+ //public UInt32 reserved : 31; //!< Must be 0
+ public UInt32 Flags;
+ //!< Used by Non-NVIDIA adapter for pointer to OS Adapter of LUID
+ //!< type, type casted to void *.
+ public IntPtr OSAdapterID;
+
+ public bool IsNonNVIDIAAdapter => Flags.GetBit(0); //!< if bit is set then this path uses a non-nvidia adapter
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 8)]
+ public struct NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2_INTERNAL
+ {
+ public UInt32 DisplayId; //!< Display ID
+ public IntPtr Details; // Points to an NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1_INTERNAL object
+ //!< NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO - May be NULL if no advanced settings are required
+ public UInt32 WindowsCCDTargetId; //!< 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_V1 : IEquatable // Version is 1
+ public struct NV_DISPLAYCONFIG_PATH_INFO_V1 : IEquatable, ICloneable // Version is 1
{
public UInt32 Version;
public UInt32 SourceId; //!< Identifies sourceId used by Windows CCD. This can be optionally set.
@@ -1269,7 +1538,7 @@ namespace DisplayMagicianShared.NVIDIA
=> Version == other.Version &&
SourceId == other.SourceId &&
TargetInfoCount == other.TargetInfoCount &&
- TargetInfo.Equals(other.TargetInfo) &&
+ TargetInfo.SequenceEqual(other.TargetInfo) &&
SourceModeInfo.Equals(other.SourceModeInfo);
public override Int32 GetHashCode()
@@ -1279,11 +1548,22 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_DISPLAYCONFIG_PATH_INFO_V1 lhs, NV_DISPLAYCONFIG_PATH_INFO_V1 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_DISPLAYCONFIG_PATH_INFO_V1 lhs, NV_DISPLAYCONFIG_PATH_INFO_V1 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_DISPLAYCONFIG_PATH_INFO_V2 other = (NV_DISPLAYCONFIG_PATH_INFO_V2)MemberwiseClone();
+ other.TargetInfo = new NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2[TargetInfoCount];
+ for (int x = 0; x < (int)TargetInfoCount; x++)
+ {
+ other.TargetInfo[x] = (NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2)TargetInfo[x].Clone();
+ }
+ other.SourceModeInfo = (NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1)SourceModeInfo.Clone(); ;
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 : IEquatable
+ public struct NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 : IEquatable, ICloneable
{
public NV_RESOLUTION Resolution;
public NV_FORMAT ColorFormat; //!< Ignored at present, must be NV_FORMAT_UNKNOWN (0)
@@ -1301,44 +1581,42 @@ namespace DisplayMagicianShared.NVIDIA
public bool Equals(NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 other)
=> Resolution.Equals(other.Resolution) &&
ColorFormat == other.ColorFormat &&
- Position.Equals(other.Position);
+ Position.Equals(other.Position) &&
+ Flags == other.Flags;
public override Int32 GetHashCode()
{
- return (Resolution, ColorFormat, Position).GetHashCode();
+ return (Resolution, ColorFormat, Position, Flags).GetHashCode();
}
public static bool operator ==(NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 lhs, NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 lhs, NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 rhs) => !(lhs == rhs);
- }
-
- [StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_DISPLAYCONFIG_PATH_TARGET_INFO : IEquatable
- {
- public UInt32 DisplayId; //!< Display ID
- public NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO Details; //!< May be NULL if no advanced settings are required
- public UInt32 TargetId; //!< Windows CCD target ID. Must be present only for non-NVIDIA adapter, for NVIDIA adapter this parameter is ignored.
-
- public override bool Equals(object obj) => obj is NV_DISPLAYCONFIG_PATH_TARGET_INFO other && this.Equals(other);
-
- public bool Equals(NV_DISPLAYCONFIG_PATH_TARGET_INFO other)
- => DisplayId == other.DisplayId &&
- Details.Equals(other.Details) &&
- TargetId == other.TargetId;
-
- public override Int32 GetHashCode()
+ public object Clone()
{
- return (DisplayId, Details, TargetId).GetHashCode();
+ NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 other = (NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1)MemberwiseClone();
+ other.Resolution = (NV_RESOLUTION)Resolution.Clone();
+ other.Position = (NV_POSITION)Position.Clone();
+ return other;
}
- public static bool operator ==(NV_DISPLAYCONFIG_PATH_TARGET_INFO lhs, NV_DISPLAYCONFIG_PATH_TARGET_INFO rhs) => lhs.Equals(rhs);
+ }
- public static bool operator !=(NV_DISPLAYCONFIG_PATH_TARGET_INFO lhs, NV_DISPLAYCONFIG_PATH_TARGET_INFO rhs) => !(lhs == rhs);
+ [StructLayout(LayoutKind.Sequential, Pack = 8)]
+ public struct NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1_INTERNAL
+ {
+ public IntPtr Resolution; // Points to a NV_RESOLUTION_INTERNAL object
+ public NV_FORMAT ColorFormat; //!< Ignored at present, must be NV_FORMAT_UNKNOWN (0)
+ public IntPtr Position; // Points to a NV_POSITION_INTERNAL object
+ //!< 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 UInt32 Flags;
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_MOSAIC_TOPO_BRIEF : IEquatable // Note: Version 1 of NV_MOSAIC_TOPO_BRIEF structure
+ public struct NV_MOSAIC_TOPO_BRIEF : IEquatable, ICloneable // Note: Version 1 of NV_MOSAIC_TOPO_BRIEF structure
{
public UInt32 Version; // Version of this structure - MUST BE SET TO 1
public NV_MOSAIC_TOPO Topo; //!< The topology
@@ -1364,6 +1642,11 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_MOSAIC_TOPO_BRIEF lhs, NV_MOSAIC_TOPO_BRIEF rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_MOSAIC_TOPO_BRIEF lhs, NV_MOSAIC_TOPO_BRIEF rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_MOSAIC_TOPO_BRIEF other = (NV_MOSAIC_TOPO_BRIEF)MemberwiseClone();
+ return other;
+ }
}
//
@@ -1384,7 +1667,7 @@ namespace DisplayMagicianShared.NVIDIA
//! You can then look at the detailed values within the structure. There are no
//! entrypoInt32s which take this structure as input (effectively making it read-only).
[StructLayout(LayoutKind.Sequential)]
- public struct NV_MOSAIC_TOPO_GROUP : IEquatable // Note: Version 1 of NV_MOSAIC_TOPO_GROUP structure
+ public struct NV_MOSAIC_TOPO_GROUP : IEquatable, ICloneable // Note: Version 1 of NV_MOSAIC_TOPO_GROUP structure
{
public UInt32 Version; // Version of this structure - MUST BE SET TO 1
public NV_MOSAIC_TOPO_BRIEF Brief; //!< The brief details of this topo
@@ -1407,11 +1690,22 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_MOSAIC_TOPO_GROUP lhs, NV_MOSAIC_TOPO_GROUP rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_MOSAIC_TOPO_GROUP lhs, NV_MOSAIC_TOPO_GROUP rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_MOSAIC_TOPO_GROUP other = (NV_MOSAIC_TOPO_GROUP)MemberwiseClone();
+ other.Brief = (NV_MOSAIC_TOPO_BRIEF)Brief.Clone();
+ other.Topos = new NV_MOSAIC_TOPO_DETAILS[Topos.Length];
+ for (int x = 0; x < (int)Topos.Length; x++)
+ {
+ other.Topos[x] = (NV_MOSAIC_TOPO_DETAILS)Topos[x].Clone();
+ }
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential)]
- public struct NV_MOSAIC_TOPO_DETAILS : IEquatable // Note: Version 1 of NV_MOSAIC_TOPO_DETAILS structure
+ public struct NV_MOSAIC_TOPO_DETAILS : IEquatable, ICloneable // Note: Version 1 of NV_MOSAIC_TOPO_DETAILS structure
{
public UInt32 Version; // Version of this structure - MUST BE SET TO 1
public LogicalGpuHandle LogicalGPUHandle; //!< Logical GPU for this topology
@@ -1478,10 +1772,31 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_MOSAIC_TOPO_DETAILS lhs, NV_MOSAIC_TOPO_DETAILS rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_MOSAIC_TOPO_DETAILS lhs, NV_MOSAIC_TOPO_DETAILS rhs) => !(lhs == rhs);
+
+ public object Clone()
+ {
+ NV_MOSAIC_TOPO_DETAILS other = (NV_MOSAIC_TOPO_DETAILS)MemberwiseClone();
+ other.LogicalGPUHandle = (LogicalGpuHandle)LogicalGPUHandle.Clone();
+ other.GPULayout1D = new NV_MOSAIC_TOPO_GPU_LAYOUT_CELL[GPULayout1D.Length];
+ for (int x = 0; x < (int)GPULayout1D.Length; x++)
+ {
+ other.GPULayout1D[x] = (NV_MOSAIC_TOPO_GPU_LAYOUT_CELL)GPULayout1D[x].Clone();
+ }
+
+ other.GPULayout = new NV_MOSAIC_TOPO_GPU_LAYOUT_CELL[GPULayout.GetLength(0), GPULayout.GetLength(1)];
+ for (int x = 0; x < (int)GPULayout.GetLength(0); x++)
+ {
+ for (int y = 0; y < (int)GPULayout.GetLength(1); y++)
+ {
+ other.GPULayout[x, y] = (NV_MOSAIC_TOPO_GPU_LAYOUT_CELL)GPULayout[x, y].Clone();
+ }
+ }
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_MOSAIC_TOPO_GPU_LAYOUT_CELL : IEquatable
+ public struct NV_MOSAIC_TOPO_GPU_LAYOUT_CELL : IEquatable, ICloneable
{
public PhysicalGpuHandle PhysicalGPUHandle; //!< Physical GPU to be used in the topology (0 if GPU missing) size is 8
public UInt32 DisplayOutputId; //!< Connected display target(0 if no display connected) size is 8
@@ -1503,10 +1818,16 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_MOSAIC_TOPO_GPU_LAYOUT_CELL lhs, NV_MOSAIC_TOPO_GPU_LAYOUT_CELL rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_MOSAIC_TOPO_GPU_LAYOUT_CELL lhs, NV_MOSAIC_TOPO_GPU_LAYOUT_CELL rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_MOSAIC_TOPO_GPU_LAYOUT_CELL other = (NV_MOSAIC_TOPO_GPU_LAYOUT_CELL)MemberwiseClone();
+ other.PhysicalGPUHandle = (PhysicalGpuHandle)PhysicalGPUHandle.Clone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_MOSAIC_DISPLAY_SETTING_V1 : IEquatable // Note: Version 1 of NV_MOSAIC_DISPLAY_SETTING structure
+ public struct NV_MOSAIC_DISPLAY_SETTING_V1 : IEquatable, ICloneable // Note: Version 1 of NV_MOSAIC_DISPLAY_SETTING structure
{
public UInt32 Version; // Version of this structure - MUST BE SET TO 1
public UInt32 Width; //!< Per-display width
@@ -1530,10 +1851,15 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_MOSAIC_DISPLAY_SETTING_V1 lhs, NV_MOSAIC_DISPLAY_SETTING_V1 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_MOSAIC_DISPLAY_SETTING_V1 lhs, NV_MOSAIC_DISPLAY_SETTING_V1 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_MOSAIC_DISPLAY_SETTING_V1 other = (NV_MOSAIC_DISPLAY_SETTING_V1)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_MOSAIC_DISPLAY_SETTING_V2 : IEquatable // Note: Version 2 of NV_MOSAIC_DISPLAY_SETTING structure
+ public struct NV_MOSAIC_DISPLAY_SETTING_V2 : IEquatable, ICloneable // Note: Version 2 of NV_MOSAIC_DISPLAY_SETTING structure
{
public UInt32 Version; // Version of this structure - MUST BE SET TO 2
public UInt32 Width; //!< Per-display width
@@ -1559,10 +1885,15 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_MOSAIC_DISPLAY_SETTING_V2 lhs, NV_MOSAIC_DISPLAY_SETTING_V2 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_MOSAIC_DISPLAY_SETTING_V2 lhs, NV_MOSAIC_DISPLAY_SETTING_V2 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_MOSAIC_DISPLAY_SETTING_V2 other = (NV_MOSAIC_DISPLAY_SETTING_V2)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_MOSAIC_GRID_TOPO_V1 : IEquatable // Note: Version 1 of NV_MOSAIC_GRID_TOPO structure
+ public struct NV_MOSAIC_GRID_TOPO_V1 : IEquatable, ICloneable // Note: Version 1 of NV_MOSAIC_GRID_TOPO structure
{
public UInt32 Version; // Version of this structure - MUST BE SET TO 1
public UInt32 Rows; //!< Per-display width
@@ -1597,10 +1928,21 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_MOSAIC_GRID_TOPO_V1 lhs, NV_MOSAIC_GRID_TOPO_V1 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_MOSAIC_GRID_TOPO_V1 lhs, NV_MOSAIC_GRID_TOPO_V1 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_MOSAIC_GRID_TOPO_V1 other = (NV_MOSAIC_GRID_TOPO_V1)MemberwiseClone();
+ other.DisplaySettings = (NV_MOSAIC_DISPLAY_SETTING_V1)DisplaySettings.Clone();
+ other.Displays = new NV_MOSAIC_GRID_TOPO_DISPLAY_V1[Displays.Length];
+ for (int x = 0; x < (int)Displays.Length; x++)
+ {
+ other.Displays[x] = (NV_MOSAIC_GRID_TOPO_DISPLAY_V1)Displays[x].Clone();
+ }
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_MOSAIC_GRID_TOPO_V2 : IEquatable // Note: Version 2 of NV_MOSAIC_GRID_TOPO structure
+ public struct NV_MOSAIC_GRID_TOPO_V2 : IEquatable, ICloneable // Note: Version 2 of NV_MOSAIC_GRID_TOPO structure
{
public UInt32 Version; // Version of this structure - MUST BE SET TO 2
public UInt32 Rows; //!< Per-display width
@@ -1636,10 +1978,21 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_MOSAIC_GRID_TOPO_V2 lhs, NV_MOSAIC_GRID_TOPO_V2 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_MOSAIC_GRID_TOPO_V2 lhs, NV_MOSAIC_GRID_TOPO_V2 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_MOSAIC_GRID_TOPO_V2 other = (NV_MOSAIC_GRID_TOPO_V2)MemberwiseClone();
+ other.DisplaySettings = (NV_MOSAIC_DISPLAY_SETTING_V1)DisplaySettings.Clone();
+ other.Displays = new NV_MOSAIC_GRID_TOPO_DISPLAY_V2[Displays.Length];
+ for (int x = 0; x < (int)Displays.Length; x++)
+ {
+ other.Displays[x] = (NV_MOSAIC_GRID_TOPO_DISPLAY_V2)Displays[x].Clone();
+ }
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_MOSAIC_GRID_TOPO_DISPLAY_V1 : IEquatable // Note: Version 1 of NV_MOSAIC_GRID_TOPO_DISPLAY structure
+ public struct NV_MOSAIC_GRID_TOPO_DISPLAY_V1 : IEquatable, ICloneable // Note: Version 1 of NV_MOSAIC_GRID_TOPO_DISPLAY structure
{
public UInt32 DisplayId; //!< DisplayID of the display
public Int32 OverlapX; //!< (+overlap, -gap)
@@ -1662,10 +2015,15 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_MOSAIC_GRID_TOPO_DISPLAY_V1 lhs, NV_MOSAIC_GRID_TOPO_DISPLAY_V1 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_MOSAIC_GRID_TOPO_DISPLAY_V1 lhs, NV_MOSAIC_GRID_TOPO_DISPLAY_V1 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_MOSAIC_GRID_TOPO_DISPLAY_V1 other = (NV_MOSAIC_GRID_TOPO_DISPLAY_V1)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_MOSAIC_GRID_TOPO_DISPLAY_V2 : IEquatable // Note: Version 2 of NV_MOSAIC_GRID_TOPO_DISPLAY structure
+ public struct NV_MOSAIC_GRID_TOPO_DISPLAY_V2 : IEquatable, ICloneable // Note: Version 2 of NV_MOSAIC_GRID_TOPO_DISPLAY structure
{
public UInt32 Version; // Version of this structure - MUST BE SET TO 2
public UInt32 DisplayId; //!< DisplayID of the display
@@ -1692,11 +2050,16 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_MOSAIC_GRID_TOPO_DISPLAY_V2 lhs, NV_MOSAIC_GRID_TOPO_DISPLAY_V2 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_MOSAIC_GRID_TOPO_DISPLAY_V2 lhs, NV_MOSAIC_GRID_TOPO_DISPLAY_V2 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_MOSAIC_GRID_TOPO_DISPLAY_V2 other = (NV_MOSAIC_GRID_TOPO_DISPLAY_V2)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_MOSAIC_SUPPORTED_TOPO_INFO_V1 : IEquatable // Note: Version 1 of NV_MOSAIC_SUPPORTED_TOPO_INFO structure
+ public struct NV_MOSAIC_SUPPORTED_TOPO_INFO_V1 : IEquatable, ICloneable // Note: Version 1 of NV_MOSAIC_SUPPORTED_TOPO_INFO structure
{
public UInt32 Version; // Version of this structure - MUST BE SET TO 1
public UInt32 TopoBriefsCount; //!< Number of topologies in below array
@@ -1722,10 +2085,25 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_MOSAIC_SUPPORTED_TOPO_INFO_V1 lhs, NV_MOSAIC_SUPPORTED_TOPO_INFO_V1 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_MOSAIC_SUPPORTED_TOPO_INFO_V1 lhs, NV_MOSAIC_SUPPORTED_TOPO_INFO_V1 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_MOSAIC_SUPPORTED_TOPO_INFO_V1 other = (NV_MOSAIC_SUPPORTED_TOPO_INFO_V1)MemberwiseClone();
+ other.TopoBriefs = new NV_MOSAIC_TOPO_BRIEF[TopoBriefs.Length];
+ for (int x = 0; x < (int)TopoBriefs.Length; x++)
+ {
+ other.TopoBriefs[x] = (NV_MOSAIC_TOPO_BRIEF)TopoBriefs[x].Clone();
+ }
+ other.DisplaySettings = new NV_MOSAIC_DISPLAY_SETTING_V1[DisplaySettings.Length];
+ for (int x = 0; x < (int)DisplaySettings.Length; x++)
+ {
+ other.DisplaySettings[x] = (NV_MOSAIC_DISPLAY_SETTING_V1)DisplaySettings[x].Clone();
+ }
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_MOSAIC_SUPPORTED_TOPO_INFO_V2 : IEquatable // Note: Version 2 of NV_MOSAIC_SUPPORTED_TOPO_INFO structure
+ public struct NV_MOSAIC_SUPPORTED_TOPO_INFO_V2 : IEquatable, ICloneable // Note: Version 2 of NV_MOSAIC_SUPPORTED_TOPO_INFO structure
{
public UInt32 Version; // Version of this structure - MUST BE SET TO 2
public UInt32 TopoBriefsCount; //!< Number of topologies in below array
@@ -1750,10 +2128,25 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_MOSAIC_SUPPORTED_TOPO_INFO_V2 lhs, NV_MOSAIC_SUPPORTED_TOPO_INFO_V2 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_MOSAIC_SUPPORTED_TOPO_INFO_V2 lhs, NV_MOSAIC_SUPPORTED_TOPO_INFO_V2 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_MOSAIC_SUPPORTED_TOPO_INFO_V2 other = (NV_MOSAIC_SUPPORTED_TOPO_INFO_V2)MemberwiseClone();
+ other.TopoBriefs = new NV_MOSAIC_TOPO_BRIEF[TopoBriefs.Length];
+ for (int x = 0; x < (int)TopoBriefs.Length; x++)
+ {
+ other.TopoBriefs[x] = (NV_MOSAIC_TOPO_BRIEF)TopoBriefs[x].Clone();
+ }
+ other.DisplaySettings = new NV_MOSAIC_DISPLAY_SETTING_V2[DisplaySettings.Length];
+ for (int x = 0; x < (int)DisplaySettings.Length; x++)
+ {
+ other.DisplaySettings[x] = (NV_MOSAIC_DISPLAY_SETTING_V2)DisplaySettings[x].Clone();
+ }
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_GPU_DISPLAYIDS_V2 : IEquatable // Note: Version 2 of NV_GPU_DISPLAYIDS_V2 structure
+ public struct NV_GPU_DISPLAYIDS_V2 : IEquatable, ICloneable // Note: Version 2 of NV_GPU_DISPLAYIDS_V2 structure
{
public UInt32 Version; // Version of this structure - MUST BE SET TO 2 (NOTE R470 contains a bug, and sets this to 3!)
public NV_MONITOR_CONN_TYPE ConnectorType; //!< out: vga, tv, dvi, hdmi and dp.This is reserved for future use and clients should not rely on this information.Instead get the
@@ -1787,11 +2180,16 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_GPU_DISPLAYIDS_V2 lhs, NV_GPU_DISPLAYIDS_V2 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_GPU_DISPLAYIDS_V2 lhs, NV_GPU_DISPLAYIDS_V2 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_GPU_DISPLAYIDS_V2 other = (NV_GPU_DISPLAYIDS_V2)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_MOSAIC_DISPLAY_TOPO_STATUS_V1 : IEquatable // Note: Version 1 of NV_MOSAIC_DISPLAY_TOPO_STATUS_V1 structure
+ public struct NV_MOSAIC_DISPLAY_TOPO_STATUS_V1 : IEquatable, ICloneable // Note: Version 1 of NV_MOSAIC_DISPLAY_TOPO_STATUS_V1 structure
{
public UInt32 Version;
public NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS ErrorFlags; //!< (OUT) Any of the NV_MOSAIC_DISPLAYTOPO_ERROR_* flags.
@@ -1816,10 +2214,20 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_MOSAIC_DISPLAY_TOPO_STATUS_V1 lhs, NV_MOSAIC_DISPLAY_TOPO_STATUS_V1 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_MOSAIC_DISPLAY_TOPO_STATUS_V1 lhs, NV_MOSAIC_DISPLAY_TOPO_STATUS_V1 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_MOSAIC_DISPLAY_TOPO_STATUS_V1 other = (NV_MOSAIC_DISPLAY_TOPO_STATUS_V1)MemberwiseClone();
+ other.Displays = new NV_MOSAIC_DISPLAY_TOPO_STATUS_DISPLAY[Displays.Length];
+ for (int x = 0; x < (int)Displays.Length; x++)
+ {
+ other.Displays[x] = (NV_MOSAIC_DISPLAY_TOPO_STATUS_DISPLAY)Displays[x].Clone();
+ }
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_MOSAIC_DISPLAY_TOPO_STATUS_DISPLAY : IEquatable
+ public struct NV_MOSAIC_DISPLAY_TOPO_STATUS_DISPLAY : IEquatable, ICloneable
{
public UInt32 DisplayId; //!< (OUT) The DisplayID of this display.
public NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS ErrorFlags; //!< (OUT) Any of the NV_MOSAIC_DISPLAYCAPS_PROBLEM_* flags.
@@ -1842,11 +2250,16 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_MOSAIC_DISPLAY_TOPO_STATUS_DISPLAY lhs, NV_MOSAIC_DISPLAY_TOPO_STATUS_DISPLAY rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_MOSAIC_DISPLAY_TOPO_STATUS_DISPLAY lhs, NV_MOSAIC_DISPLAY_TOPO_STATUS_DISPLAY rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_MOSAIC_DISPLAY_TOPO_STATUS_DISPLAY other = (NV_MOSAIC_DISPLAY_TOPO_STATUS_DISPLAY)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_HDR_CAPABILITIES_V2 : IEquatable // Note: Version 2 of NV_HDR_CAPABILITIES structure
+ public struct NV_HDR_CAPABILITIES_V2 : IEquatable, ICloneable // Note: Version 2 of NV_HDR_CAPABILITIES structure
{
public UInt32 Version; // Version of this structure - MUST BE SET TO 2
public NV_HDR_CAPABILITIES_V2_FLAGS SupportFlags; //!< Various flags indicating HDR support
@@ -1877,10 +2290,15 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_HDR_CAPABILITIES_V2 lhs, NV_HDR_CAPABILITIES_V2 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_HDR_CAPABILITIES_V2 lhs, NV_HDR_CAPABILITIES_V2 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_POSITION other = (NV_POSITION)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_HDR_DV_STATIC_METADATA : IEquatable
+ public struct NV_HDR_DV_STATIC_METADATA : IEquatable, ICloneable
{
public UInt32 Flags;
public UInt16 TargetMinLuminance;
@@ -1916,10 +2334,15 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_HDR_DV_STATIC_METADATA lhs, NV_HDR_DV_STATIC_METADATA rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_HDR_DV_STATIC_METADATA lhs, NV_HDR_DV_STATIC_METADATA rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_POSITION other = (NV_POSITION)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_HDR_CAPABILITIES_DISPLAY_DATA : IEquatable
+ public struct NV_HDR_CAPABILITIES_DISPLAY_DATA : IEquatable, ICloneable
{
public UInt16 DisplayPrimaryX0;
public UInt16 DisplayPrimaryY0;
@@ -1955,10 +2378,15 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_HDR_CAPABILITIES_DISPLAY_DATA lhs, NV_HDR_CAPABILITIES_DISPLAY_DATA rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_HDR_CAPABILITIES_DISPLAY_DATA lhs, NV_HDR_CAPABILITIES_DISPLAY_DATA rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_POSITION other = (NV_POSITION)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_HDR_COLOR_DATA_V2 : IEquatable
+ public struct NV_HDR_COLOR_DATA_V2 : IEquatable, ICloneable
{
public UInt32 Version; //!< Version of this structure
public NV_HDR_CMD Cmd; //!< Command get/set
@@ -1990,10 +2418,15 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_HDR_COLOR_DATA_V2 lhs, NV_HDR_COLOR_DATA_V2 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_HDR_COLOR_DATA_V2 lhs, NV_HDR_COLOR_DATA_V2 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_POSITION other = (NV_POSITION)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_HDR_COLOR_DISPLAY_DATA : IEquatable
+ public struct NV_HDR_COLOR_DISPLAY_DATA : IEquatable, ICloneable
{
public UInt16 DisplayPrimaryX0;
public UInt16 DisplayPrimaryY0;
@@ -2031,10 +2464,15 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_HDR_COLOR_DISPLAY_DATA lhs, NV_HDR_COLOR_DISPLAY_DATA rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_HDR_COLOR_DISPLAY_DATA lhs, NV_HDR_COLOR_DISPLAY_DATA rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_POSITION other = (NV_POSITION)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_COLOR_DATA_V5 : IEquatable
+ public struct NV_COLOR_DATA_V5 : IEquatable, ICloneable
{
public UInt32 Version; //!< Version of this structure
public UInt16 Size; //!< Size of this structure
@@ -2065,10 +2503,15 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_COLOR_DATA_V5 lhs, NV_COLOR_DATA_V5 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_COLOR_DATA_V5 lhs, NV_COLOR_DATA_V5 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_POSITION other = (NV_POSITION)MemberwiseClone();
+ return other;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
- public struct NV_CUSTOM_DISPLAY_V1 : IEquatable
+ public struct NV_CUSTOM_DISPLAY_V1 : IEquatable, ICloneable
{
public UInt32 Version; //!< Version of this structure
public UInt32 Width; //!< Source surface(source mode) width
@@ -2104,6 +2547,86 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator ==(NV_CUSTOM_DISPLAY_V1 lhs, NV_CUSTOM_DISPLAY_V1 rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_CUSTOM_DISPLAY_V1 lhs, NV_CUSTOM_DISPLAY_V1 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_POSITION other = (NV_POSITION)MemberwiseClone();
+ return other;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 8)]
+ public struct NV_GET_ADAPTIVE_SYNC_DATA_V1 : IEquatable, ICloneable
+ {
+ public UInt32 Version; // Must be V1
+ public UInt32 MaxFrameInterval; //!< maximum frame interval in micro seconds as set previously using NvAPI_DISP_SetAdaptiveSyncData function. If default values from EDID are used, this parameter returns 0.
+ public UInt32 Flags;
+ public UInt32 LastFlipRefreshCount; //!< Number of times the last flip was shown on the screen
+ public UInt64 LastFlipTimeStamp; //!< Timestamp for the lastest flip on the screen
+ public UInt32 ReservedEx1;
+ public UInt32 ReservedEx2;
+ public UInt32 ReservedEx3;
+ public UInt32 ReservedEx4;
+
+ public bool DisableAdaptiveSync => (Flags & 0x1) == 0x1; //!< Indicates if adaptive sync is disabled on the display.
+ public bool DisableFrameSplitting => (Flags & 0x1) == 0x1; //!< Indicates if frame splitting is disabled on the display.
+
+ public override bool Equals(object obj) => obj is NV_GET_ADAPTIVE_SYNC_DATA_V1 other && this.Equals(other);
+
+ public bool Equals(NV_GET_ADAPTIVE_SYNC_DATA_V1 other)
+ => MaxFrameInterval == other.MaxFrameInterval &&
+ Flags == other.Flags &&
+ LastFlipRefreshCount == other.LastFlipRefreshCount &&
+ LastFlipTimeStamp == other.LastFlipTimeStamp;
+
+ public override Int32 GetHashCode()
+ {
+ return (MaxFrameInterval, Flags, LastFlipRefreshCount, LastFlipTimeStamp).GetHashCode();
+ }
+ public static bool operator ==(NV_GET_ADAPTIVE_SYNC_DATA_V1 lhs, NV_GET_ADAPTIVE_SYNC_DATA_V1 rhs) => lhs.Equals(rhs);
+
+ public static bool operator !=(NV_GET_ADAPTIVE_SYNC_DATA_V1 lhs, NV_GET_ADAPTIVE_SYNC_DATA_V1 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_GET_ADAPTIVE_SYNC_DATA_V1 other = (NV_GET_ADAPTIVE_SYNC_DATA_V1)MemberwiseClone();
+ return other;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 8)]
+ public struct NV_SET_ADAPTIVE_SYNC_DATA_V1 : IEquatable, ICloneable
+ {
+ public UInt32 Version; // Must be V1
+ public UInt32 MaxFrameInterval; //!< maximum frame interval in micro seconds as set previously using NvAPI_DISP_SetAdaptiveSyncData function. If default values from EDID are used, this parameter returns 0.
+ public UInt32 Flags;
+ public UInt32 ReservedEx1; //!< Number of times the last flip was shown on the screen
+ public UInt64 ReservedEx2; //!< Timestamp for the lastest flip on the screen
+ public UInt32 ReservedEx3;
+ public UInt32 ReservedEx4;
+ public UInt32 ReservedEx5;
+ public UInt32 ReservedEx6;
+ public UInt32 ReservedEx7;
+
+ public bool DisableAdaptiveSync => (Flags & 0x1) == 0x1; //!< Indicates if adaptive sync is disabled on the display.
+ public bool DisableFrameSplitting => (Flags & 0x1) == 0x1; //!< Indicates if frame splitting is disabled on the display.
+
+ public override bool Equals(object obj) => obj is NV_SET_ADAPTIVE_SYNC_DATA_V1 other && this.Equals(other);
+
+ public bool Equals(NV_SET_ADAPTIVE_SYNC_DATA_V1 other)
+ => MaxFrameInterval == other.MaxFrameInterval &&
+ Flags == other.Flags;
+
+ public override Int32 GetHashCode()
+ {
+ return (MaxFrameInterval, Flags).GetHashCode();
+ }
+ public static bool operator ==(NV_SET_ADAPTIVE_SYNC_DATA_V1 lhs, NV_SET_ADAPTIVE_SYNC_DATA_V1 rhs) => lhs.Equals(rhs);
+
+ public static bool operator !=(NV_SET_ADAPTIVE_SYNC_DATA_V1 lhs, NV_SET_ADAPTIVE_SYNC_DATA_V1 rhs) => !(lhs == rhs);
+ public object Clone()
+ {
+ NV_SET_ADAPTIVE_SYNC_DATA_V1 other = (NV_SET_ADAPTIVE_SYNC_DATA_V1)MemberwiseClone();
+ return other;
+ }
}
// ==================================
@@ -2187,7 +2710,16 @@ namespace DisplayMagicianShared.NVIDIA
public static UInt32 NV_EDID_V3_VER = MAKE_NVAPI_VERSION(3);
public static UInt32 NV_DISPLAYCONFIG_PATH_INFO_V1_VER = MAKE_NVAPI_VERSION(1);
public static UInt32 NV_DISPLAYCONFIG_PATH_INFO_V2_VER = MAKE_NVAPI_VERSION(2);
+ public static UInt32 NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1_VER = MAKE_NVAPI_VERSION(1);
public static UInt32 NV_CUSTOM_DISPLAY_V1_VER = MAKE_NVAPI_VERSION(1);
+ public static UInt32 NV_LOGICAL_GPU_DATA_V1_VER = MAKE_NVAPI_VERSION(1);
+ public static UInt32 NV_GET_ADAPTIVE_SYNC_DATA_V1_VER = MAKE_NVAPI_VERSION(1);
+ public static UInt32 NV_SET_ADAPTIVE_SYNC_DATA_V1_VER = MAKE_NVAPI_VERSION(1);
+
+ public static UInt32 NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL_VER = MAKE_NVAPI_VERSION(2);
+ public static UInt32 NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1_INTERNAL_VER = MAKE_NVAPI_VERSION(1);
+
+
#region Internal Constant
@@ -2324,8 +2856,11 @@ namespace DisplayMagicianShared.NVIDIA
GetDelegate(NvId_Disp_ColorControl, out Disp_ColorControlInternal);
GetDelegate(NvId_DISP_GetDisplayConfig, out DISP_GetDisplayConfigInternal);
GetDelegate(NvId_DISP_GetDisplayConfig, out DISP_GetDisplayConfigInternalNull); // null version of the submission
+ GetDelegate(NvId_DISP_SetDisplayConfig, out DISP_SetDisplayConfigInternal);
GetDelegate(NvId_DISP_GetDisplayIdByDisplayName, out DISP_GetDisplayIdByDisplayNameInternal);
GetDelegate(NvId_DISP_EnumCustomDisplay, out Disp_EnumCustomDisplayInternal);
+ GetDelegate(NvId_DISP_GetAdaptiveSyncData, out DISP_GetAdaptiveSyncDataInternal);
+ GetDelegate(NvId_DISP_SetAdaptiveSyncData, out DISP_SetAdaptiveSyncDataInternal);
// GPUs
GetDelegate(NvId_EnumPhysicalGPUs, out EnumPhysicalGPUsInternal);
@@ -2337,6 +2872,9 @@ namespace DisplayMagicianShared.NVIDIA
GetDelegate(NvId_GPU_GetBusType, out GPU_GetBusTypeInternal);
GetDelegate(NvId_GPU_GetBusId, out GPU_GetBusIdInternal);
GetDelegate(NvId_GPU_GetEDID, out GPU_GetEDIDInternal);
+ GetDelegate(NvId_GPU_GetEDID, out GPU_GetEDIDInternal);
+ GetDelegate(NvId_GetLogicalGPUFromPhysicalGPU, out GetLogicalGPUFromPhysicalGPUInternal);
+ GetDelegate(NvId_GPU_GetLogicalGpuInfo, out GPU_GetLogicalGpuInfoInternal);
// Mosaic
GetDelegate(NvId_Mosaic_EnableCurrentTopo, out Mosaic_EnableCurrentTopoInternal);
@@ -3400,42 +3938,136 @@ namespace DisplayMagicianShared.NVIDIA
///
public static NVAPI_STATUS NvAPI_DISP_GetDisplayConfig(ref UInt32 PathInfoCount, ref NV_DISPLAYCONFIG_PATH_INFO_V2[] PathInfos, bool thirdPass = false)
{
- NVAPI_STATUS status;
- IntPtr pathInfoBuffer = IntPtr.Zero;
- IntPtr currentPathInfoBuffer = IntPtr.Zero;
+ NVAPI_STATUS status = NVAPI_STATUS.NVAPI_OK;
if (thirdPass)
{
- // Copy the supplied object for the third pass (when we have the pathInfoCount and the targetInfoCount for each pathInfo, but we want the details)
- // Third Pass(Optional, only required if target information is required): Allocate memory for targetInfo with respect
- //! to number of targetInfoCount(from Second Pass).
- NV_DISPLAYCONFIG_PATH_INFO_V2[] passedPathInfo = PathInfos;
- PathInfos = new NV_DISPLAYCONFIG_PATH_INFO_V2[PathInfoCount];
- // Go through the array and create the structure
- int overallTargetCount = 0;
+ NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL[] pass2PathInfos = new NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL[PathInfoCount];
+ int totalTargetInfoCount = 0;
for (Int32 x = 0; x < (Int32)PathInfoCount; x++)
{
- // Copy the information passed in, into the buffer we want to pass
-
- PathInfos[x].SourceId = passedPathInfo[x].SourceId;
- PathInfos[x].TargetInfoCount = passedPathInfo[x].TargetInfoCount;
- PathInfos[x].TargetInfo = passedPathInfo[x].TargetInfo;
- PathInfos[x].SourceModeInfo = passedPathInfo[x].SourceModeInfo;
- overallTargetCount += (int)PathInfos[x].TargetInfoCount;
- PathInfos[x].Version = MAKE_NVAPI_VERSION(Marshal.SizeOf(passedPathInfo[x]), 1);
+ totalTargetInfoCount += (int)PathInfos[x].TargetInfoCount;
}
- // Initialize unmanged memory to hold the unmanaged array of structs
- int memorySizeRequired = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_INFO_V2)) * (int)PathInfoCount;
- pathInfoBuffer = Marshal.AllocCoTaskMem(memorySizeRequired);
+
+ int onePathInfoMemSize = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL));
+ int oneSourceModeMemSize = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1));
+ int onePathTargetMemSize = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2));
+ int oneAdvTargetMemSize = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1));
+ IntPtr pathInfoPointer = Marshal.AllocHGlobal(onePathInfoMemSize * (int)PathInfoCount);
+ IntPtr sourceModeInfoPointer = Marshal.AllocHGlobal(oneSourceModeMemSize * (int)PathInfoCount);
+ IntPtr targetInfoPointer = Marshal.AllocHGlobal(onePathTargetMemSize * totalTargetInfoCount);
+ IntPtr advTargetPointer = Marshal.AllocHGlobal(oneAdvTargetMemSize * totalTargetInfoCount);
// Also set another memory pointer to the same place so that we can do the memory copying item by item
// as we have to do it ourselves (there isn't an easy to use Marshal equivalent)
- currentPathInfoBuffer = pathInfoBuffer;
- // Go through the array and copy things from managed code to unmanaged code
- for (Int32 x = 0; x < (Int32)PathInfoCount; x++)
+ IntPtr currentPathInfoPointer = pathInfoPointer;
+ IntPtr currentSourceModeInfoPointer = sourceModeInfoPointer;
+ IntPtr currentTargetInfoPointer = targetInfoPointer;
+ IntPtr currentAdvTargetPointer = advTargetPointer;
+
+ try
{
- // Marshal a single gridtopology into unmanaged code ready for sending to the unmanaged NVAPI function
- Marshal.StructureToPtr(PathInfos[x], currentPathInfoBuffer, false);
- // advance the buffer forwards to the next object
- currentPathInfoBuffer = (IntPtr)((long)currentPathInfoBuffer + Marshal.SizeOf(PathInfos[x]));
+ // Go through the array and copy things from managed code to unmanaged code
+ for (Int32 x = 0; x < (Int32)PathInfoCount; x++)
+ {
+ // Set up the fields in the path info
+ pass2PathInfos[x].Version = NVImport.NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL_VER;
+ pass2PathInfos[x].TargetInfoCount = PathInfos[x].TargetInfoCount;
+ pass2PathInfos[x].Flags = PathInfos[x].Flags;
+ pass2PathInfos[x].OSAdapterID = PathInfos[x].OSAdapterID;
+ pass2PathInfos[x].SourceId = PathInfos[x].SourceId;
+ // Create a target info array and copy it over
+ NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2_INTERNAL[] targetInforArray = new NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2_INTERNAL[PathInfos[x].TargetInfoCount];
+ pass2PathInfos[x].TargetInfo = currentTargetInfoPointer;
+ //for (Int32 y = 0; y < (Int32)PathInfos[x].TargetInfoCount; y++)
+ for (Int32 y = 0; y < (Int32)PathInfos[x].TargetInfoCount; y++)
+ {
+ NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1 advInfo = new NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1();
+ advInfo.Version = NVImport.NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1_VER;
+ Marshal.StructureToPtr(advInfo, currentAdvTargetPointer, true);
+ targetInforArray[y].Details = currentAdvTargetPointer;
+ Marshal.StructureToPtr(targetInforArray[y], currentTargetInfoPointer, true);
+ currentTargetInfoPointer = new IntPtr(currentTargetInfoPointer.ToInt64() + onePathTargetMemSize);
+ currentAdvTargetPointer = new IntPtr(currentAdvTargetPointer.ToInt64() + oneAdvTargetMemSize);
+ }
+
+ // Create a source mode info object and copy it over
+ NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 sourceModeInfo = (NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1)PathInfos[x].SourceModeInfo.Clone();
+ Marshal.StructureToPtr(sourceModeInfo, currentSourceModeInfoPointer, true);
+ pass2PathInfos[x].SourceModeInfo = currentSourceModeInfoPointer;
+
+ // Marshal a single gridtopology into unmanaged code ready for sending to the unmanaged NVAPI function
+ Marshal.StructureToPtr(pass2PathInfos[x], currentPathInfoPointer, true);
+
+ // advance the buffer forwards to the next object for each object
+ currentPathInfoPointer = new IntPtr(currentPathInfoPointer.ToInt64() + onePathInfoMemSize);
+ currentSourceModeInfoPointer = new IntPtr(currentSourceModeInfoPointer.ToInt64() + oneSourceModeMemSize);
+ }
+
+ if (DISP_GetDisplayConfigInternal != null)
+ {
+ // Use the unmanaged buffer in the unmanaged C call
+ status = DISP_GetDisplayConfigInternal(ref PathInfoCount, pathInfoPointer);
+
+ if (status == NVAPI_STATUS.NVAPI_OK)
+ {
+ // If everything worked, then copy the data back from the unmanaged array into the managed array
+ // So that we can use it in C# land
+ // Reset the memory pointer we're using for tracking where we are back to the start of the unmanaged memory buffer
+ currentPathInfoPointer = pathInfoPointer;
+ // Create a managed array to store the received information within
+ PathInfos = new NV_DISPLAYCONFIG_PATH_INFO_V2[PathInfoCount];
+ NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL[] returnedPass2PathInfos = new NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL[PathInfoCount];
+ // Go through the memory buffer item by item and copy the items into the managed array
+ for (int i = 0; i < PathInfoCount; i++)
+ {
+ // fill the returned pass2 array slot structure with the data from the buffer
+ // This lets us get the information and then copy it across to the one we want to return!
+ returnedPass2PathInfos[i] = (NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL)Marshal.PtrToStructure(currentPathInfoPointer, typeof(NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL));
+
+ // Next copy the information across to the PathInfo we actually want to return
+ PathInfos[i].SourceId = returnedPass2PathInfos[i].SourceId;
+ PathInfos[i].Flags = returnedPass2PathInfos[i].Flags;
+ PathInfos[i].OSAdapterID = returnedPass2PathInfos[i].OSAdapterID;
+ PathInfos[i].TargetInfoCount = returnedPass2PathInfos[i].TargetInfoCount;
+ PathInfos[i].TargetInfo = new NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2[PathInfos[i].TargetInfoCount];
+ PathInfos[i].Version = returnedPass2PathInfos[i].Version;
+
+ // And turn the memory pointer to NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 into an actual object and populate the object.
+ PathInfos[i].SourceModeInfo = (NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1)Marshal.PtrToStructure(returnedPass2PathInfos[i].SourceModeInfo, typeof(NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1));
+
+ currentTargetInfoPointer = returnedPass2PathInfos[i].TargetInfo;
+ for (Int32 y = 0; y < (Int32)PathInfos[i].TargetInfoCount; y++)
+ {
+ NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2_INTERNAL targetInfo;
+ NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1 targetInfoDetails;
+
+ // And turn the memory pointer to NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 into an actual object and populate the object.
+ targetInfo = (NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2_INTERNAL)Marshal.PtrToStructure(currentTargetInfoPointer, typeof(NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2_INTERNAL));
+ PathInfos[i].TargetInfo[y].DisplayId = targetInfo.DisplayId;
+ PathInfos[i].TargetInfo[y].WindowsCCDTargetId = targetInfo.WindowsCCDTargetId;
+
+ // Next we need to get access to the details object.
+ targetInfoDetails = (NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1)Marshal.PtrToStructure(targetInfo.Details, typeof(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1));
+ PathInfos[i].TargetInfo[y].Details = targetInfoDetails;
+ currentTargetInfoPointer = new IntPtr(currentTargetInfoPointer.ToInt64() + onePathTargetMemSize);
+
+ }
+
+ // advance the buffer forwards to the next object
+ currentPathInfoPointer = (IntPtr)((long)currentPathInfoPointer + Marshal.SizeOf(returnedPass2PathInfos[i]));
+ }
+ }
+ }
+ else
+ {
+ status = NVAPI_STATUS.NVAPI_FUNCTION_NOT_FOUND;
+ }
+ }
+ finally
+ {
+ Marshal.FreeCoTaskMem(pathInfoPointer);
+ Marshal.FreeCoTaskMem(sourceModeInfoPointer);
+ Marshal.FreeCoTaskMem(targetInfoPointer);
+ Marshal.FreeCoTaskMem(advTargetPointer);
}
}
@@ -3446,80 +4078,92 @@ namespace DisplayMagicianShared.NVIDIA
// targetInfoCount. If sourceModeInfo is needed allocate memory or it can be initialized to NULL.
// Build a new blank object for the second pass (when we have the pathInfoCount, but want the targetInfoCount for each pathInfo)
// Build a managed structure for us to use as a data source for another object that the unmanaged NVAPI C library can use
- PathInfos = new NV_DISPLAYCONFIG_PATH_INFO_V2[PathInfoCount];
- // Prepare the struct for second pass duties
- for (Int32 x = 0; x < (Int32)PathInfoCount; x++)
- {
- NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 sourceMode = new NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1();
- IntPtr sourceModeBuffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1)));
- Marshal.StructureToPtr(sourceMode, sourceModeBuffer, true);
- PathInfos[x].Version = NVImport.NV_DISPLAYCONFIG_PATH_INFO_V2_VER;
- PathInfos[x].SourceModeInfo = sourceModeBuffer;
- /*PathInfos[x].SourceModeInfo.Resolution = new NV_RESOLUTION();
- PathInfos[x].SourceModeInfo.Position = new NV_POSITION();
- //PathInfos[x].SourceModeInfo = null;
- PathInfos[x].TargetInfoCount = 0;
- PathInfos[x].TargetInfo = IntPtr.Zero;
- //!< This field is reserved. There is ongoing debate if we need this field.
- //!< Identifies sourceIds used by Windows. If all sourceIds are 0,
- //!< these will be computed automatically.
- PathInfos[x].SourceId = 0;
- PathInfos[x].Flags = 0;
- PathInfos[x].OSAdapterID = new NV_LUID();
- //PathInfos[x].OSAdapterID = IntPtr.Zero;*/
- }
- // Initialize unmanged memory to hold the unmanaged array of structs
- int sizeOfOneStruct = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_INFO_V2));
- int sizeOfAllStructs = sizeOfOneStruct * (int)PathInfoCount;
- //int sizeOfOneStruct = Marshal.SizeOf(PathInfos);
- pathInfoBuffer = Marshal.AllocCoTaskMem(sizeOfAllStructs);
+ NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL[] pass2PathInfos = new NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL[PathInfoCount];
+
+ int onePathInfoMemSize = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL));
+ int oneSourceModeMemSize = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1));
+ IntPtr pathInfoPointer = Marshal.AllocHGlobal(onePathInfoMemSize * (int)PathInfoCount);
+ IntPtr sourceModeInfoPointer = Marshal.AllocHGlobal(oneSourceModeMemSize * (int)PathInfoCount);
// Also set another memory pointer to the same place so that we can do the memory copying item by item
// as we have to do it ourselves (there isn't an easy to use Marshal equivalent)
- currentPathInfoBuffer = pathInfoBuffer;
- // Go through the array and copy things from managed code to unmanaged code
- for (Int32 x = 0; x < (Int32)PathInfoCount; x++)
+ IntPtr currentPathInfoPointer = pathInfoPointer;
+ IntPtr currentSourceModeInfoPointer = sourceModeInfoPointer;
+
+ try
{
- // Marshal a single gridtopology into unmanaged code ready for sending to the unmanaged NVAPI function
- Marshal.StructureToPtr(PathInfos[x], currentPathInfoBuffer, true);
- // advance the buffer forwards to the next object
- currentPathInfoBuffer = (IntPtr)((long)currentPathInfoBuffer.ToInt64() + Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2)));
- }
- }
-
-
- if (DISP_GetDisplayConfigInternal != null)
- {
- // Use the unmanaged buffer in the unmanaged C call
- status = DISP_GetDisplayConfigInternal(ref PathInfoCount, pathInfoBuffer);
-
- if (status == NVAPI_STATUS.NVAPI_OK)
- {
- // If everything worked, then copy the data back from the unmanaged array into the managed array
- // So that we can use it in C# land
- // Reset the memory pointer we're using for tracking where we are back to the start of the unmanaged memory buffer
- currentPathInfoBuffer = pathInfoBuffer;
- // Create a managed array to store the received information within
- PathInfos = new NV_DISPLAYCONFIG_PATH_INFO_V2[PathInfoCount];
- // Go through the memory buffer item by item and copy the items into the managed array
- for (int i = 0; i < PathInfoCount; i++)
+ // Go through the array and copy things from managed code to unmanaged code
+ for (Int32 x = 0; x < (Int32)PathInfoCount; x++)
{
- // build a structure in the array slot
- PathInfos[i] = new NV_DISPLAYCONFIG_PATH_INFO_V2();
- // fill the array slot structure with the data from the buffer
- PathInfos[i] = (NV_DISPLAYCONFIG_PATH_INFO_V2)Marshal.PtrToStructure(currentPathInfoBuffer, typeof(NV_DISPLAYCONFIG_PATH_INFO_V2));
- // destroy the bit of memory we no longer need
- Marshal.DestroyStructure(currentPathInfoBuffer, typeof(NV_DISPLAYCONFIG_PATH_INFO_V2));
- // advance the buffer forwards to the next object
- currentPathInfoBuffer = (IntPtr)((long)currentPathInfoBuffer + Marshal.SizeOf(PathInfos[i]));
+ // Set up the fields in the path info
+ pass2PathInfos[x].Version = NVImport.NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL_VER;
+ pass2PathInfos[x].TargetInfoCount = 0;
+ pass2PathInfos[x].TargetInfo = IntPtr.Zero;
+
+ // Create a source mode info object and copy it over
+ NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 sourceModeInfo = new NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1();
+ Marshal.StructureToPtr(sourceModeInfo, currentSourceModeInfoPointer, true);
+ pass2PathInfos[x].SourceModeInfo = currentSourceModeInfoPointer;
+
+ // Marshal a single gridtopology into unmanaged code ready for sending to the unmanaged NVAPI function
+ Marshal.StructureToPtr(pass2PathInfos[x], currentPathInfoPointer, true);
+
+ // advance the buffer forwards to the next object for each object
+ //currentPathInfoPointer = new IntPtr(currentPathInfoPointer.ToInt64() + onePathInfoMemSize + oneSourceModeMemSize);
+ currentPathInfoPointer = new IntPtr(currentPathInfoPointer.ToInt64() + onePathInfoMemSize);
+ currentSourceModeInfoPointer = new IntPtr(currentSourceModeInfoPointer.ToInt64() + oneSourceModeMemSize);
+ }
+
+ if (DISP_GetDisplayConfigInternal != null)
+ {
+ // Use the unmanaged buffer in the unmanaged C call
+ status = DISP_GetDisplayConfigInternal(ref PathInfoCount, pathInfoPointer);
+
+ if (status == NVAPI_STATUS.NVAPI_OK)
+ {
+ // If everything worked, then copy the data back from the unmanaged array into the managed array
+ // So that we can use it in C# land
+ // Reset the memory pointer we're using for tracking where we are back to the start of the unmanaged memory buffer
+ currentPathInfoPointer = pathInfoPointer;
+ // Create a managed array to store the received information within
+ PathInfos = new NV_DISPLAYCONFIG_PATH_INFO_V2[PathInfoCount];
+ NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL[] returnedPass2PathInfos = new NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL[PathInfoCount];
+ // Go through the memory buffer item by item and copy the items into the managed array
+ for (int i = 0; i < PathInfoCount; i++)
+ {
+ // fill the returned pass2 array slot structure with the data from the buffer
+ // This lets us get the information and then copy it across to the one we want to return!
+ returnedPass2PathInfos[i] = (NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL)Marshal.PtrToStructure(currentPathInfoPointer, typeof(NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL));
+
+ // Next copy the information across to the PathInfo we actually want to return
+ PathInfos[i].SourceId = returnedPass2PathInfos[i].SourceId;
+ PathInfos[i].Flags = returnedPass2PathInfos[i].Flags;
+ PathInfos[i].OSAdapterID = returnedPass2PathInfos[i].OSAdapterID;
+ PathInfos[i].TargetInfo = new NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2[0];
+ PathInfos[i].TargetInfoCount = returnedPass2PathInfos[i].TargetInfoCount;
+ PathInfos[i].Version = returnedPass2PathInfos[i].Version;
+
+ // And turn the memory pointer to NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 into an actual object and populate the object.
+ PathInfos[i].SourceModeInfo = (NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1)Marshal.PtrToStructure(returnedPass2PathInfos[i].SourceModeInfo, typeof(NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1));
+
+ // destroy the bit of memory we no longer need
+ //Marshal.DestroyStructure(currentPathInfoPointer, typeof(NV_DISPLAYCONFIG_PATH_INFO_V2));
+ // advance the buffer forwards to the next object
+ currentPathInfoPointer = (IntPtr)((long)currentPathInfoPointer + Marshal.SizeOf(returnedPass2PathInfos[i]));
+ }
+ }
+ }
+ else
+ {
+ status = NVAPI_STATUS.NVAPI_FUNCTION_NOT_FOUND;
}
}
- }
- else
- {
- status = NVAPI_STATUS.NVAPI_FUNCTION_NOT_FOUND;
- }
+ finally
+ {
+ Marshal.FreeCoTaskMem(pathInfoPointer);
+ Marshal.FreeCoTaskMem(sourceModeInfoPointer);
+ }
- Marshal.FreeCoTaskMem(pathInfoBuffer);
+ }
return status;
}
@@ -3554,6 +4198,137 @@ namespace DisplayMagicianShared.NVIDIA
return status;
}
+ // ******** IMPORTANT! This code has an error when attempting to perform the third pass as required by NVAPI documentation *********
+ // ******** FOr this reason I have disabled the code as I don't actually need to get it going. ********
+ // NVAPI_INTERFACE NvAPI_DISP_SetDisplayConfig ( __in NvU32 pathInfoCount, __in_ecount(pathInfoCount) NV_DISPLAYCONFIG_PATH_INFO* pathInfo,__in NvU32 flags )
+ private delegate NVAPI_STATUS DISP_SetDisplayConfigDelegate(
+ [In] UInt32 pathInfoCount,
+ [In] IntPtr pathInfoBuffer,
+ [In] NV_DISPLAYCONFIG_FLAGS flags);
+ private static readonly DISP_SetDisplayConfigDelegate DISP_SetDisplayConfigInternal;
+
+ ///
+ /// DESCRIPTION: This API lets caller apply a global display configuration across multiple GPUs.
+ /// If all sourceIds are zero, then NvAPI will pick up sourceId's based on the following criteria :
+ /// If user provides sourceModeInfo then we are trying to assign 0th sourceId always to GDIPrimary.This is needed since active windows always moves along with 0th sourceId.
+ /// For rest of the paths, we are incrementally assigning the sourceId per adapter basis.
+ /// If user doesn't provide sourceModeInfo then NVAPI just picks up some default sourceId's in incremental order. Note : NVAPI will not intelligently choose the sourceIDs for any configs that does not need a modeset.
+ /// SUPPORTED OS: Windows 7 and higher
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static NVAPI_STATUS NvAPI_DISP_SetDisplayConfig(UInt32 pathInfoCount, NV_DISPLAYCONFIG_PATH_INFO_V2[] pathInfos, NV_DISPLAYCONFIG_FLAGS flags)
+ {
+ NVAPI_STATUS status = NVAPI_STATUS.NVAPI_OK;
+ NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL[] pass2PathInfos = new NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL[pathInfoCount];
+
+ int totalTargetInfoCount = 0;
+ for (Int32 x = 0; x < (Int32)pathInfoCount; x++)
+ {
+ totalTargetInfoCount += (int)pathInfos[x].TargetInfoCount;
+ }
+
+ int onePathInfoMemSize = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL));
+ int oneSourceModeMemSize = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1));
+ int onePathTargetMemSize = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2_INTERNAL));
+ int oneAdvTargetMemSize = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1));
+
+ IntPtr pathInfoPointer = Marshal.AllocCoTaskMem(onePathInfoMemSize * (int)pathInfoCount);
+ IntPtr sourceModeInfoPointer = Marshal.AllocCoTaskMem(oneSourceModeMemSize * (int)pathInfoCount);
+ IntPtr targetInfoPointer = Marshal.AllocCoTaskMem(onePathTargetMemSize * totalTargetInfoCount);
+ IntPtr advTargetPointer = Marshal.AllocCoTaskMem(oneAdvTargetMemSize * totalTargetInfoCount);
+
+ // Also set another memory pointer to the same place so that we can do the memory copying item by item
+ // as we have to do it ourselves (there isn't an easy to use Marshal equivalent)
+ IntPtr currentPathInfoPointer = pathInfoPointer;
+ IntPtr currentSourceModeInfoPointer = sourceModeInfoPointer;
+ IntPtr currentTargetInfoPointer = targetInfoPointer;
+ IntPtr currentAdvTargetPointer = advTargetPointer;
+
+ // Go through the array and copy things from managed code to unmanaged code
+ for (Int32 x = 0; x < (Int32)pathInfoCount; x++)
+ {
+ // Create a target info array and copy it over
+ NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2_INTERNAL[] targetInfoArray = new NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2_INTERNAL[pathInfos[x].TargetInfoCount];
+ pass2PathInfos[x].TargetInfo = currentTargetInfoPointer;
+ for (Int32 y = 0; y < (Int32)pathInfos[x].TargetInfoCount; y++)
+ {
+
+ NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1 advInfo = new NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1();
+ advInfo.ConnectorType = pathInfos[x].TargetInfo[y].Details.ConnectorType;
+ advInfo.Flags = pathInfos[x].TargetInfo[y].Details.Flags;
+ advInfo.RefreshRateInMillihertz = pathInfos[x].TargetInfo[y].Details.RefreshRateInMillihertz;
+ advInfo.Rotation = pathInfos[x].TargetInfo[y].Details.Rotation;
+ advInfo.Scaling = pathInfos[x].TargetInfo[y].Details.Scaling;
+ advInfo.Timing = (NV_TIMING)pathInfos[x].TargetInfo[y].Details.Timing.Clone();
+ advInfo.TimingOverride = pathInfos[x].TargetInfo[y].Details.TimingOverride;
+ advInfo.TvFormat = pathInfos[x].TargetInfo[y].Details.TvFormat;
+ //advInfo.Version = NVImport.NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1_INTERNAL_VER;
+ advInfo.Version = NVImport.NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1_VER;
+ Marshal.StructureToPtr(advInfo, currentAdvTargetPointer, true);
+
+ // Fill in this target info array item
+ targetInfoArray[y].Details = currentAdvTargetPointer;
+ targetInfoArray[y].DisplayId = pathInfos[x].TargetInfo[y].DisplayId;
+ targetInfoArray[y].WindowsCCDTargetId = pathInfos[x].TargetInfo[y].WindowsCCDTargetId;
+ Marshal.StructureToPtr(targetInfoArray[y], currentTargetInfoPointer, true);
+
+ // Prepare the pointers for the next objects
+ currentTargetInfoPointer = new IntPtr(currentTargetInfoPointer.ToInt64() + onePathTargetMemSize);
+ currentAdvTargetPointer = new IntPtr(currentAdvTargetPointer.ToInt64() + oneAdvTargetMemSize);
+ }
+
+
+ // Create a source mode info object and copy it over
+ NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 sourceModeInfo = new NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1();
+ sourceModeInfo.ColorFormat = pathInfos[x].SourceModeInfo.ColorFormat;
+ sourceModeInfo.Flags = pathInfos[x].SourceModeInfo.Flags;
+ sourceModeInfo.Position = (NV_POSITION)pathInfos[x].SourceModeInfo.Position.Clone();
+ sourceModeInfo.Resolution = (NV_RESOLUTION)pathInfos[x].SourceModeInfo.Resolution.Clone();
+ sourceModeInfo.SpanningOrientation = pathInfos[x].SourceModeInfo.SpanningOrientation;
+ Marshal.StructureToPtr(sourceModeInfo, currentSourceModeInfoPointer, true);
+
+ // Set up the fields in the path info
+ pass2PathInfos[x].Version = NVImport.NV_DISPLAYCONFIG_PATH_INFO_V2_INTERNAL_VER;
+ pass2PathInfos[x].TargetInfoCount = pathInfos[x].TargetInfoCount;
+ pass2PathInfos[x].Flags = pathInfos[x].Flags;
+ pass2PathInfos[x].OSAdapterID = pathInfos[x].OSAdapterID;
+ pass2PathInfos[x].SourceId = pathInfos[x].SourceId;
+ pass2PathInfos[x].SourceModeInfo = currentSourceModeInfoPointer;
+
+ // Marshal a single gridtopology into unmanaged code ready for sending to the unmanaged NVAPI function
+ Marshal.StructureToPtr(pass2PathInfos[x], currentPathInfoPointer, true);
+
+ // advance the buffer forwards to the next object for each object
+ currentPathInfoPointer = new IntPtr(currentPathInfoPointer.ToInt64() + onePathInfoMemSize);
+ currentSourceModeInfoPointer = new IntPtr(currentSourceModeInfoPointer.ToInt64() + oneSourceModeMemSize);
+ }
+
+ if (DISP_SetDisplayConfigInternal != null)
+ {
+ // Use the unmanaged buffer in the unmanaged C call
+ status = DISP_SetDisplayConfigInternal(pathInfoCount, pathInfoPointer, 0);
+ }
+ else
+ {
+ status = NVAPI_STATUS.NVAPI_FUNCTION_NOT_FOUND;
+ }
+
+ Marshal.FreeCoTaskMem(pathInfoPointer);
+ Marshal.FreeCoTaskMem(sourceModeInfoPointer);
+ Marshal.FreeCoTaskMem(targetInfoPointer);
+ Marshal.FreeCoTaskMem(advTargetPointer);
+ //Marshal.FreeCoTaskMem(timingPointer);
+ //Marshal.FreeCoTaskMem(timingExtraPointer);
+ //Marshal.FreeCoTaskMem(positionPointer);
+ //Marshal.FreeCoTaskMem(resolutionPointer);
+
+ return status;
+ }
+
+
// NVAPI_INTERFACE NvAPI_DISP_GetDisplayIdByDisplayName(const char *displayName, NvU32* displayId);
private delegate NVAPI_STATUS DISP_GetDisplayIdByDisplayNameDelegate(
@@ -3657,7 +4432,7 @@ namespace DisplayMagicianShared.NVIDIA
// Build a managed structure for us to use as a data source for another object that the unmanaged NVAPI C library can use
displaySettings = new NV_MOSAIC_DISPLAY_SETTING_V2[displayCount];
// Initialize unmanged memory to hold the unmanaged array of structs
- IntPtr displaySettingsBuffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(NV_MOSAIC_DISPLAY_SETTING_V2)) * (int)displayCount);
+ IntPtr displaySettingsBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NV_MOSAIC_DISPLAY_SETTING_V2)) * (int)displayCount);
// Also set another memory pointer to the same place so that we can do the memory copying item by item
// as we have to do it ourselves (there isn't an easy to use Marshal equivalent)
IntPtr currentDisplaySettingsBuffer = displaySettingsBuffer;
@@ -3761,7 +4536,7 @@ namespace DisplayMagicianShared.NVIDIA
// Build a managed structure for us to use as a data source for another object that the unmanaged NVAPI C library can use
GridTopologies = new NV_MOSAIC_GRID_TOPO_V2[GridCount];
// Initialize unmanged memory to hold the unmanaged array of structs
- IntPtr gridTopologiesBuffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(NV_MOSAIC_GRID_TOPO_V2)) * (int)GridCount);
+ IntPtr gridTopologiesBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NV_MOSAIC_GRID_TOPO_V2)) * (int)GridCount);
// Also set another memory pointer to the same place so that we can do the memory copying item by item
// as we have to do it ourselves (there isn't an easy to use Marshal equivalent)
IntPtr currentGridTopologiesBuffer = gridTopologiesBuffer;
@@ -3867,7 +4642,7 @@ namespace DisplayMagicianShared.NVIDIA
// Warning! - This function still has some errors with it. It errors with an NVAPI_INCOMPATIBLE_STRUCT_VERSION error. Still needs troubleshooting.
NVAPI_STATUS status;
// Initialize unmanged memory to hold the unmanaged array of structs
- IntPtr gridTopologiesBuffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(NV_MOSAIC_GRID_TOPO_V2)) * (int)gridCount);
+ IntPtr gridTopologiesBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NV_MOSAIC_GRID_TOPO_V2)) * (int)gridCount);
// Also set another memory pointer to the same place so that we can do the memory copying item by item
// as we have to do it ourselves (there isn't an easy to use Marshal equivalent)
IntPtr currentGridTopologiesBuffer = gridTopologiesBuffer;
@@ -3882,7 +4657,7 @@ namespace DisplayMagicianShared.NVIDIA
// Build a managed structure for us to use as a data source for another object that the unmanaged NVAPI C library can use
topoStatuses = new NV_MOSAIC_DISPLAY_TOPO_STATUS_V1[gridCount];
// Initialize unmanged memory to hold the unmanaged array of structs
- IntPtr topoStatusesBuffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(NV_MOSAIC_DISPLAY_TOPO_STATUS_V1)) * (int)gridCount);
+ IntPtr topoStatusesBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NV_MOSAIC_DISPLAY_TOPO_STATUS_V1)) * (int)gridCount);
// Also set another memory pointer to the same place so that we can do the memory copying item by item
// as we have to do it ourselves (there isn't an easy to use Marshal equivalent)
IntPtr currentTopoStatusesBuffer = topoStatusesBuffer;
@@ -3958,7 +4733,7 @@ namespace DisplayMagicianShared.NVIDIA
NVAPI_STATUS status;
// Initialize unmanged memory to hold the unmanaged array of structs
- IntPtr gridTopologiesBuffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(NV_MOSAIC_GRID_TOPO_V2)) * (int)GridCount);
+ IntPtr gridTopologiesBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NV_MOSAIC_GRID_TOPO_V2)) * (int)GridCount);
// Also set another memory pointer to the same place so that we can do the memory copying item by item
// as we have to do it ourselves (there isn't an easy to use Marshal equivalent)
IntPtr currentGridTopologiesBuffer = gridTopologiesBuffer;
@@ -4215,6 +4990,47 @@ namespace DisplayMagicianShared.NVIDIA
return status;
}
+ //NVAPI_INTERFACE NvAPI_DISP_GetAdaptiveSyncData (__in NvU32 displayId, __inout NV_GET_ADAPTIVE_SYNC_DATA *pAdaptiveSyncData)
+ private delegate NVAPI_STATUS DISP_GetAdaptiveSyncDataDelegate(
+ [In] UInt32 displayId,
+ [In, Out] ref NV_GET_ADAPTIVE_SYNC_DATA_V1 adaptiveSyncData);
+ private static readonly DISP_GetAdaptiveSyncDataDelegate DISP_GetAdaptiveSyncDataInternal;
+ ///
+ /// This function is used to get data for the Adaptive Sync Display.
+ ///
+ ///
+ ///
+ ///
+ public static NVAPI_STATUS NvAPI_DISP_GetAdaptiveSyncData(UInt32 displayId, ref NV_GET_ADAPTIVE_SYNC_DATA_V1 adaptiveSyncData)
+ {
+ NVAPI_STATUS status = NVAPI_STATUS.NVAPI_ERROR;
+ if (DISP_GetAdaptiveSyncDataInternal != null) { status = DISP_GetAdaptiveSyncDataInternal(displayId, ref adaptiveSyncData); }
+ else { status = NVAPI_STATUS.NVAPI_FUNCTION_NOT_FOUND; }
+
+ return status;
+ }
+
+ //NVAPI_INTERFACE NvAPI_DISP_SetAdaptiveSyncData (__in NvU32 displayId, __in NV_SET_ADAPTIVE_SYNC_DATA *pAdaptiveSyncData)
+ private delegate NVAPI_STATUS DISP_SetAdaptiveSyncDataDelegate(
+ [In] UInt32 displayId,
+ [In] ref NV_SET_ADAPTIVE_SYNC_DATA_V1 adaptiveSyncData);
+ private static readonly DISP_SetAdaptiveSyncDataDelegate DISP_SetAdaptiveSyncDataInternal;
+ ///
+ /// This function is used to set data for Adaptive Sync Display.
+ ///
+ ///
+ ///
+ ///
+ public static NVAPI_STATUS NvAPI_DISP_SetAdaptiveSyncData(UInt32 displayId, ref NV_SET_ADAPTIVE_SYNC_DATA_V1 adaptiveSyncData)
+ {
+ NVAPI_STATUS status = NVAPI_STATUS.NVAPI_ERROR;
+ if (DISP_SetAdaptiveSyncDataInternal != null) { status = DISP_SetAdaptiveSyncDataInternal(displayId, ref adaptiveSyncData); }
+ else { status = NVAPI_STATUS.NVAPI_FUNCTION_NOT_FOUND; }
+
+ return status;
+ }
+
+
//NVAPI_INTERFACE NvAPI_DISP_GetGDIPrimaryDisplayId(NvU32* displayId);
private delegate NVAPI_STATUS DISP_GetGDIPrimaryDisplayIdDelegate(
[Out] out UInt32 displayId);
@@ -4264,7 +5080,7 @@ namespace DisplayMagicianShared.NVIDIA
// Build a managed structure for us to use as a data source for another object that the unmanaged NVAPI C library can use
displayIds = new NV_GPU_DISPLAYIDS_V2[displayCount];
// Initialize unmanged memory to hold the unmanaged array of structs
- IntPtr displayIdBuffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(NV_GPU_DISPLAYIDS_V2)) * (int)displayCount);
+ IntPtr displayIdBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NV_GPU_DISPLAYIDS_V2)) * (int)displayCount);
// Also set another memory pointer to the same place so that we can do the memory copying item by item
// as we have to do it ourselves (there isn't an easy to use Marshal equivalent)
IntPtr currentDisplayIdBuffer = displayIdBuffer;
@@ -4582,5 +5398,61 @@ namespace DisplayMagicianShared.NVIDIA
return status;
}
+
+ //NVAPI_INTERFACE NvAPI_GPU_GetLogicalGpuInfo(__in NvLogicalGpuHandle hLogicalGpu, __inout NV_LOGICAL_GPU_DATA * pLogicalGpuData)
+ private delegate NVAPI_STATUS GPU_GetLogicalGpuInfoDelegate(
+ [In] LogicalGpuHandle gpuHandle,
+ [In][Out] ref NV_LOGICAL_GPU_DATA_V1 logicalGPUData);
+ private static readonly GPU_GetLogicalGpuInfoDelegate GPU_GetLogicalGpuInfoInternal;
+ ///
+ /// This function is used to query Logical GPU information.
+ /// SUPPORTED OS: Windows 7 and higher
+ ///
+ ///
+ ///
+ public static NVAPI_STATUS NvAPI_GPU_GetLogicalGpuInfo(LogicalGpuHandle gpuHandle, ref NV_LOGICAL_GPU_DATA_V1 logicalGPUData)
+ {
+ NVAPI_STATUS status;
+
+ logicalGPUData = new NV_LOGICAL_GPU_DATA_V1();
+ logicalGPUData.Version = NVImport.NV_LOGICAL_GPU_DATA_V1_VER;
+ logicalGPUData.OSAdapterId = IntPtr.Zero;
+ logicalGPUData.PhysicalGPUHandles = new PhysicalGpuHandle[(int)NVImport.NVAPI_MAX_PHYSICAL_GPUS];
+
+ if (GPU_GetEDIDInternal != null) { status = GPU_GetLogicalGpuInfoInternal(gpuHandle, ref logicalGPUData); }
+ else { status = NVAPI_STATUS.NVAPI_FUNCTION_NOT_FOUND; }
+
+ return status;
+ }
+
+ //NVAPI_INTERFACE NvAPI_GetLogicalGPUFromPhysicalGPU(NvPhysicalGpuHandle hPhysicalGPU, NvLogicalGpuHandle* pLogicalGPU)
+ private delegate NVAPI_STATUS GetLogicalGPUFromPhysicalGPUDelegate(
+ [In] PhysicalGpuHandle physicalGPUHandle,
+ [Out] out LogicalGpuHandle logicalGPUHandle);
+ private static readonly GetLogicalGPUFromPhysicalGPUDelegate GetLogicalGPUFromPhysicalGPUInternal;
+ ///
+ /// This function is used to query Logical GPU information.
+ /// SUPPORTED OS: Windows 7 and higher
+ ///
+ ///
+ ///
+ public static NVAPI_STATUS NvAPI_GetLogicalGPUFromPhysicalGPU(PhysicalGpuHandle physicalGPUHandle, out LogicalGpuHandle logicalGPUHandle)
+ {
+ NVAPI_STATUS status;
+
+ if (GPU_GetEDIDInternal != null)
+ {
+ status = GetLogicalGPUFromPhysicalGPUInternal(physicalGPUHandle, out LogicalGpuHandle lgpu);
+ logicalGPUHandle = lgpu;
+ }
+ else
+ {
+ status = NVAPI_STATUS.NVAPI_FUNCTION_NOT_FOUND;
+ logicalGPUHandle = new LogicalGpuHandle();
+ }
+
+ return status;
+ }
+
}
}
\ No newline at end of file
diff --git a/DisplayMagicianShared/NVIDIA/NVIDIALibrary.cs b/DisplayMagicianShared/NVIDIA/NVIDIALibrary.cs
index e364538..1fb6b6a 100644
--- a/DisplayMagicianShared/NVIDIA/NVIDIALibrary.cs
+++ b/DisplayMagicianShared/NVIDIA/NVIDIALibrary.cs
@@ -50,44 +50,40 @@ namespace DisplayMagicianShared.NVIDIA
}
[StructLayout(LayoutKind.Sequential)]
- public struct NVIDIA_HDR_CONFIG : IEquatable
+ public struct NVIDIA_PER_DISPLAY_CONFIG : IEquatable
{
- public Dictionary HdrCapabilities;
- public Dictionary HdrColorData;
- public bool IsNvHdrEnabled;
+ public bool HasNvHdrEnabled;
+ public NV_HDR_CAPABILITIES_V2 HdrCapabilities;
+ public NV_HDR_COLOR_DATA_V2 HdrColorData;
+ public bool HasAdaptiveSync;
+ public NV_SET_ADAPTIVE_SYNC_DATA_V1 AdaptiveSyncConfig;
+ public bool HasColorData;
+ public NV_COLOR_DATA_V5 ColorData;
+ public bool HasCustomDisplay;
+ public List CustomDisplays;
- public override bool Equals(object obj) => obj is NVIDIA_HDR_CONFIG other && this.Equals(other);
- public bool Equals(NVIDIA_HDR_CONFIG other)
- => HdrCapabilities.SequenceEqual(other.HdrCapabilities) &&
- HdrColorData.SequenceEqual(other.HdrColorData) &&
- IsNvHdrEnabled == other.IsNvHdrEnabled;
+
+ public override bool Equals(object obj) => obj is NVIDIA_PER_DISPLAY_CONFIG other && this.Equals(other);
+ public bool Equals(NVIDIA_PER_DISPLAY_CONFIG other)
+ => HasNvHdrEnabled == other.HasNvHdrEnabled &&
+ HdrCapabilities.Equals(other.HdrCapabilities) &&
+ HdrColorData.Equals(other.HdrColorData) &&
+ HasAdaptiveSync == other.HasAdaptiveSync &&
+ AdaptiveSyncConfig.Equals(other.AdaptiveSyncConfig) &&
+ HasColorData == other.HasColorData &&
+ ColorData.Equals(other.ColorData) &&
+ HasCustomDisplay == other.HasCustomDisplay &&
+ CustomDisplays.SequenceEqual(other.CustomDisplays);
public override int GetHashCode()
{
- return (HdrCapabilities, HdrColorData, IsNvHdrEnabled).GetHashCode();
+ return (HasNvHdrEnabled, HdrCapabilities, HdrColorData, HasAdaptiveSync, AdaptiveSyncConfig, HasColorData, ColorData, HasCustomDisplay, CustomDisplays).GetHashCode();
}
- public static bool operator ==(NVIDIA_HDR_CONFIG lhs, NVIDIA_HDR_CONFIG rhs) => lhs.Equals(rhs);
+ public static bool operator ==(NVIDIA_PER_DISPLAY_CONFIG lhs, NVIDIA_PER_DISPLAY_CONFIG rhs) => lhs.Equals(rhs);
- public static bool operator !=(NVIDIA_HDR_CONFIG lhs, NVIDIA_HDR_CONFIG rhs) => !(lhs == rhs);
+ public static bool operator !=(NVIDIA_PER_DISPLAY_CONFIG lhs, NVIDIA_PER_DISPLAY_CONFIG rhs) => !(lhs == rhs);
}
- [StructLayout(LayoutKind.Sequential)]
- public struct NVIDIA_COLOR_CONFIG : IEquatable
- {
- public Dictionary ColorData;
-
- public override bool Equals(object obj) => obj is NVIDIA_COLOR_CONFIG other && this.Equals(other);
- public bool Equals(NVIDIA_COLOR_CONFIG other)
- => ColorData.SequenceEqual(other.ColorData);
-
- public override int GetHashCode()
- {
- return (ColorData).GetHashCode();
- }
- public static bool operator ==(NVIDIA_COLOR_CONFIG lhs, NVIDIA_COLOR_CONFIG rhs) => lhs.Equals(rhs);
-
- public static bool operator !=(NVIDIA_COLOR_CONFIG lhs, NVIDIA_COLOR_CONFIG rhs) => !(lhs == rhs);
- }
/*[StructLayout(LayoutKind.Sequential)]
public struct NVIDIA_CUSTOM_DISPLAY_CONFIG : IEquatable
@@ -107,13 +103,38 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator !=(NVIDIA_CUSTOM_DISPLAY_CONFIG lhs, NVIDIA_CUSTOM_DISPLAY_CONFIG rhs) => !(lhs == rhs);
}*/
+ [StructLayout(LayoutKind.Sequential)]
+ public struct NVIDIA_PER_ADAPTER_CONFIG : IEquatable
+ {
+ public bool IsQuadro;
+ public bool HasLogicalGPU;
+ public NV_LOGICAL_GPU_DATA_V1 LogicalGPU;
+ public UInt32 DisplayCount;
+ public Dictionary Displays;
+
+ public override bool Equals(object obj) => obj is NVIDIA_PER_ADAPTER_CONFIG other && this.Equals(other);
+ public bool Equals(NVIDIA_PER_ADAPTER_CONFIG other)
+ => IsQuadro == other.IsQuadro &&
+ HasLogicalGPU == other.HasLogicalGPU &&
+ LogicalGPU.Equals(other.LogicalGPU) &&
+ DisplayCount == other.DisplayCount &&
+ Displays.SequenceEqual(other.Displays);
+
+ public override int GetHashCode()
+ {
+ return (IsQuadro, HasLogicalGPU, LogicalGPU, DisplayCount, Displays).GetHashCode();
+ }
+ public static bool operator ==(NVIDIA_PER_ADAPTER_CONFIG lhs, NVIDIA_PER_ADAPTER_CONFIG rhs) => lhs.Equals(rhs);
+
+ public static bool operator !=(NVIDIA_PER_ADAPTER_CONFIG lhs, NVIDIA_PER_ADAPTER_CONFIG rhs) => !(lhs == rhs);
+ }
+
[StructLayout(LayoutKind.Sequential)]
public struct NVIDIA_DISPLAY_CONFIG : IEquatable
{
+ public bool IsCloned;
public NVIDIA_MOSAIC_CONFIG MosaicConfig;
- public NVIDIA_HDR_CONFIG HdrConfig;
- public NVIDIA_COLOR_CONFIG ColorConfig;
- public Dictionary> CustomDisplays;
+ public Dictionary PhysicalAdapters;
public List DisplayConfigs;
// Note: We purposely have left out the DisplayNames from the Equals as it's order keeps changing after each reboot and after each profile swap
// and it is informational only and doesn't contribute to the configuration (it's used for generating the Screens structure, and therefore for
@@ -124,16 +145,16 @@ namespace DisplayMagicianShared.NVIDIA
public override bool Equals(object obj) => obj is NVIDIA_DISPLAY_CONFIG other && this.Equals(other);
public bool Equals(NVIDIA_DISPLAY_CONFIG other)
- => MosaicConfig.Equals(other.MosaicConfig) &&
- HdrConfig.Equals(other.HdrConfig) &&
- ColorConfig.Equals(other.ColorConfig) &&
- CustomDisplays.SequenceEqual(other.CustomDisplays) &&
- DisplayConfigs.SequenceEqual(other.DisplayConfigs) &&
- DisplayIdentifiers.SequenceEqual(other.DisplayIdentifiers);
+ => IsCloned == other.IsCloned &&
+ PhysicalAdapters.SequenceEqual(other.PhysicalAdapters) &&
+ MosaicConfig.Equals(other.MosaicConfig) &&
+ DisplayConfigs.SequenceEqual(other.DisplayConfigs) &&
+ DisplayIdentifiers.SequenceEqual(other.DisplayIdentifiers);
+
public override int GetHashCode()
{
- return (MosaicConfig, HdrConfig, CustomDisplays, DisplayConfigs, DisplayIdentifiers, DisplayNames).GetHashCode();
+ return (IsCloned, MosaicConfig, PhysicalAdapters, DisplayConfigs, DisplayIdentifiers, DisplayNames).GetHashCode();
}
public static bool operator ==(NVIDIA_DISPLAY_CONFIG lhs, NVIDIA_DISPLAY_CONFIG rhs) => lhs.Equals(rhs);
@@ -161,6 +182,15 @@ namespace DisplayMagicianShared.NVIDIA
static NVIDIALibrary() { }
public NVIDIALibrary()
{
+ // Populate the list of ConnectionTypes we want to skip as they don't support querying
+ SkippedColorConnectionTypes = new List {
+ NV_MONITOR_CONN_TYPE.VGA,
+ NV_MONITOR_CONN_TYPE.COMPONENT,
+ NV_MONITOR_CONN_TYPE.SVIDEO,
+ NV_MONITOR_CONN_TYPE.DVI,
+ NV_MONITOR_CONN_TYPE.COMPOSITE,
+ };
+
_activeDisplayConfig = CreateDefaultConfig();
try
{
@@ -199,15 +229,6 @@ namespace DisplayMagicianShared.NVIDIA
SharedLogger.logger.Info(ex, $"NVIDIALibrary/NVIDIALibrary: Exception trying to load the NVIDIA NVAPI DLL. This generally means you don't have the NVIDIA driver installed.");
}
- // Populate the list of ConnectionTypes we want to skip as they don't support querying
- SkippedColorConnectionTypes = new List {
- NV_MONITOR_CONN_TYPE.VGA,
- NV_MONITOR_CONN_TYPE.COMPONENT,
- NV_MONITOR_CONN_TYPE.SVIDEO,
- NV_MONITOR_CONN_TYPE.DVI,
- NV_MONITOR_CONN_TYPE.COMPOSITE,
- };
-
}
~NVIDIALibrary()
@@ -282,15 +303,14 @@ namespace DisplayMagicianShared.NVIDIA
// Fill in the minimal amount we need to avoid null references
// so that we won't break json.net when we save a default config
+ myDefaultConfig.MosaicConfig.IsMosaicEnabled = false;
myDefaultConfig.MosaicConfig.MosaicGridTopos = new NV_MOSAIC_GRID_TOPO_V2[0];
myDefaultConfig.MosaicConfig.MosaicViewports = new List();
- myDefaultConfig.HdrConfig.HdrCapabilities = new Dictionary();
- myDefaultConfig.HdrConfig.HdrColorData = new Dictionary();
- myDefaultConfig.ColorConfig.ColorData = new Dictionary();
- myDefaultConfig.CustomDisplays = new Dictionary>();
+ myDefaultConfig.PhysicalAdapters = new Dictionary();
myDefaultConfig.DisplayConfigs = new List();
myDefaultConfig.DisplayNames = new Dictionary();
myDefaultConfig.DisplayIdentifiers = new List();
+ myDefaultConfig.IsCloned = false;
return myDefaultConfig;
}
@@ -320,10 +340,14 @@ namespace DisplayMagicianShared.NVIDIA
private NVIDIA_DISPLAY_CONFIG GetNVIDIADisplayConfig(bool allDisplays = false)
{
- NVIDIA_DISPLAY_CONFIG myDisplayConfig = new NVIDIA_DISPLAY_CONFIG();
+ NVIDIA_DISPLAY_CONFIG myDisplayConfig = CreateDefaultConfig();
if (_initialised)
{
+
+ // Store all the found display IDs so we can use them later
+ List foundDisplayIds = new List();
+
// Enumerate all the Physical GPUs
PhysicalGpuHandle[] physicalGpus = new PhysicalGpuHandle[NVImport.NVAPI_MAX_PHYSICAL_GPUS];
uint physicalGpuCount = 0;
@@ -340,6 +364,13 @@ namespace DisplayMagicianShared.NVIDIA
// Go through the Physical GPUs one by one
for (uint physicalGpuIndex = 0; physicalGpuIndex < physicalGpuCount; physicalGpuIndex++)
{
+ // Prepare the physicalGPU per adapter structure to use later
+ NVIDIA_PER_ADAPTER_CONFIG myAdapter = new NVIDIA_PER_ADAPTER_CONFIG();
+ myAdapter.LogicalGPU.PhysicalGPUHandles = new PhysicalGpuHandle[0];
+ myAdapter.IsQuadro = false;
+ myAdapter.HasLogicalGPU = false;
+ myAdapter.Displays = new Dictionary();
+
//This function retrieves the Quadro status for the GPU (1 if Quadro, 0 if GeForce)
uint quadroStatus = 0;
NVStatus = NVImport.NvAPI_GPU_GetQuadroStatus(physicalGpus[physicalGpuIndex], out quadroStatus);
@@ -352,6 +383,7 @@ namespace DisplayMagicianShared.NVIDIA
else if (quadroStatus == 1)
{
SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NVIDIA Video Card is one from the Quadro range");
+ myAdapter.IsQuadro = true;
}
else
{
@@ -362,6 +394,36 @@ namespace DisplayMagicianShared.NVIDIA
{
SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Error getting Quadro status. NvAPI_GPU_GetQuadroStatus() returned error code {NVStatus}");
}
+
+ // Firstly let's get the logical GPU from the Physical handle
+ LogicalGpuHandle logicalGPUHandle;
+ NVStatus = NVImport.NvAPI_GetLogicalGPUFromPhysicalGPU(physicalGpus[physicalGpuIndex], out logicalGPUHandle);
+ if (NVStatus == NVAPI_STATUS.NVAPI_OK)
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Successfully got Logical GPU Handle from physical GPU.");
+ NV_LOGICAL_GPU_DATA_V1 logicalGPUData = new NV_LOGICAL_GPU_DATA_V1();
+ NVStatus = NVImport.NvAPI_GPU_GetLogicalGpuInfo(logicalGPUHandle, ref logicalGPUData);
+ if (NVStatus == NVAPI_STATUS.NVAPI_OK)
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Successfully got the Logical GPU information from the NVIDIA driver!");
+ myAdapter.HasLogicalGPU = true;
+ myAdapter.LogicalGPU = logicalGPUData;
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_POINTER)
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: No Logical GPU found so no logicalGPUData available. NvAPI_GPU_GetLogicalGpuInfo() returned error code {NVStatus}");
+ }
+ else
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Error getting Logical GPU information from NVIDIA driver. NvAPI_GPU_GetLogicalGpuInfo() returned error code {NVStatus}");
+ }
+ }
+ else
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Error getting Logical GPU handle from Physical GPU. NvAPI_GetLogicalGPUFromPhysicalGPU() returned error code {NVStatus}");
+ }
+
+ myDisplayConfig.PhysicalAdapters[physicalGpuIndex] = myAdapter;
}
// Get current Supported Mosaic Topology info (check whether Mosaic is on)
@@ -573,7 +635,7 @@ namespace DisplayMagicianShared.NVIDIA
{
SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_Mosaic_EnumDisplayGrids() returned error code {NVStatus}");
}
-
+
myDisplayConfig.MosaicConfig.MosaicGridTopos = mosaicGridTopos;
myDisplayConfig.MosaicConfig.MosaicGridCount = mosaicGridCount;
@@ -700,9 +762,7 @@ namespace DisplayMagicianShared.NVIDIA
//! to number of targetInfoCount(from Second Pass).
//! SUPPORTED OS: Windows 7 and higher
// First pass: Figure out how many pathInfo objects there are
- List allDisplayConfigs = new List();
-
- /*uint pathInfoCount = 0;
+ uint pathInfoCount = 0;
NVStatus = NVImport.NvAPI_DISP_GetDisplayConfig(ref pathInfoCount);
if (NVStatus == NVAPI_STATUS.NVAPI_OK && pathInfoCount > 0)
{
@@ -717,6 +777,19 @@ namespace DisplayMagicianShared.NVIDIA
NVStatus = NVImport.NvAPI_DISP_GetDisplayConfig(ref pathInfoCount, ref pathInfos, true);
if (NVStatus == NVAPI_STATUS.NVAPI_OK)
{
+ SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_DISP_GetDisplayConfig returned OK on third and final pass.");
+ // If this worked, we need to check for and handle cloned displays if there are any
+ // They need to be set in a special way (see DisplayConfiguration.cpp from the DisplayConfiguration sample from NVIDIA)
+ for (int x = 0; x < pathInfoCount; x++)
+ {
+ if (pathInfos[x].TargetInfoCount > 1)
+ {
+ // This is a cloned display, we need to mark this NVIDIA display profile as cloned so we correct the profile later
+ myDisplayConfig.IsCloned = true;
+ }
+ }
+
+ myDisplayConfig.DisplayConfigs = pathInfos.ToList();
SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_DISP_GetDisplayConfig returned OK on third pass.");
}
else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED)
@@ -739,6 +812,10 @@ namespace DisplayMagicianShared.NVIDIA
{
SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: ModeSet has not yet completed. Please wait and call it again. NvAPI_DISP_GetDisplayConfig() returned error code {NVStatus} on third pass.");
}
+ else if (NVStatus == NVAPI_STATUS.NVAPI_INCOMPATIBLE_STRUCT_VERSION)
+ {
+ SharedLogger.logger.Error($"NVIDIALibrary/GetNVIDIADisplayConfig: The version of the structure passed in is not compatible with this entrypoint. NvAPI_DISP_GetDisplayConfig() returned error code {NVStatus} on third pass.");
+ }
else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR)
{
SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_DISP_GetDisplayConfig() returned error code {NVStatus} on third pass.");
@@ -768,6 +845,10 @@ namespace DisplayMagicianShared.NVIDIA
{
SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: ModeSet has not yet completed. Please wait and call it again. NvAPI_DISP_GetDisplayConfig() returned error code {NVStatus} on second pass.");
}
+ else if (NVStatus == NVAPI_STATUS.NVAPI_INCOMPATIBLE_STRUCT_VERSION)
+ {
+ SharedLogger.logger.Error($"NVIDIALibrary/GetNVIDIADisplayConfig: The version of the structure passed in is not compatible with this entrypoint. NvAPI_DISP_GetDisplayConfig() returned error code {NVStatus} on second pass.");
+ }
else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR)
{
SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_DISP_GetDisplayConfig() returned error code {NVStatus} on second pass.");
@@ -775,7 +856,7 @@ namespace DisplayMagicianShared.NVIDIA
else
{
SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting NVIDIA Display Config! NvAPI_DISP_GetDisplayConfig() returned error code {NVStatus} on second pass.");
- }
+ }
}
else if (NVStatus == NVAPI_STATUS.NVAPI_OK && pathInfoCount == 0)
@@ -798,6 +879,10 @@ namespace DisplayMagicianShared.NVIDIA
{
SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: ModeSet has not yet completed. Please wait and call it again. NvAPI_DISP_GetDisplayConfig() returned error code {NVStatus} on first pass");
}
+ else if (NVStatus == NVAPI_STATUS.NVAPI_INCOMPATIBLE_STRUCT_VERSION)
+ {
+ SharedLogger.logger.Error($"NVIDIALibrary/GetNVIDIADisplayConfig: The version of the structure passed in is not compatible with this entrypoint. NvAPI_DISP_GetDisplayConfig() returned error code {NVStatus} on first pass.");
+ }
else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR)
{
SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_DISP_GetDisplayConfig() returned error code {NVStatus} on first pass");
@@ -805,7 +890,7 @@ namespace DisplayMagicianShared.NVIDIA
else
{
SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting NVIDIA Display Config! NvAPI_DISP_GetDisplayConfig() returned error code {NVStatus} on first pass");
- }*/
+ }
// We want to get the primary monitor
NVStatus = NVImport.NvAPI_DISP_GetGDIPrimaryDisplayId(out UInt32 primaryDisplayId);
@@ -843,6 +928,12 @@ namespace DisplayMagicianShared.NVIDIA
// Go through the Physical GPUs one by one
for (uint physicalGpuIndex = 0; physicalGpuIndex < physicalGpuCount; physicalGpuIndex++)
{
+
+ // Get a new variable to the PhysicalAdapters to make easier to use
+ // NOTE: This struct was filled in earlier by code further up
+ NVIDIA_PER_ADAPTER_CONFIG myAdapter = myDisplayConfig.PhysicalAdapters[physicalGpuIndex];
+ myAdapter.Displays = new Dictionary();
+
//This function retrieves the number of display IDs we know about
UInt32 displayCount = 0;
NVStatus = NVImport.NvAPI_GPU_GetConnectedDisplayIds(physicalGpus[physicalGpuIndex], ref displayCount, 0);
@@ -882,7 +973,7 @@ namespace DisplayMagicianShared.NVIDIA
NVStatus = NVImport.NvAPI_GPU_GetConnectedDisplayIds(physicalGpus[physicalGpuIndex], ref displayIds, ref displayCount, 0);
if (NVStatus == NVAPI_STATUS.NVAPI_OK)
{
- SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_GPU_GetConnectedDisplayIds returned OK on second pass. We have {displayCount} physical GPUs");
+ SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_GPU_GetConnectedDisplayIds returned OK on second pass. We have {displayCount} physical displays");
}
else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER)
{
@@ -912,10 +1003,6 @@ namespace DisplayMagicianShared.NVIDIA
// Time to get the color settings, HDR capabilities and settings for each display
bool isNvHdrEnabled = false;
- Dictionary allHdrCapabilities = new Dictionary();
- Dictionary allHdrColorData = new Dictionary();
- Dictionary allColorData = new Dictionary();
- Dictionary> allCustomDisplays = new Dictionary>();
for (int displayIndex = 0; displayIndex < displayCount; displayIndex++)
{
if (allDisplays)
@@ -935,6 +1022,20 @@ namespace DisplayMagicianShared.NVIDIA
}
}
+ // Record this as an active display ID
+ foundDisplayIds.Add(displayIds[displayIndex].DisplayId);
+
+ // Prepare the config structure for us to fill it in
+ NVIDIA_PER_DISPLAY_CONFIG myDisplay = new NVIDIA_PER_DISPLAY_CONFIG();
+ myDisplay.ColorData = new NV_COLOR_DATA_V5();
+ myDisplay.HdrColorData = new NV_HDR_COLOR_DATA_V2();
+ myDisplay.HdrCapabilities = new NV_HDR_CAPABILITIES_V2();
+ myDisplay.AdaptiveSyncConfig = new NV_SET_ADAPTIVE_SYNC_DATA_V1();
+ myDisplay.CustomDisplays = new List();
+ myDisplay.HasNvHdrEnabled = false;
+ myDisplay.HasAdaptiveSync = false;
+ myDisplay.HasCustomDisplay = false;
+
// We need to skip recording anything that doesn't support color communication
if (!SkippedColorConnectionTypes.Contains(displayIds[displayIndex].ConnectorType))
{
@@ -947,7 +1048,8 @@ namespace DisplayMagicianShared.NVIDIA
if (NVStatus == NVAPI_STATUS.NVAPI_OK)
{
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Your monitor {displayIds[displayIndex].DisplayId} has the following color settings set. BPC = {colorData.Bpc.ToString("G")}. Color Format = {colorData.ColorFormat.ToString("G")}. Colorimetry = {colorData.Colorimetry.ToString("G")}. Color Selection Policy = {colorData.ColorSelectionPolicy.ToString("G")}. Color Depth = {colorData.Depth.ToString("G")}. Dynamic Range = {colorData.DynamicRange.ToString("G")}. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
- allColorData.Add(displayIds[displayIndex].DisplayId.ToString(), colorData);
+ myDisplay.ColorData = colorData;
+ myDisplay.HasColorData = true;
}
else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER)
{
@@ -1034,7 +1136,7 @@ namespace DisplayMagicianShared.NVIDIA
SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Display {displayIds[displayIndex].DisplayId} DOES NOT support Driver Expanded Default HDR Parameters ");
}
- allHdrCapabilities.Add(displayIds[displayIndex].DisplayId.ToString(), hdrCapabilities);
+ myDisplay.HdrCapabilities = hdrCapabilities;
}
else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER)
{
@@ -1071,8 +1173,9 @@ namespace DisplayMagicianShared.NVIDIA
if (hdrColorData.HdrMode != NV_HDR_MODE.OFF)
{
isNvHdrEnabled = true;
+ myDisplay.HasNvHdrEnabled = true;
}
- allHdrColorData.Add(displayIds[displayIndex].DisplayId.ToString(), hdrColorData);
+ myDisplay.HdrColorData = hdrColorData;
}
else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER)
{
@@ -1099,75 +1202,125 @@ namespace DisplayMagicianShared.NVIDIA
SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting HDR color settings! NvAPI_Disp_HdrColorControl() returned error code {NVStatus}. It's most likely that your monitor {displayIds[displayIndex].DisplayId} doesn't support HDR.");
}
- }
-
-
- // TEMPORARILY DISABLING THE CUSTOM DISPLAY CODE FOR NOW, AS NOT SURE WHAT NVIDIA SETTINGS IT TRACKS
- // KEEPING IT IN CASE I NEED IT FOR LATER. I ORIGINALLY THOUGHT THAT IS WHERE INTEGER SCALING SETTINGS LIVED< BUT WAS WRONG
- /*// Now we get the Custom Display settings of the display (if there are any)
- //NVIDIA_CUSTOM_DISPLAY_CONFIG customDisplayConfig = new NVIDIA_CUSTOM_DISPLAY_CONFIG();
- List customDisplayConfig = new List();
- for (UInt32 d = 0; d < UInt32.MaxValue; d++)
- {
- NV_CUSTOM_DISPLAY_V1 customDisplay = new NV_CUSTOM_DISPLAY_V1();
- NVStatus = NVImport.NvAPI_DISP_EnumCustomDisplay(displayIds[displayIndex].DisplayId, d, ref customDisplay);
+ // Now we get the Adaptive Sync Settings from the display
+ NV_GET_ADAPTIVE_SYNC_DATA_V1 getAdaptiveSyncData = new NV_GET_ADAPTIVE_SYNC_DATA_V1();
+ getAdaptiveSyncData.Version = NVImport.NV_GET_ADAPTIVE_SYNC_DATA_V1_VER;
+ NVStatus = NVImport.NvAPI_DISP_GetAdaptiveSyncData(displayIds[displayIndex].DisplayId, ref getAdaptiveSyncData);
if (NVStatus == NVAPI_STATUS.NVAPI_OK)
{
- SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_DISP_EnumCustomDisplay returned OK. Custom Display settings retrieved.");
- customDisplayConfig.Add(customDisplay);
+ // Copy the AdaptiveSync Data we got into a NV_SET_ADAPTIVE_SYNC_DATA_V1 object so that it can be used without conversion
+ NV_SET_ADAPTIVE_SYNC_DATA_V1 setAdaptiveSyncData = new NV_SET_ADAPTIVE_SYNC_DATA_V1();
+ setAdaptiveSyncData.Version = NVImport.NV_SET_ADAPTIVE_SYNC_DATA_V1_VER;
+ setAdaptiveSyncData.Flags = getAdaptiveSyncData.Flags;
+ setAdaptiveSyncData.MaxFrameInterval = getAdaptiveSyncData.MaxFrameInterval;
+
+ SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_DISP_GetAdaptiveSyncData returned OK.");
+ if (getAdaptiveSyncData.DisableAdaptiveSync)
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: AdaptiveSync is DISABLED for Display {displayIds[displayIndex].DisplayId} .");
+ }
+ else
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: AdaptiveSync is ENABLED for Display {displayIds[displayIndex].DisplayId} .");
+ }
+ if (getAdaptiveSyncData.DisableFrameSplitting)
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: FrameSplitting is DISABLED for Display {displayIds[displayIndex].DisplayId} .");
+ }
+ else
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: FrameSplitting is ENABLED for Display {displayIds[displayIndex].DisplayId} .");
+ }
+ myDisplay.AdaptiveSyncConfig = setAdaptiveSyncData;
+ myDisplay.HasAdaptiveSync = true;
}
- else if (NVStatus == NVAPI_STATUS.NVAPI_END_ENUMERATION)
+ else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER)
{
- SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: We've reached the end of the list of Custom Displays. Breaking the polling loop.");
- break;
+ SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The input buffer is not large enough to hold it's contents. NvAPI_DISP_GetAdaptiveSyncData() returned error code {NVStatus}");
}
else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID)
{
- SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_DISP_EnumCustomDisplay() returned error code {NVStatus}");
- break;
+ SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The input monitor {displayIds[displayIndex].DisplayId} is either not connected or is not a DP or HDMI panel. NvAPI_DISP_GetAdaptiveSyncData() returned error code {NVStatus}");
}
else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED)
{
- SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_DISP_EnumCustomDisplay() returned error code {NVStatus}");
- break;
+ SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_DISP_GetAdaptiveSyncData() returned error code {NVStatus}");
}
else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION)
{
- SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_DISP_EnumCustomDisplay() returned error code {NVStatus}");
- break;
- }
- else if (NVStatus == NVAPI_STATUS.NVAPI_INCOMPATIBLE_STRUCT_VERSION)
- {
- SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The supplied struct is incompatible. NvAPI_DISP_EnumCustomDisplay() returned error code {NVStatus}");
- break;
+ SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_DISP_GetAdaptiveSyncData() returned error code {NVStatus}");
}
else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR)
{
- SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_DISP_EnumCustomDisplay() returned error code {NVStatus}.");
- break;
+ SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_DISP_GetAdaptiveSyncData() returned error code {NVStatus}.");
}
else
{
- SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while enumerating the custom displays! NvAPI_DISP_EnumCustomDisplay() returned error code {NVStatus}.");
- break;
+ SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting HDR color settings! NvAPI_DISP_GetAdaptiveSyncData() returned error code {NVStatus}. It's most likely that your monitor {displayIds[displayIndex].DisplayId} doesn't support HDR.");
}
- }
- if (customDisplayConfig.Count > 0)
- {
- allCustomDisplays.Add(displayIds[displayIndex].DisplayId, customDisplayConfig);
- }*/
- }
- // Store the HDR information
- myDisplayConfig.HdrConfig.IsNvHdrEnabled = isNvHdrEnabled;
- myDisplayConfig.HdrConfig.HdrCapabilities = allHdrCapabilities;
- myDisplayConfig.HdrConfig.HdrColorData = allHdrColorData;
- myDisplayConfig.ColorConfig.ColorData = allColorData;
- myDisplayConfig.CustomDisplays = allCustomDisplays;
- myDisplayConfig.DisplayConfigs = allDisplayConfigs;
+ // TEMPORARILY DISABLING THE CUSTOM DISPLAY CODE FOR NOW, AS NOT SURE WHAT NVIDIA SETTINGS IT TRACKS
+ // KEEPING IT IN CASE I NEED IT FOR LATER. I ORIGINALLY THOUGHT THAT IS WHERE INTEGER SCALING SETTINGS LIVED< BUT WAS WRONG
+ /*// Now we get the Custom Display settings of the display (if there are any)
+ //NVIDIA_CUSTOM_DISPLAY_CONFIG customDisplayConfig = new NVIDIA_CUSTOM_DISPLAY_CONFIG();
+ List customDisplayConfig = new List();
+ for (UInt32 d = 0; d < UInt32.MaxValue; d++)
+ {
+ NV_CUSTOM_DISPLAY_V1 customDisplay = new NV_CUSTOM_DISPLAY_V1();
+ NVStatus = NVImport.NvAPI_DISP_EnumCustomDisplay(displayIds[displayIndex].DisplayId, d, ref customDisplay);
+ if (NVStatus == NVAPI_STATUS.NVAPI_OK)
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_DISP_EnumCustomDisplay returned OK. Custom Display settings retrieved.");
+ myDisplay.CustomDisplay = customDisplay;
+ myDisplay.HasCustomDisplay = true;
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_END_ENUMERATION)
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: We've reached the end of the list of Custom Displays. Breaking the polling loop.");
+ break;
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_DISP_EnumCustomDisplay() returned error code {NVStatus}");
+ break;
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_DISP_EnumCustomDisplay() returned error code {NVStatus}");
+ break;
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_DISP_EnumCustomDisplay() returned error code {NVStatus}");
+ break;
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_INCOMPATIBLE_STRUCT_VERSION)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The supplied struct is incompatible. NvAPI_DISP_EnumCustomDisplay() returned error code {NVStatus}");
+ break;
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_DISP_EnumCustomDisplay() returned error code {NVStatus}.");
+ break;
+ }
+ else
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while enumerating the custom displays! NvAPI_DISP_EnumCustomDisplay() returned error code {NVStatus}.");
+ break;
+ }
+
+ }*/
+
+ myAdapter.Displays.Add(displayIds[displayIndex].DisplayId, myDisplay);
+ }
+ }
}
+ myAdapter.DisplayCount = (UInt32)myAdapter.Displays.Count();
+ myDisplayConfig.PhysicalAdapters[physicalGpuIndex] = myAdapter;
+
}
@@ -1213,6 +1366,59 @@ namespace DisplayMagicianShared.NVIDIA
// Get the display identifiers
myDisplayConfig.DisplayIdentifiers = GetCurrentDisplayIdentifiers();
+
+ // Go through and find the list of displayIDs
+ // ignore the ones that were found
+ // if one was not found, then
+ // go through the modes
+ // patch the target
+ if (myDisplayConfig.IsCloned)
+ {
+ List clonedIdsWeKnow = new List();
+ List missingIdsWeWant = new List();
+ // Find all displays in the displayconfig
+ foreach (var displayConfig in myDisplayConfig.DisplayConfigs)
+ {
+ foreach (var targetInfo in displayConfig.TargetInfo)
+ {
+ if (foundDisplayIds.Contains(targetInfo.DisplayId))
+ {
+ // We have this foundId
+ clonedIdsWeKnow.Add(targetInfo.DisplayId);
+ }
+ }
+ }
+
+ // Now go through and figure out which foundDisplayId we're missing
+ foreach (var foundDisplayId in foundDisplayIds)
+ {
+ if (!clonedIdsWeKnow.Contains(foundDisplayId))
+ {
+ // We found a cloned display id \o/
+ missingIdsWeWant.Add(foundDisplayId);
+ }
+ }
+
+ int clonedIdOffset = 0;
+ // Now we go through the list of missing cloned id's and we fill them in
+ for (int x = 0; x < myDisplayConfig.DisplayConfigs.Count; x++)
+ {
+ // We go through all the displayconfigs, but we want to only change the cloned displays (those with > 1 targetInfo)
+ if (myDisplayConfig.DisplayConfigs[x].TargetInfoCount > 1)
+ {
+ // We only want to change the cloned displays, so we start at index 1 (the clones themselves)
+ for (int y = 1; y < myDisplayConfig.DisplayConfigs[x].TargetInfoCount; y++)
+ {
+ // We want to assign the cloned display the display ID from the missing display
+ myDisplayConfig.DisplayConfigs[x].TargetInfo[y].DisplayId = missingIdsWeWant[clonedIdOffset++];
+ // We also want to clone the Details struct from the base display (the first display) and replicate them on the clone
+ // This copies the process used within the DisplayCOnfiguration C++ Sample released by NVIDIA
+ myDisplayConfig.DisplayConfigs[x].TargetInfo[y].Details = (NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO_V1)myDisplayConfig.DisplayConfigs[0].TargetInfo[0].Details.Clone();
+ }
+ }
+ }
+ }
+
}
else
{
@@ -1341,86 +1547,89 @@ namespace DisplayMagicianShared.NVIDIA
stringToReturn += $"NVIDIA Surround/Mosaic is Disabled\n";
}
- // Start printing out things
- stringToReturn += $"\n****** NVIDIA COLOR CONFIG *******\n";
- foreach (KeyValuePair colorData in displayConfig.ColorConfig.ColorData)
+ // Start printing out things for the physical GPU
+ foreach (KeyValuePair physicalGPU in displayConfig.PhysicalAdapters)
{
- string displayId = colorData.Key.ToString();
- stringToReturn += $"Display {displayId} BPC is {colorData.Value.Bpc.ToString("G")}.\n";
- stringToReturn += $"Display {displayId} ColorFormat is {colorData.Value.ColorFormat.ToString("G")}.\n";
- stringToReturn += $"Display {displayId} Colorimetry is {colorData.Value.Colorimetry.ToString("G")}.\n";
- stringToReturn += $"Display {displayId} ColorSelectionPolicy is {colorData.Value.ColorSelectionPolicy.ToString("G")}.\n";
- stringToReturn += $"Display {displayId} Depth is {colorData.Value.Depth.ToString("G")}.\n";
- stringToReturn += $"Display {displayId} DynamicRange is {colorData.Value.DynamicRange.ToString("G")}.\n";
- }
+ stringToReturn += $"\n****** NVIDIA PHYSICAL ADAPTER {physicalGPU.Key} *******\n";
- // Start printing out HDR things
- stringToReturn += $"\n****** NVIDIA HDR CONFIG *******\n";
- if (displayConfig.HdrConfig.IsNvHdrEnabled)
- {
- stringToReturn += $"NVIDIA HDR is Enabled\n";
- if (displayConfig.HdrConfig.HdrCapabilities.Count > 0)
- {
- stringToReturn += $"There are {displayConfig.HdrConfig.HdrCapabilities.Count} NVIDIA HDR devices in use.\n";
- }
- if (displayConfig.MosaicConfig.MosaicGridTopos.Length == 1)
- {
- stringToReturn += $"There is 1 NVIDIA HDR devices in use.\n";
- }
- else
- {
- stringToReturn += $"There are no NVIDIA HDR devices in use.\n";
- }
+ NVIDIA_PER_ADAPTER_CONFIG myAdapter = physicalGPU.Value;
- foreach (KeyValuePair hdrCapabilityItem in displayConfig.HdrConfig.HdrCapabilities)
+ foreach (KeyValuePair myDisplayItem in myAdapter.Displays)
{
- string displayId = hdrCapabilityItem.Key.ToString();
- if (hdrCapabilityItem.Value.IsDolbyVisionSupported)
+ string displayId = myDisplayItem.Key.ToString();
+ NVIDIA_PER_DISPLAY_CONFIG myDisplay = myDisplayItem.Value;
+
+ stringToReturn += $"\n****** NVIDIA PER DISPLAY CONFIG {displayId} *******\n";
+
+ stringToReturn += $"\n****** NVIDIA COLOR CONFIG *******\n";
+ stringToReturn += $"Display {displayId} BPC is {myDisplay.ColorData.Bpc.ToString("G")}.\n";
+ stringToReturn += $"Display {displayId} ColorFormat is {myDisplay.ColorData.ColorFormat.ToString("G")}.\n";
+ stringToReturn += $"Display {displayId} Colorimetry is {myDisplay.ColorData.Colorimetry.ToString("G")}.\n";
+ stringToReturn += $"Display {displayId} ColorSelectionPolicy is {myDisplay.ColorData.ColorSelectionPolicy.ToString("G")}.\n";
+ stringToReturn += $"Display {displayId} Depth is {myDisplay.ColorData.Depth.ToString("G")}.\n";
+ stringToReturn += $"Display {displayId} DynamicRange is {myDisplay.ColorData.DynamicRange.ToString("G")}.\n";
+
+ // Start printing out HDR things
+ stringToReturn += $"\n****** NVIDIA HDR CONFIG *******\n";
+ if (myDisplay.HasNvHdrEnabled)
{
- stringToReturn += $"Display {displayId} supports DolbyVision HDR.\n";
+ stringToReturn += $"NVIDIA HDR is Enabled\n";
+ if (displayConfig.MosaicConfig.MosaicGridTopos.Length == 1)
+ {
+ stringToReturn += $"There is 1 NVIDIA HDR devices in use.\n";
+ }
+ else
+ {
+ stringToReturn += $"There are no NVIDIA HDR devices in use.\n";
+ }
+
+ if (myDisplay.HdrCapabilities.IsDolbyVisionSupported)
+ {
+ stringToReturn += $"Display {displayId} supports DolbyVision HDR.\n";
+ }
+ else
+ {
+ stringToReturn += $"Display {displayId} DOES NOT support DolbyVision HDR.\n";
+ }
+ if (myDisplay.HdrCapabilities.IsST2084EotfSupported)
+ {
+ stringToReturn += $"Display {displayId} supports ST2084EOTF HDR Mode.\n";
+ }
+ else
+ {
+ stringToReturn += $"Display {displayId} DOES NOT support ST2084EOTF HDR Mode.\n";
+ }
+ if (myDisplay.HdrCapabilities.IsTraditionalHdrGammaSupported)
+ {
+ stringToReturn += $"Display {displayId} supports Traditional HDR Gamma.\n";
+ }
+ else
+ {
+ stringToReturn += $"Display {displayId} DOES NOT support Traditional HDR Gamma.\n";
+ }
+ if (myDisplay.HdrCapabilities.IsEdrSupported)
+ {
+ stringToReturn += $"Display {displayId} supports EDR.\n";
+ }
+ else
+ {
+ stringToReturn += $"Display {displayId} DOES NOT support EDR.\n";
+ }
+ if (myDisplay.HdrCapabilities.IsTraditionalSdrGammaSupported)
+ {
+ stringToReturn += $"Display {displayId} supports SDR Gamma.\n";
+ }
+ else
+ {
+ stringToReturn += $"Display {displayId} DOES NOT support SDR Gamma.\n";
+ }
}
else
{
- stringToReturn += $"Display {displayId} DOES NOT support DolbyVision HDR.\n";
- }
- if (hdrCapabilityItem.Value.IsST2084EotfSupported)
- {
- stringToReturn += $"Display {displayId} supports ST2084EOTF HDR Mode.\n";
- }
- else
- {
- stringToReturn += $"Display {displayId} DOES NOT support ST2084EOTF HDR Mode.\n";
- }
- if (hdrCapabilityItem.Value.IsTraditionalHdrGammaSupported)
- {
- stringToReturn += $"Display {displayId} supports Traditional HDR Gamma.\n";
- }
- else
- {
- stringToReturn += $"Display {displayId} DOES NOT support Traditional HDR Gamma.\n";
- }
- if (hdrCapabilityItem.Value.IsEdrSupported)
- {
- stringToReturn += $"Display {displayId} supports EDR.\n";
- }
- else
- {
- stringToReturn += $"Display {displayId} DOES NOT support EDR.\n";
- }
- if (hdrCapabilityItem.Value.IsTraditionalSdrGammaSupported)
- {
- stringToReturn += $"Display {displayId} supports SDR Gamma.\n";
- }
- else
- {
- stringToReturn += $"Display {displayId} DOES NOT support SDR Gamma.\n";
+ stringToReturn += $"NVIDIA HDR is Disabled (HDR may still be enabled within Windows itself)\n";
}
}
}
- else
- {
- stringToReturn += $"NVIDIA HDR is Disabled (HDR may still be enabled within Windows itself)\n";
- }
stringToReturn += $"\n\n";
// Now we also get the Windows CCD Library info, and add it to the above
@@ -1439,177 +1648,235 @@ namespace DisplayMagicianShared.NVIDIA
// Remove any custom NVIDIA Colour settings
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to turn off colour if it's default set colour.");
- // Now we try to set each display color
- foreach (var colorDataDict in displayConfig.ColorConfig.ColorData)
+ foreach (var physicalGPU in displayConfig.PhysicalAdapters)
{
- NV_COLOR_DATA_V5 colorData = colorDataDict.Value;
- string displayId = colorDataDict.Key;
- try
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Processing settings for Physical GPU #{physicalGPU.Key}");
+ NVIDIA_PER_ADAPTER_CONFIG myAdapter = physicalGPU.Value;
+ UInt32 myAdapterIndex = physicalGPU.Key;
+ foreach (var displayDict in myAdapter.Displays)
{
- UInt32 displayIdAsUInt32 = UInt32.Parse(displayId);
+ NVIDIA_PER_DISPLAY_CONFIG myDisplay = displayDict.Value;
+ UInt32 displayId = displayDict.Key;
- if (!ActiveDisplayConfig.ColorConfig.ColorData.ContainsKey(displayId))
+ if (!ActiveDisplayConfig.PhysicalAdapters[myAdapterIndex].Displays.ContainsKey(displayId))
{
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Display {displayId} doesn't exist in this setup, so skipping turning off prior NVIDIA Color Settings.");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Display {displayId} doesn't exist in this setup, so skipping changing any NVIDIA display Settings.");
continue;
}
- // If the setting for this display is not the same as we want, then we set it to NV_COLOR_SELECTION_POLICY_BEST_QUALITY
- if (ActiveDisplayConfig.ColorConfig.ColorData[displayId].ColorSelectionPolicy != NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_BEST_QUALITY)
+ // Remove any custom NVIDIA Colour settings
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to turn off colour if it's user set colour.");
+
+ NV_COLOR_DATA_V5 colorData = myDisplay.ColorData;
+ try
{
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to turn off NVIDIA customer colour settings for display {displayId}.");
-
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want the standard colour settings to be {displayConfig.ColorConfig.ColorData[displayId].ColorSelectionPolicy.ToString("G")} for Mosaic display {displayId}.");
- // Force the colorData to be NV_COLOR_SELECTION_POLICY_BEST_QUALITY so that we return the color control to Windows
- // We will change the colorData to whatever is required later on
- colorData = displayConfig.ColorConfig.ColorData[displayId];
- colorData.ColorSelectionPolicy = NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_BEST_QUALITY;
-
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want the standard colour settings to be {displayConfig.ColorConfig.ColorData[displayId].ColorSelectionPolicy.ToString("G")} and they are {ActiveDisplayConfig.ColorConfig.ColorData[displayId].ColorSelectionPolicy.ToString("G")} for Mosaic display {displayId}.");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to turn off standard colour mode for Mosaic display {displayId}.");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want standard colour settings Color selection policy {colorData.ColorSelectionPolicy.ToString("G")} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want standard colour settings BPC {colorData.Bpc} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want standard colour settings colour format {colorData.ColorFormat} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want standard colour settings colourimetry {colorData.Colorimetry} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want standard colour settings colour depth {colorData.Depth} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want standard colour settings dynamic range {colorData.DynamicRange} for Mosaic display {displayId}");
-
- // Set the command as a 'SET'
- colorData.Cmd = NV_COLOR_CMD.NV_COLOR_CMD_SET;
- NVStatus = NVImport.NvAPI_Disp_ColorControl(displayIdAsUInt32, ref colorData);
- if (NVStatus == NVAPI_STATUS.NVAPI_OK)
+ // If the setting for this display is not the same as we want, then we set it to NV_COLOR_SELECTION_POLICY_BEST_QUALITY
+ if (ActiveDisplayConfig.PhysicalAdapters[myAdapterIndex].Displays[displayId].ColorData.ColorSelectionPolicy != NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_BEST_QUALITY)
{
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: NvAPI_Disp_ColorControl returned OK. BPC is set to {colorData.Bpc.ToString("G")}. Color Format is set to {colorData.ColorFormat.ToString("G")}. Colorimetry is set to {colorData.Colorimetry.ToString("G")}. Color Selection Policy is set to {colorData.ColorSelectionPolicy.ToString("G")}. Color Depth is set to {colorData.Depth.ToString("G")}. Dynamic Range is set to {colorData.DynamicRange.ToString("G")}");
- switch (colorData.ColorSelectionPolicy)
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to turn off NVIDIA customer colour settings for display {displayId}.");
+
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want the standard colour settings to be {myDisplay.ColorData.ColorSelectionPolicy.ToString("G")} for Mosaic display {displayId}.");
+ // Force the colorData to be NV_COLOR_SELECTION_POLICY_BEST_QUALITY so that we return the color control to Windows
+ // We will change the colorData to whatever is required later on
+ //colorData = myDisplay.ColorData;
+ colorData.ColorSelectionPolicy = NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_BEST_QUALITY;
+
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want the standard colour settings to be {myDisplay.ColorData.ColorSelectionPolicy.ToString("G")} and they are currently {ActiveDisplayConfig.PhysicalAdapters[myAdapterIndex].Displays[displayId].ColorData.ColorSelectionPolicy.ToString("G")} for Mosaic display {displayId}.");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to turn off standard colour mode for Mosaic display {displayId}.");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want standard colour settings Color selection policy {colorData.ColorSelectionPolicy.ToString("G")} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want standard colour settings BPC {colorData.Bpc} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want standard colour settings colour format {colorData.ColorFormat} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want standard colour settings colourimetry {colorData.Colorimetry} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want standard colour settings colour depth {colorData.Depth} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want standard colour settings dynamic range {colorData.DynamicRange} for Mosaic display {displayId}");
+
+ // Set the command as a 'SET'
+ colorData.Cmd = NV_COLOR_CMD.NV_COLOR_CMD_SET;
+ NVStatus = NVImport.NvAPI_Disp_ColorControl(displayId, ref colorData);
+ if (NVStatus == NVAPI_STATUS.NVAPI_OK)
{
- case NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_USER:
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Color Selection Policy is set to NV_COLOR_SELECTION_POLICY_USER so the color settings have been set by the user in the NVIDIA Control Panel.");
- break;
- case NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_BEST_QUALITY: // Also matches NV_COLOR_SELECTION_POLICY_DEFAULT as it is 1
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Color Selection Policy is set to NV_COLOR_SELECTION_POLICY_BEST_QUALITY so the color settings are being handled by the Windows OS.");
- break;
- case NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_UNKNOWN:
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: Color Selection Policy is set to NV_COLOR_SELECTION_POLICY_UNKNOWN so the color settings aren't being handled by either the Windows OS or the NVIDIA Setup!");
- break;
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: NvAPI_Disp_ColorControl returned OK. BPC is set to {colorData.Bpc.ToString("G")}. Color Format is set to {colorData.ColorFormat.ToString("G")}. Colorimetry is set to {colorData.Colorimetry.ToString("G")}. Color Selection Policy is set to {colorData.ColorSelectionPolicy.ToString("G")}. Color Depth is set to {colorData.Depth.ToString("G")}. Dynamic Range is set to {colorData.DynamicRange.ToString("G")}");
+ switch (colorData.ColorSelectionPolicy)
+ {
+ case NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_USER:
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Color Selection Policy is set to NV_COLOR_SELECTION_POLICY_USER so the color settings have been set by the user in the NVIDIA Control Panel.");
+ break;
+ case NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_BEST_QUALITY: // Also matches NV_COLOR_SELECTION_POLICY_DEFAULT as it is 1
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Color Selection Policy is set to NV_COLOR_SELECTION_POLICY_BEST_QUALITY so the color settings are being handled by the Windows OS.");
+ break;
+ case NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_UNKNOWN:
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: Color Selection Policy is set to NV_COLOR_SELECTION_POLICY_UNKNOWN so the color settings aren't being handled by either the Windows OS or the NVIDIA Setup!");
+ break;
+ }
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: Your monitor {displayId} doesn't support the requested color settings. BPC = {colorData.Bpc.ToString("G")}. Color Format = {colorData.ColorFormat.ToString("G")}. Colorimetry = {colorData.Colorimetry.ToString("G")}. Color Selection Policy = {colorData.ColorSelectionPolicy.ToString("G")}. Color Depth = {colorData.Depth.ToString("G")}. Dynamic Range = {colorData.DynamicRange.ToString("G")}. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The input buffer is not large enough to hold it's contents. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The NvAPI API needs to be initialized first. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: This entry point not available in this NVIDIA Driver. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: A miscellaneous error occurred. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
+ }
+ else
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Some non standard error occurred while seting the color settings! NvAPI_Disp_ColorControl() returned error code {NVStatus}. It's most likely that your monitor {displayId} doesn't support this color mode.");
}
}
- else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED)
+ else
{
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: Your monitor {displayId} doesn't support the requested color settings. BPC = {colorData.Bpc.ToString("G")}. Color Format = {colorData.ColorFormat.ToString("G")}. Colorimetry = {colorData.Colorimetry.ToString("G")}. Color Selection Policy = {colorData.ColorSelectionPolicy.ToString("G")}. Color Depth = {colorData.Depth.ToString("G")}. Dynamic Range = {colorData.DynamicRange.ToString("G")}. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want only want to turn off custom NVIDIA colour settings if needed for display {displayId}, and that currently isn't required. Skipping changing NVIDIA colour mode.");
}
- else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER)
+ }
+ catch (Exception ex)
+ {
+ SharedLogger.logger.Error(ex, $"NVIDIALibrary/SetActiveConfig: Exception caused while turning off prior NVIDIA specific colour settings for display {displayId}.");
+ }
+
+ // Remove any custom NVIDIA HDR Colour settings
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to turn off HDR colour if it's user set HDR colour.");
+
+ NV_HDR_COLOR_DATA_V2 hdrColorData = myDisplay.HdrColorData;
+ try
+ {
+
+ // if it's not the same HDR we want, then we turn off HDR (and will apply it if needed later on in SetActiveOverride)
+ if (ActiveDisplayConfig.PhysicalAdapters[myAdapterIndex].Displays[displayId].HdrColorData.HdrMode != NV_HDR_MODE.OFF)
{
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The input buffer is not large enough to hold it's contents. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
- }
- else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID)
- {
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
- }
- else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED)
- {
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The NvAPI API needs to be initialized first. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
- }
- else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION)
- {
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: This entry point not available in this NVIDIA Driver. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
- }
- else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR)
- {
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: A miscellaneous error occurred. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to turn on custom HDR mode for display {displayId}.");
+
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: HDR mode is currently {ActiveDisplayConfig.PhysicalAdapters[myAdapterIndex].Displays[displayId].HdrColorData.HdrMode.ToString("G")} for Mosaic display {displayId}.");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want HDR settings BPC {hdrColorData.HdrBpc} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want HDR settings HDR Colour Format {hdrColorData.HdrColorFormat} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want HDR settings HDR dynamic range {hdrColorData.HdrDynamicRange} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want HDR settings HDR Mode {hdrColorData.HdrMode} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want HDR settings Mastering Display Data {hdrColorData.MasteringDisplayData} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want HDR settings Static Meradata Description ID {hdrColorData.StaticMetadataDescriptorId} for Mosaic display {displayId}");
+ // Apply the HDR removal
+ hdrColorData.Cmd = NV_HDR_CMD.CMD_SET;
+ hdrColorData.HdrMode = NV_HDR_MODE.OFF;
+ NVStatus = NVImport.NvAPI_Disp_HdrColorControl(displayId, ref hdrColorData);
+ if (NVStatus == NVAPI_STATUS.NVAPI_OK)
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: NvAPI_Disp_HdrColorControl returned OK. We just successfully turned off the HDR mode for Mosaic display {displayId}.");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The input buffer is not large enough to hold it's contents. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The NvAPI API needs to be initialized first. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: This entry point not available in this NVIDIA Driver. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: A miscellaneous error occurred. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
+ }
+ else
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_Disp_HdrColorControl() returned error code {NVStatus}. It's most likely that your monitor {displayId} doesn't support HDR.");
+ }
}
else
{
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Some non standard error occurred while seting the color settings! NvAPI_Disp_ColorControl() returned error code {NVStatus}. It's most likely that your monitor {displayId} doesn't support this color mode.");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want only want to turn off custom NVIDIA HDR settings if needed for display {displayId}, and that currently isn't required. Skipping changing NVIDIA HDR mode.");
}
+
}
- else
+ catch (Exception ex)
{
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want only want to turn off custom NVIDIA colour settings if needed for display {displayId}, and that currently isn't required. Skipping changing NVIDIA colour mode.");
- }
- }
- catch (Exception ex)
- {
- SharedLogger.logger.Error(ex, $"NVIDIALibrary/SetActiveConfig: Exception caused while turning off prior NVIDIA specific colour settings for display {displayId}.");
- }
- }
-
- // Remove any custom NVIDIA HDR Colour settings
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to turn off HDR colour if it's user set HDR colour.");
- // Now we try to set each display color
- foreach (var hdrColorDataDict in displayConfig.HdrConfig.HdrColorData)
- {
- NV_HDR_COLOR_DATA_V2 hdrColorData = hdrColorDataDict.Value;
- string displayId = hdrColorDataDict.Key;
-
- try
- {
-
- UInt32 displayIdAsUInt32 = UInt32.Parse(displayId);
-
- if (!ActiveDisplayConfig.HdrConfig.HdrColorData.ContainsKey(displayId))
- {
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Display {displayId} doesn't exist in this setup, so skipping turning off HDR.");
- continue;
+ SharedLogger.logger.Error(ex, $"NVIDIALibrary/SetActiveConfig: Exception caused while turning off prior NVIDIA HDR colour settings for display {displayId}.");
}
- // if it's not the same HDR we want, then we turn off HDR (and will apply it if needed later on in SetActiveOverride)
- if (ActiveDisplayConfig.HdrConfig.HdrColorData[displayId].HdrMode != NV_HDR_MODE.OFF)
- {
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to turn on custom HDR mode for display {displayId}.");
+ // Set any AdaptiveSync settings
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to set any adaptive Sync settings if in use.");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: HDR mode is currently {ActiveDisplayConfig.HdrConfig.HdrColorData[displayId].HdrMode.ToString("G")} for Mosaic display {displayId}.");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want HDR settings BPC {hdrColorData.HdrBpc} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want HDR settings HDR Colour Format {hdrColorData.HdrColorFormat} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want HDR settings HDR dynamic range {hdrColorData.HdrDynamicRange} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want HDR settings HDR Mode {hdrColorData.HdrMode} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want HDR settings Mastering Display Data {hdrColorData.MasteringDisplayData} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want HDR settings Static Meradata Description ID {hdrColorData.StaticMetadataDescriptorId} for Mosaic display {displayId}");
- // Apply the HDR removal
- hdrColorData.Cmd = NV_HDR_CMD.CMD_SET;
- hdrColorData.HdrMode = NV_HDR_MODE.OFF;
- NVStatus = NVImport.NvAPI_Disp_HdrColorControl(displayIdAsUInt32, ref hdrColorData);
+ NV_SET_ADAPTIVE_SYNC_DATA_V1 adaptiveSyncData = myDisplay.AdaptiveSyncConfig;
+ try
+ {
+ if (myDisplay.AdaptiveSyncConfig.DisableAdaptiveSync)
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to DISABLE Adaptive Sync for display {displayId}.");
+ }
+ else
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to ENABLE Adaptive Sync for display {displayId}.");
+ }
+
+ if (myDisplay.AdaptiveSyncConfig.DisableFrameSplitting)
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to DISABLE Frame Splitting for display {displayId}.");
+ }
+ else
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to ENABLE Frame Splitting for display {displayId}.");
+ }
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to set the Adaptice Sync Max Frame Interval to {myDisplay.AdaptiveSyncConfig.MaxFrameInterval}ms for display {displayId}.");
+
+ // Apply the AdaptiveSync settings
+ NVStatus = NVImport.NvAPI_DISP_SetAdaptiveSyncData(displayId, ref adaptiveSyncData);
if (NVStatus == NVAPI_STATUS.NVAPI_OK)
{
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: NvAPI_Disp_HdrColorControl returned OK. We just successfully turned off the HDR mode for Mosaic display {displayId}.");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: NvAPI_DISP_SetAdaptiveSyncData returned OK. We just successfully set the Adaptive Sync settings for display {displayId}.");
}
else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER)
{
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The input buffer is not large enough to hold it's contents. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The input buffer is not large enough to hold it's contents. NvAPI_DISP_SetAdaptiveSyncData() returned error code {NVStatus}");
}
else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID)
{
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_DISP_SetAdaptiveSyncData() returned error code {NVStatus}");
}
else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED)
{
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The NvAPI API needs to be initialized first. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The NvAPI API needs to be initialized first. NvAPI_DISP_SetAdaptiveSyncData() returned error code {NVStatus}");
}
else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION)
{
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: This entry point not available in this NVIDIA Driver. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: This entry point not available in this NVIDIA Driver. NvAPI_DISP_SetAdaptiveSyncData() returned error code {NVStatus}");
}
else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR)
{
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: A miscellaneous error occurred. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: A miscellaneous error occurred. NvAPI_DISP_SetAdaptiveSyncData() returned error code {NVStatus}");
}
else
{
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_Disp_HdrColorControl() returned error code {NVStatus}. It's most likely that your monitor {displayId} doesn't support HDR.");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_DISP_SetAdaptiveSyncData() returned error code {NVStatus}. It's most likely that your monitor {displayId} doesn't support HDR.");
}
- }
- else
- {
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want only want to turn off custom NVIDIA HDR settings if needed for display {displayId}, and that currently isn't required. Skipping changing NVIDIA HDR mode.");
- }
- }
- catch (Exception ex)
- {
- SharedLogger.logger.Error(ex, $"NVIDIALibrary/SetActiveConfig: Exception caused while turning off prior NVIDIA HDR colour settings for display {displayId}.");
+ }
+ catch (Exception ex)
+ {
+ SharedLogger.logger.Error(ex, $"NVIDIALibrary/SetActiveConfig: Exception caused while trying to set NVIDIA Adaptive Sync settings for display {displayId}.");
+ }
}
}
+
// Now we've set the color the way we want it, lets do the thing
// We want to check the NVIDIA Surround (Mosaic) config is valid
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Testing whether the display configuration is valid");
@@ -1977,7 +2244,70 @@ namespace DisplayMagicianShared.NVIDIA
{
// We are on a non-Mosaic profile now, and we are changing to a non-Mosaic profile
// so there is nothing to do as far as NVIDIA is concerned!
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We are on a non-Mosaic profile now, and we are changing to a non-Mosaic profile so there is nothing to do as far as NVIDIA is concerned!");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We are on a non-Mosaic profile now, and we are changing to a non-Mosaic profile so there is no need to modify Mosaic settings!");
+ }
+
+ // Now we set the NVIDIA Display Config (if we have one!)
+ // If the display profile is a cloned config then NVIDIA GetDisplayConfig doesn't work
+ // so we need to check for that. We just skip the SetDisplayConfig as it won't exist
+ if (displayConfig.DisplayConfigs.Count > 0)
+ {
+ NVStatus = NVImport.NvAPI_DISP_SetDisplayConfig((UInt32)displayConfig.DisplayConfigs.Count, displayConfig.DisplayConfigs.ToArray(), NV_DISPLAYCONFIG_FLAGS.SAVE_TO_PERSISTENCE);
+ if (NVStatus == NVAPI_STATUS.NVAPI_OK)
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: NvAPI_DISP_SetDisplayConfig returned OK.");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Waiting 0.5 second to let the Display Config layout change take place before continuing");
+ System.Threading.Thread.Sleep(500);
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_NO_ACTIVE_SLI_TOPOLOGY)
+ {
+ SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: No matching GPU topologies could be found. NvAPI_DISP_SetDisplayConfig() returned error code {NVStatus}");
+ return false;
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The Display ID of the first display is not currently possible to use. NvAPI_DISP_SetDisplayConfig() returned error code {NVStatus}. Trying again with the next display.");
+ return false;
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_ARGUMENT)
+ {
+ SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: One or more arguments passed in are invalid. NvAPI_DISP_SetDisplayConfig() returned error code {NVStatus}");
+ return false;
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED)
+ {
+ SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: The NvAPI API needs to be initialized first. NvAPI_DISP_SetDisplayConfig() returned error code {NVStatus}");
+ return false;
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION)
+ {
+ SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: This entry point not available in this NVIDIA Driver. NvAPI_DISP_SetDisplayConfig() returned error code {NVStatus}");
+ return false;
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_INCOMPATIBLE_STRUCT_VERSION)
+ {
+ SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: The version of the structure passed in is not compatible with this entrypoint. NvAPI_DISP_SetDisplayConfig() returned error code {NVStatus}");
+ return false;
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_MODE_CHANGE_FAILED)
+ {
+ SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: There was an error changing the display mode. NvAPI_DISP_SetDisplayConfig() returned error code {NVStatus}");
+ return false;
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR)
+ {
+ SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: A miscellaneous error occurred. NvAPI_DISP_SetDisplayConfig() returned error code {NVStatus}");
+ return false;
+ }
+ else
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Some non standard error occurred while getting Setting the NVIDIA Display Config! NvAPI_DISP_SetDisplayConfig() returned error code {NVStatus}");
+ return false;
+ }
+ }
+ else
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Skipping setting the NVIDIA Display Config as there isn't one provided in the configuration.");
}
}
@@ -1994,171 +2324,171 @@ namespace DisplayMagicianShared.NVIDIA
NVAPI_STATUS NVStatus = NVAPI_STATUS.NVAPI_ERROR;
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want to turn on colour if it's user set colour.");
- // Now we try to set each display color
- foreach (var colorDataDict in displayConfig.ColorConfig.ColorData)
+ // Go through the physical adapters
+ foreach (var physicalGPU in displayConfig.PhysicalAdapters)
{
- NV_COLOR_DATA_V5 colorData = colorDataDict.Value;
- string displayId = colorDataDict.Key;
- try
- {
- UInt32 displayIdAsUInt32 = UInt32.Parse(displayId);
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Processing settings for Physical GPU #{physicalGPU.Key}");
+ NVIDIA_PER_ADAPTER_CONFIG myAdapter = physicalGPU.Value;
+ UInt32 myAdapterIndex = physicalGPU.Key;
- if (!ActiveDisplayConfig.ColorConfig.ColorData.ContainsKey(displayId))
+ foreach (var displayDict in myAdapter.Displays)
+ {
+ NVIDIA_PER_DISPLAY_CONFIG myDisplay = displayDict.Value;
+ UInt32 displayId = displayDict.Key;
+
+ // Now we try to set each display settings
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want to process settings for display {displayId}.");
+
+ if (!ActiveDisplayConfig.PhysicalAdapters[myAdapterIndex].Displays.ContainsKey(displayId))
{
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: Display {displayId} doesn't exist in this setup, so skipping setting the NVIDIA Color Settings.");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Display {displayId} doesn't exist in this setup, so skipping overriding any NVIDIA display Settings.");
continue;
}
- // If this is a setting that says it uses user colour settings, then we turn it off
- if (ActiveDisplayConfig.ColorConfig.ColorData[displayId].ColorSelectionPolicy != colorData.ColorSelectionPolicy)
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want to turn on colour if it's user set colour.");
+ // Now we try to set each display color
+
+ NV_COLOR_DATA_V5 colorData = myDisplay.ColorData;
+ try
{
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want to use custom NVIDIA HDR Colour for display {displayId}.");
-
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want the standard colour settings to be {displayConfig.ColorConfig.ColorData[displayId].ColorSelectionPolicy.ToString("G")} for Mosaic display {displayId}.");
- colorData = displayConfig.ColorConfig.ColorData[displayId];
-
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want the standard colour settings to be {displayConfig.ColorConfig.ColorData[displayId].ColorSelectionPolicy.ToString("G")} and they are {ActiveDisplayConfig.ColorConfig.ColorData[displayId].ColorSelectionPolicy.ToString("G")} for Mosaic display {displayId}.");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want to turn off standard colour mode for Mosaic display {displayId}.");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want standard colour settings Color selection policy {colorData.ColorSelectionPolicy.ToString("G")} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want standard colour settings BPC {colorData.Bpc} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want standard colour settings colour format {colorData.ColorFormat} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want standard colour settings colourimetry {colorData.Colorimetry} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want standard colour settings colour depth {colorData.Depth} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want standard colour settings dynamic range {colorData.DynamicRange} for Mosaic display {displayId}");
-
- // Set the command as a 'SET'
- colorData.Cmd = NV_COLOR_CMD.NV_COLOR_CMD_SET;
- NVStatus = NVImport.NvAPI_Disp_ColorControl(displayIdAsUInt32, ref colorData);
- if (NVStatus == NVAPI_STATUS.NVAPI_OK)
+ // If this is a setting that says it uses user colour settings, then we turn it off
+ if (ActiveDisplayConfig.PhysicalAdapters[myAdapterIndex].Displays[displayId].ColorData.ColorSelectionPolicy != colorData.ColorSelectionPolicy)
{
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: NvAPI_Disp_ColorControl returned OK. BPC is set to {colorData.Bpc.ToString("G")}. Color Format is set to {colorData.ColorFormat.ToString("G")}. Colorimetry is set to {colorData.Colorimetry.ToString("G")}. Color Selection Policy is set to {colorData.ColorSelectionPolicy.ToString("G")}. Color Depth is set to {colorData.Depth.ToString("G")}. Dynamic Range is set to {colorData.DynamicRange.ToString("G")}");
- switch (colorData.ColorSelectionPolicy)
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want to use custom NVIDIA HDR Colour for display {displayId}.");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want the standard colour settings to be {myDisplay.ColorData.ColorSelectionPolicy.ToString("G")} and they are {ActiveDisplayConfig.PhysicalAdapters[myAdapterIndex].Displays[displayId].ColorData.ColorSelectionPolicy.ToString("G")} for Mosaic display {displayId}.");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want to turn off standard colour mode for Mosaic display {displayId}.");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want standard colour settings Color selection policy {colorData.ColorSelectionPolicy.ToString("G")} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want standard colour settings BPC {colorData.Bpc} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want standard colour settings colour format {colorData.ColorFormat} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want standard colour settings colourimetry {colorData.Colorimetry} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want standard colour settings colour depth {colorData.Depth} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want standard colour settings dynamic range {colorData.DynamicRange} for Mosaic display {displayId}");
+
+ // Set the command as a 'SET'
+ colorData.Cmd = NV_COLOR_CMD.NV_COLOR_CMD_SET;
+ NVStatus = NVImport.NvAPI_Disp_ColorControl(displayId, ref colorData);
+ if (NVStatus == NVAPI_STATUS.NVAPI_OK)
{
- case NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_USER:
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: Color Selection Policy is set to NV_COLOR_SELECTION_POLICY_USER so the color settings have been set by the user in the NVIDIA Control Panel.");
- break;
- case NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_BEST_QUALITY: // Also matches NV_COLOR_SELECTION_POLICY_DEFAULT as it is 1
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: Color Selection Policy is set to NV_COLOR_SELECTION_POLICY_BEST_QUALITY so the color settings are being handled by the Windows OS.");
- break;
- case NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_UNKNOWN:
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: Color Selection Policy is set to NV_COLOR_SELECTION_POLICY_UNKNOWN so the color settings aren't being handled by either the Windows OS or the NVIDIA Setup!");
- break;
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: NvAPI_Disp_ColorControl returned OK. BPC is set to {colorData.Bpc.ToString("G")}. Color Format is set to {colorData.ColorFormat.ToString("G")}. Colorimetry is set to {colorData.Colorimetry.ToString("G")}. Color Selection Policy is set to {colorData.ColorSelectionPolicy.ToString("G")}. Color Depth is set to {colorData.Depth.ToString("G")}. Dynamic Range is set to {colorData.DynamicRange.ToString("G")}");
+ switch (colorData.ColorSelectionPolicy)
+ {
+ case NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_USER:
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: Color Selection Policy is set to NV_COLOR_SELECTION_POLICY_USER so the color settings have been set by the user in the NVIDIA Control Panel.");
+ break;
+ case NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_BEST_QUALITY: // Also matches NV_COLOR_SELECTION_POLICY_DEFAULT as it is 1
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: Color Selection Policy is set to NV_COLOR_SELECTION_POLICY_BEST_QUALITY so the color settings are being handled by the Windows OS.");
+ break;
+ case NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_UNKNOWN:
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: Color Selection Policy is set to NV_COLOR_SELECTION_POLICY_UNKNOWN so the color settings aren't being handled by either the Windows OS or the NVIDIA Setup!");
+ break;
+ }
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: Your monitor {displayId} doesn't support the requested color settings. BPC = {colorData.Bpc.ToString("G")}. Color Format = {colorData.ColorFormat.ToString("G")}. Colorimetry = {colorData.Colorimetry.ToString("G")}. Color Selection Policy = {colorData.ColorSelectionPolicy.ToString("G")}. Color Depth = {colorData.Depth.ToString("G")}. Dynamic Range = {colorData.DynamicRange.ToString("G")}. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: The input buffer is not large enough to hold it's contents. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: The NvAPI API needs to be initialized first. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: This entry point not available in this NVIDIA Driver. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: A miscellaneous error occurred. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
+ }
+ else
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: Some non standard error occurred while seting the color settings! NvAPI_Disp_ColorControl() returned error code {NVStatus}. It's most likely that your monitor {displayId} doesn't support this color mode.");
}
}
- else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED)
+ else
{
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: Your monitor {displayId} doesn't support the requested color settings. BPC = {colorData.Bpc.ToString("G")}. Color Format = {colorData.ColorFormat.ToString("G")}. Colorimetry = {colorData.Colorimetry.ToString("G")}. Color Selection Policy = {colorData.ColorSelectionPolicy.ToString("G")}. Color Depth = {colorData.Depth.ToString("G")}. Dynamic Range = {colorData.DynamicRange.ToString("G")}. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want only want to turn on custom NVIDIA colour settings if needed for display {displayId}, and that currently isn't required. Skipping changing NVIDIA colour mode.");
}
- else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER)
+ }
+ catch (Exception ex)
+ {
+ SharedLogger.logger.Error(ex, $"NVIDIALibrary/SetActiveConfigOverride: Exception caused while turning on NVIDIA custom colour settings for display {displayId}.");
+ }
+
+
+
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want to turn on NVIDIA HDR colour if it's user wants to use NVIDIA HDR colour.");
+ // Now we try to set each display color
+
+ NV_HDR_COLOR_DATA_V2 hdrColorData = myDisplay.HdrColorData;
+ try
+ {
+
+ // if it's HDR and it's a different mode than what we are in now, then set HDR
+ if (ActiveDisplayConfig.PhysicalAdapters[myAdapterIndex].Displays[displayId].HdrColorData.HdrMode != hdrColorData.HdrMode)
{
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: The input buffer is not large enough to hold it's contents. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
- }
- else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID)
- {
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
- }
- else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED)
- {
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: The NvAPI API needs to be initialized first. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
- }
- else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION)
- {
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: This entry point not available in this NVIDIA Driver. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
- }
- else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR)
- {
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: A miscellaneous error occurred. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want to turn on user-set HDR mode for display {displayId} as it's supposed to be on.");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: HDR mode is currently {ActiveDisplayConfig.PhysicalAdapters[myAdapterIndex].Displays[displayId].HdrColorData.HdrMode.ToString("G")} for Mosaic display {displayId}.");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want HDR settings BPC {hdrColorData.HdrBpc} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want HDR settings HDR Colour Format {hdrColorData.HdrColorFormat} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want HDR settings HDR dynamic range {hdrColorData.HdrDynamicRange} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want HDR settings HDR Mode {hdrColorData.HdrMode} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want HDR settings Mastering Display Data {hdrColorData.MasteringDisplayData} for Mosaic display {displayId}");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want HDR settings Static Meradata Description ID {hdrColorData.StaticMetadataDescriptorId} for Mosaic display {displayId}");
+ // Apply the HDR removal
+ hdrColorData.Cmd = NV_HDR_CMD.CMD_SET;
+ NVStatus = NVImport.NvAPI_Disp_HdrColorControl(displayId, ref hdrColorData);
+ if (NVStatus == NVAPI_STATUS.NVAPI_OK)
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: NvAPI_Disp_HdrColorControl returned OK. We just successfully turned off the HDR mode for Mosaic display {displayId}.");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: The input buffer is not large enough to hold it's contents. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: The NvAPI API needs to be initialized first. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: This entry point not available in this NVIDIA Driver. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
+ }
+ else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR)
+ {
+ SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: A miscellaneous error occurred. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
+ }
+ else
+ {
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: Some non standard error occurred while getting Mosaic Topology! NvAPI_Disp_HdrColorControl() returned error code {NVStatus}. It's most likely that your monitor {displayId} doesn't support HDR.");
+ }
}
else
{
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: Some non standard error occurred while seting the color settings! NvAPI_Disp_ColorControl() returned error code {NVStatus}. It's most likely that your monitor {displayId} doesn't support this color mode.");
+ SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want only want to turn on custom NVIDIA HDR if needed for display {displayId} and that currently isn't required. Skipping changing NVIDIA HDR mode.");
}
}
- else
+ catch (Exception ex)
{
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want only want to turn on custom NVIDIA colour settings if needed for display {displayId}, and that currently isn't required. Skipping changing NVIDIA colour mode.");
+ SharedLogger.logger.Error(ex, $"NVIDIALibrary/SetActiveConfigOverride: Exception caused while turning on custom NVIDIA HDR colour settings for display {displayId}.");
}
+
}
- catch (Exception ex)
- {
- SharedLogger.logger.Error(ex, $"NVIDIALibrary/SetActiveConfigOverride: Exception caused while turning on NVIDIA custom colour settings for display {displayId}.");
- }
+
+
}
-
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want to turn on NVIDIA HDR colour if it's user wants to use NVIDIA HDR colour.");
- // Now we try to set each display color
- foreach (var hdrColorDataDict in displayConfig.HdrConfig.HdrColorData)
- {
- NV_HDR_COLOR_DATA_V2 hdrColorData = hdrColorDataDict.Value;
- string displayId = hdrColorDataDict.Key;
-
- try
- {
- UInt32 displayIdAsUInt32 = UInt32.Parse(displayId);
-
- if (!ActiveDisplayConfig.HdrConfig.HdrColorData.ContainsKey(displayId))
- {
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: Display {displayId} doesn't exist in this setup, so skipping setting the HdrColorData.");
- continue;
- }
-
- // if it's HDR and it's a different mode than what we are in now, then set HDR
- if (ActiveDisplayConfig.HdrConfig.HdrColorData[displayId].HdrMode != hdrColorData.HdrMode)
- {
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want to turn on user-set HDR mode for display {displayId} as it's supposed to be on.");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: HDR mode is currently {ActiveDisplayConfig.HdrConfig.HdrColorData[displayId].HdrMode.ToString("G")} for Mosaic display {displayId}.");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want HDR settings BPC {hdrColorData.HdrBpc} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want HDR settings HDR Colour Format {hdrColorData.HdrColorFormat} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want HDR settings HDR dynamic range {hdrColorData.HdrDynamicRange} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want HDR settings HDR Mode {hdrColorData.HdrMode} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want HDR settings Mastering Display Data {hdrColorData.MasteringDisplayData} for Mosaic display {displayId}");
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want HDR settings Static Meradata Description ID {hdrColorData.StaticMetadataDescriptorId} for Mosaic display {displayId}");
- // Apply the HDR removal
- hdrColorData.Cmd = NV_HDR_CMD.CMD_SET;
- NVStatus = NVImport.NvAPI_Disp_HdrColorControl(displayIdAsUInt32, ref hdrColorData);
- if (NVStatus == NVAPI_STATUS.NVAPI_OK)
- {
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: NvAPI_Disp_HdrColorControl returned OK. We just successfully turned off the HDR mode for Mosaic display {displayId}.");
- }
- else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER)
- {
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: The input buffer is not large enough to hold it's contents. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
- }
- else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID)
- {
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
- }
- else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED)
- {
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: The NvAPI API needs to be initialized first. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
- }
- else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION)
- {
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: This entry point not available in this NVIDIA Driver. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
- }
- else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR)
- {
- SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: A miscellaneous error occurred. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
- }
- else
- {
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: Some non standard error occurred while getting Mosaic Topology! NvAPI_Disp_HdrColorControl() returned error code {NVStatus}. It's most likely that your monitor {displayId} doesn't support HDR.");
- }
- }
- else
- {
- SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want only want to turn on custom NVIDIA HDR if needed for display {displayId} and that currently isn't required. Skipping changing NVIDIA HDR mode.");
- }
- }
- catch (Exception ex)
- {
- SharedLogger.logger.Error(ex, $"NVIDIALibrary/SetActiveConfigOverride: Exception caused while turning on custom NVIDIA HDR colour settings for display {displayId}.");
- }
- }
-
-
}
else
{
diff --git a/DisplayMagicianShared/ProfileRepository.cs b/DisplayMagicianShared/ProfileRepository.cs
index 1289e1c..5d112b6 100644
--- a/DisplayMagicianShared/ProfileRepository.cs
+++ b/DisplayMagicianShared/ProfileRepository.cs
@@ -839,43 +839,7 @@ namespace DisplayMagicianShared
// We do the actual change we were trying to do
try
{
-
- // Now we try to patch in a Windows Taskbar Stuck Rects list into the json if there isnt one
- SharedLogger.logger.Trace($"ProfileRepository/MigrateJsonToLatestVersion: Looking for missing Windows Taskbar layout.");
- // Create a default object (an empty list)
- List taskBarStuckRectangles = new List();
- for (int i = 0; i < root.Count; i++)
- {
- JObject profile = (JObject)root[i];
- JArray WindowsTaskBarLayout = (JArray)profile.SelectToken("WindowsDisplayConfig.TaskBarLayout");
- if (WindowsTaskBarLayout == null)
- {
- JObject WindowsDisplayConfig = (JObject)profile.SelectToken("WindowsDisplayConfig");
- JArray newTaskBarLayout = JArray.FromObject(taskBarStuckRectangles);
- WindowsDisplayConfig.Add("TaskBarLayout",newTaskBarLayout);
- changedJson = true;
- SharedLogger.logger.Trace($"ProfileRepository/MigrateJsonToLatestVersion: Patched missing Windows TaskBarLayout in profile {profile.SelectToken("Name")} (index {i}).");
- }
- }
-
- // Now we try to patch in a Windows Taskbar Settings list into the json if there isnt one
- SharedLogger.logger.Trace($"ProfileRepository/MigrateJsonToLatestVersion: Looking for missing Windows Taskbar settings.");
- // Create a default object using whatever the taskbar settings are right now
- // (We're assuming the user keeps these settings standard)
- TaskBarSettings taskBarSettings = TaskBarSettings.GetCurrent();
- for (int i = 0; i < root.Count; i++)
- {
- JObject profile = (JObject)root[i];
- JObject WindowsTaskBarSettings = (JObject)profile.SelectToken("WindowsDisplayConfig.TaskBarSettings");
- if (WindowsTaskBarSettings == null)
- {
- JObject WindowsDisplayConfig = (JObject)profile.SelectToken("WindowsDisplayConfig");
- JObject newTaskBarSettings = JObject.FromObject(taskBarSettings);
- WindowsDisplayConfig.Add("TaskBarSettings", newTaskBarSettings);
- changedJson = true;
- SharedLogger.logger.Trace($"ProfileRepository/MigrateJsonToLatestVersion: Patched missing Windows TaskBarSettings in profile {profile.SelectToken("Name")} (index {i}).");
- }
- }
+ // Nothing to patch at the moment!
}
catch (JsonReaderException ex)
{
diff --git a/DisplayMagicianShared/Utils.cs b/DisplayMagicianShared/Utils.cs
index d382088..57d2937 100644
--- a/DisplayMagicianShared/Utils.cs
+++ b/DisplayMagicianShared/Utils.cs
@@ -1,6 +1,7 @@
using Microsoft.Win32;
using System;
using System.Collections.Generic;
+using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
@@ -8,26 +9,259 @@ using System.Threading.Tasks;
namespace DisplayMagicianShared
{
- class Utils
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
+ public struct WINDOWPOS
{
- [StructLayout(LayoutKind.Sequential)]
- public struct RECT
+ public IntPtr hWnd;
+ public IntPtr hwndInsertAfter;
+ public int x;
+ public int y;
+ public int cx;
+ public int cy;
+ public SET_WINDOW_POSITION_FLAGS flags;
+
+ // Returns the WINDOWPOS structure pointed to by the lParam parameter
+ // of a WM_WINDOWPOSCHANGING or WM_WINDOWPOSCHANGED message.
+ public static WINDOWPOS FromMessage(IntPtr lParam)
{
- public int left;
- public int top;
- public int right;
- public int bottom;
+ // Marshal the lParam parameter to an WINDOWPOS structure,
+ // and return the new structure
+ return (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS));
}
- [Flags]
- public enum SendMessageTimeoutFlag : uint
+ // Replaces the original WINDOWPOS structure pointed to by the lParam
+ // parameter of a WM_WINDOWPOSCHANGING or WM_WINDOWPSCHANGING message
+ // with this one, so that the native window will be able to see any
+ // changes that we have made to its values.
+ public void UpdateMessage(IntPtr lParam)
{
- SMTO_NORMAL = 0x0,
- SMTO_BLOCK = 0x1,
- SMTO_ABORTIFHUNG = 0x2,
- SMTO_NOTIMEOUTIFNOTHUNG = 0x8,
- SMTO_ERRORONEXIT = 0x20
+ // Marshal this updated structure back to lParam so the native
+ // window can respond to our changes.
+ // The old structure that it points to should be deleted, too.
+ Marshal.StructureToPtr(this, lParam, true);
}
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
+ public struct RECT
+ {
+ public Int32 left;
+ public Int32 top;
+ public Int32 right;
+ public Int32 bottom;
+ }
+
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 8)]
+ public struct APPBARDATA
+ {
+ public int cbSize;
+ public IntPtr hWnd;
+ public uint uCallbackMessage;
+ public ABEDGE uEdge;
+ public RECT rc;
+ public int lParam;
+ }
+
+
+
+ ///
+ /// The MONITORINFOEX structure contains information about a display monitor.
+ /// The GetMonitorInfo function stores information into a MONITORINFOEX structure or a MONITORINFO structure.
+ /// The MONITORINFOEX structure is a superset of the MONITORINFO structure. The MONITORINFOEX structure adds a string member to contain a name
+ /// for the display monitor.
+ ///
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
+ public struct MONITORINFOEX
+ {
+ ///
+ /// The size, in bytes, of the structure. Set this member to sizeof(MONITORINFOEX) (72) before calling the GetMonitorInfo function.
+ /// Doing so lets the function determine the type of structure you are passing to it.
+ ///
+ public UInt32 cbSize;
+
+ ///
+ /// A RECT structure that specifies the display monitor rectangle, expressed in virtual-screen coordinates.
+ /// Note that if the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.
+ ///
+ public RECT rcMonitor;
+
+ ///
+ /// A RECT structure that specifies the work area rectangle of the display monitor that can be used by applications,
+ /// expressed in virtual-screen coordinates. Windows uses this rectangle to maximize an application on the monitor.
+ /// The rest of the area in rcMonitor contains system windows such as the task bar and side bars.
+ /// Note that if the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.
+ ///
+ public RECT rcWork;
+
+ ///
+ /// The attributes of the display monitor.
+ ///
+ /// This member can be the following value:
+ /// 1 : MONITORINFOF_PRIMARY
+ ///
+ public UInt32 dwFlags;
+
+ ///
+ /// A string that specifies the device name of the monitor being used. Most applications have no use for a display monitor name,
+ /// and so can save some bytes by using a MONITORINFO structure.
+ ///
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = Utils.CCHDEVICENAME)]
+ public string szDevice;
+
+ /*public void Init()
+ {
+ this.cbSize = 40 + 2 * Utils.CCHDEVICENAME;
+ this.DeviceName = string.Empty;
+ }*/
+ }
+
+
+ ///
+ /// The MONITORINFO structure contains information about a display monitor.
+ /// The GetMonitorInfo function stores information into a MONITORINFOEX structure or a MONITORINFO structure.
+ /// The MONITORINFOEX structure is a superset of the MONITORINFO structure. The MONITORINFOEX structure adds a string member to contain a name
+ /// for the display monitor.
+ ///
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
+ public struct MONITORINFO
+ {
+ ///
+ /// The size, in bytes, of the structure. Set this member to sizeof(MONITORINFOEX) (72) before calling the GetMonitorInfo function.
+ /// Doing so lets the function determine the type of structure you are passing to it.
+ ///
+ public UInt32 cbSize;
+
+ ///
+ /// A RECT structure that specifies the display monitor rectangle, expressed in virtual-screen coordinates.
+ /// Note that if the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.
+ ///
+ public RECT rcMonitor;
+
+ ///
+ /// A RECT structure that specifies the work area rectangle of the display monitor that can be used by applications,
+ /// expressed in virtual-screen coordinates. Windows uses this rectangle to maximize an application on the monitor.
+ /// The rest of the area in rcMonitor contains system windows such as the task bar and side bars.
+ /// Note that if the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.
+ ///
+ public RECT rcWork;
+
+ ///
+ /// The attributes of the display monitor.
+ ///
+ /// This member can be the following value:
+ /// 1 : MONITORINFOF_PRIMARY
+ ///
+ public UInt32 dwFlags;
+
+ /*public void Init()
+ {
+ this.cbSize = 40 + 2 * Utils.CCHDEVICENAME;
+ this.DeviceName = string.Empty;
+ }*/
+ }
+
+
+ [Flags]
+ public enum SET_WINDOW_POSITION_FLAGS : UInt32
+ {
+ SWP_ASYNCWINDOWPOS = 0x4000,
+ SWP_DEFERERASE = 0x2000,
+ SWP_DRAWFRAME = 0x0020,
+ SWP_FRAMECHANGED = 0x0020,
+ SWP_HIDEWINDOW = 0x0080,
+ SWP_NOACTIVATE = 0x0010,
+ SWP_NOCOPYBITS = 0x0100,
+ SWP_NOMOVE = 0x0002,
+ SWP_NOOWNERZORDER = 0x0200,
+ SWP_NOREDRAW = 0x0008,
+ SWP_NOREPOSITION = 0x0200,
+ SWP_NOSENDCHANGING = 0x0400,
+ SWP_NOSIZE = 0x0001,
+ SWP_NOZORDER = 0x0004,
+ SWP_SHOWWINDOW = 0x0040,
+ }
+
+ public enum SET_WINDOW_POSITION_ZORDER : Int32
+ {
+ HWND_TOP = 0,
+ HWND_BOTTOM = 1,
+ HWND_TOPMOST = -1,
+ HWND_NOTOPMOST = -2,
+ }
+
+
+ [Flags]
+ public enum SendMessageTimeoutFlag : uint
+ {
+ SMTO_NORMAL = 0x0,
+ SMTO_BLOCK = 0x1,
+ SMTO_ABORTIFHUNG = 0x2,
+ SMTO_NOTIMEOUTIFNOTHUNG = 0x8,
+ SMTO_ERRORONEXIT = 0x20
+ }
+
+ public enum ABEDGE : UInt32
+ {
+ ABE_LEFT = 0x0,
+ ABE_TOP = 0x1,
+ ABE_RIGHT = 0x2,
+ ABE_BOTTOM = 0x3,
+ }
+
+ [Flags]
+ public enum MOUSEKEYS : UInt32
+ {
+ MK_LBUTTON = 0x1,
+ MK_RBUTTON = 0x2,
+ MK_SHIFT = 0x4,
+ MK_CONTROL = 0x8,
+ MK_MBUTTON = 0x10,
+ MK_XBUTTON1 = 0x20,
+ MK_XBUTTON2 = 0x40,
+ }
+
+
+ enum SYSCOMMAND : int
+ {
+ SC_SIZE = 0xF000,
+ SC_MOVE = 0xF010,
+ SC_MINIMIZE = 0xF020,
+ SC_MAXIMIZE = 0xF030,
+ SC_NEXTWINDOW = 0xF040,
+ SC_PREVWINDOW = 0xF050,
+ SC_CLOSE = 0xF060,
+ SC_VSCROLL = 0xF070,
+ SC_HSCROLL = 0xF080,
+ SC_MOUSEMENU = 0xF090,
+ SC_KEYMENU = 0xF100,
+ SC_ARRANGE = 0xF110,
+ SC_RESTORE = 0xF120,
+ SC_TASKLIST = 0xF130,
+ SC_SCREENSAVE = 0xF140,
+ SC_HOTKEY = 0xF150,
+ //#if(WINVER >= 0x0400) //Win95
+ SC_DEFAULT = 0xF160,
+ SC_MONITORPOWER = 0xF170,
+ SC_CONTEXTHELP = 0xF180,
+ SC_SEPARATOR = 0xF00F,
+ //#endif /* WINVER >= 0x0400 */
+
+ //#if(WINVER >= 0x0600) //Vista
+ SCF_ISSECURE = 0x00000001,
+ //#endif /* WINVER >= 0x0600 */
+
+ /*
+ * Obsolete names
+ */
+ SC_ICON = SC_MINIMIZE,
+ SC_ZOOM = SC_MAXIMIZE,
+ }
+
+
+ class Utils
+ {
+
#region enum HChangeNotifyEventID
///
@@ -298,19 +532,43 @@ namespace DisplayMagicianShared
[DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam);
-
+
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, Int16 wParam, Int16 lParam);
+
+
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFOEX lpmi);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumProc lpfnEnum, IntPtr dwData);
+
[DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern void SHChangeNotify(HChangeNotifyEventID wEventId,
HChangeNotifyFlags uFlags,
IntPtr dwItem1,
IntPtr dwItem2);
+ [DllImport("shell32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern int SHAppBarMessage(uint dwMessage, ref APPBARDATA pData);
+
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
@@ -318,6 +576,44 @@ namespace DisplayMagicianShared
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetWindowPos(IntPtr hWnd, SET_WINDOW_POSITION_ZORDER hWndInsertAfter, int x, int y, int cx, int cy, SET_WINDOW_POSITION_FLAGS uFlags);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ private static extern int ShowWindow(IntPtr hwnd, int command);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
+
+
+ ///
+ /// The MoveWindow function changes the position and dimensions of the specified window. For a top-level window, the
+ /// position and dimensions are relative to the upper-left corner of the screen. For a child window, they are relative
+ /// to the upper-left corner of the parent window's client area.
+ ///
+ /// Go to https://msdn.microsoft.com/en-us/library/windows/desktop/ms633534%28v=vs.85%29.aspx for more
+ /// information
+ ///
+ ///
+ /// C++ ( hWnd [in]. Type: HWND )
Handle to the window.
+ /// C++ ( X [in]. Type: int )
Specifies the new position of the left side of the window.
+ /// C++ ( Y [in]. Type: int )
Specifies the new position of the top of the window.
+ /// C++ ( nWidth [in]. Type: int )
Specifies the new width of the window.
+ /// C++ ( nHeight [in]. Type: int )
Specifies the new height of the window.
+ ///
+ /// C++ ( bRepaint [in]. Type: bool )
Specifies whether the window is to be repainted. If this
+ /// parameter is TRUE, the window receives a message. If the parameter is FALSE, no repainting of any kind occurs. This
+ /// applies to the client area, the nonclient area (including the title bar and scroll bars), and any part of the
+ /// parent window uncovered as a result of moving a child window.
+ ///
+ ///
+ /// If the function succeeds, the return value is nonzero.
If the function fails, the return value is zero.
+ ///
To get extended error information, call GetLastError.
+ ///
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
+
public static bool IsWindows11()
{
var reg = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
@@ -328,11 +624,41 @@ namespace DisplayMagicianShared
return currentBuild >= 22000;
}
- public static int MakeLParam(int p, int p_2)
+ public static int MakeLParam(int p, int p_2)
{
return ((p_2 << 16) | (p & 0xFFFF));
}
+ internal delegate bool MonitorEnumProc(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData);
+
+ public static List EnumMonitors()
+ {
+ List monitors = new List();
+ EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero,
+ delegate (IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData)
+ {
+ MONITORINFOEX mi = new MONITORINFOEX();
+ mi.cbSize = (uint)Marshal.SizeOf(mi);
+ bool success = GetMonitorInfo(hMonitor, ref mi);
+ if (success)
+ {
+ monitors.Add(mi);
+ }
+ return true;
+ }, IntPtr.Zero);
+ return monitors;
+ }
+
+ private static bool MonitorEnumCallBack(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData)
+ {
+ MONITORINFOEX mon_info = new MONITORINFOEX();
+ mon_info.cbSize = (UInt32)Marshal.SizeOf(typeof(MONITORINFOEX));
+ //mon_info.szDevice = new char[Utils.CCHDEVICENAME];
+ GetMonitorInfo(hMonitor, ref mon_info);
+ ///Monitor info is stored in 'mon_info'
+ return true;
+ }
+
/*public static bool RefreshNotificationTray()
{
Utils.SHChangeNotify(Utils.HChangeNotifyEventID.SHCNE_ASSOCCHANGED, Utils.HChangeNotifyFlags.SHCNF_IDLIST, IntPtr.Zero, IntPtr.Zero);
@@ -344,13 +670,84 @@ namespace DisplayMagicianShared
return true;
}*/
+ public static Point PointFromLParam(IntPtr lParam)
+ {
+ return new Point((int)(lParam) & 0xFFFF, ((int)(lParam) >> 16) & 0xFFFF);
+ }
+
+ public static IntPtr LParamFromPoint(Point point)
+ {
+ return (IntPtr)((point.Y << 16) | (point.X & 0xFFFF));
+ }
+
+ public static IntPtr LParamFromPoint(int x, int y)
+ {
+ return (IntPtr)((y << 16) | (x & 0xFFFF));
+ }
+
+
public const int NULL = 0;
public const int HWND_BROADCAST = 0xffff;
+ public const int WM_ENTERSIZEMOVE = 0x0231;
+ public const int WM_EXITSIZEMOVE = 0x0232;
+ public const int WM_WINDOWPOSCHANGING = 0x0046;
+ public const int WM_WINDOWPOSCHANGED = 0x0047;
+ public const int WM_SYSCOMMAND = 0x112;
+ public const int WM_NOTIFY = 0xA005;
public const int WM_SETTINGCHANGE = 0x001a;
+ public const int WM_THEMECHANGED = 0x031a;
public const int WM_MOUSEMOVE = 0x0200;
- public const int SPI_SETWORKAREA = 0x002F;
+ public const int SPI_SETWORKAREA = 0x002F;
+ public const int SHELLHOOK = 0xC028;
public const int WM_USER_REFRESHTASKBAR = 0x05CA;
+ public const int WM_USER_451 = 0x05C3;
+ public const int WM_USER_440 = 0x05B8;
+ public const int WM_USER_336 = 0x0550;
+ public const int WM_USER_92 = 0x045C;
+ public const int WM_USER_7 = 0x0407;
+ public const int WM_USER_1 = 0x0401;
+ public const int WM_USER_100 = 0x0464;
+ public const int WM_USER_13 = 0x040D;
public const int wParam_SHELLTRAY = 0x00000006;
+
+ public const int ABM_NEW = 0x00000000;
+ public const int ABM_REMOVE = 0x00000001;
+ public const int ABM_QUERYPOS = 0x00000002;
+ public const int ABM_SETPOS = 0x00000003;
+ public const int ABM_GETSTATE = 0x00000004;
+ public const int ABM_GETTASKBARPOS = 0x00000005;
+ public const int ABM_ACTIVATE = 0x00000006; // lParam == TRUE/FALSE means activate/deactivate
+ public const int ABM_GETAUTOHIDEBAR = 0x00000007;
+ public const int ABM_SETAUTOHIDEBAR = 0x00000008; // this can fail at any time. MUST check the result
+ // lParam = TRUE/FALSE Set/Unset
+ // uEdge = what edge
+ public const int ABM_WINDOWPOSCHANGED = 0x0000009;
+ public const int ABM_SETSTATE = 0x0000000a;
+
+ // these are put in the wparam of callback messages
+ public const int ABN_STATECHANGE = 0x0000000;
+ public const int ABN_POSCHANGED = 0x0000001;
+ public const int ABN_FULLSCREENAPP = 0x0000002;
+ public const int ABN_WINDOWARRANGE = 0x0000003; // lParam == TRUE means hide
+
+ // flags for get state
+ public const int ABS_AUTOHIDE = 0x0000001;
+ public const int ABS_ALWAYSONTOP = 0x0000002;
+
+ public const int ABE_LEFT = 0;
+ public const int ABE_TOP = 1;
+ public const int ABE_RIGHT = 2;
+ public const int ABE_BOTTOM = 3;
+
+ public const int MONITOR_DEFAULTTONULL = 0;
+ public const int MONITOR_DEFAULTTOPRIMARY = 1;
+ public const int MONITOR_DEFAULTTONEAREST = 2;
+
+ // size of a device name string
+ public const int CCHDEVICENAME = 32;
+ public const uint MONITORINFOF_PRIMARY = 1;
+
+
}
diff --git a/DisplayMagicianShared/Windows/CCD.cs b/DisplayMagicianShared/Windows/CCD.cs
index aa114d6..1320a22 100644
--- a/DisplayMagicianShared/Windows/CCD.cs
+++ b/DisplayMagicianShared/Windows/CCD.cs
@@ -8,7 +8,7 @@ using System.Threading.Tasks;
namespace DisplayMagicianShared.Windows
{
- public enum WIN32STATUS : uint
+ public enum WIN32STATUS : UInt32
{
ERROR_SUCCESS = 0,
ERROR_ACCESS_DENIED = 5,
@@ -19,24 +19,29 @@ namespace DisplayMagicianShared.Windows
ERROR_BAD_CONFIGURATION = 1610,
}
- public enum DISPLAYCONFIG_DEVICE_INFO_TYPE : uint
+ public enum DISPLAYCONFIG_DEVICE_INFO_TYPE : UInt32
{
Zero = 0,
- DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1,
- DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2,
- DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3,
- DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4,
- DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5,
- DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6,
- DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = 7,
- DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = 8,
- DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO = 9,
- DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE = 10,
- DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL = 11,
+ DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1, // Specifies the source name of the display device. If the DisplayConfigGetDeviceInfo function is successful, DisplayConfigGetDeviceInfo returns the source name in the DISPLAYCONFIG_SOURCE_DEVICE_NAME structure.
+ DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2, // Specifies information about the monitor. If the DisplayConfigGetDeviceInfo function is successful, DisplayConfigGetDeviceInfo returns info about the monitor in the DISPLAYCONFIG_TARGET_DEVICE_NAME structure.
+ DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3, // Specifies information about the preferred mode of a monitor. If the DisplayConfigGetDeviceInfo function is successful, DisplayConfigGetDeviceInfo returns info about the preferred mode of a monitor in the DISPLAYCONFIG_TARGET_PREFERRED_MODE structure.
+ DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4, // Specifies the graphics adapter name. If the DisplayConfigGetDeviceInfo function is successful, DisplayConfigGetDeviceInfo returns the adapter name in the DISPLAYCONFIG_ADAPTER_NAME structure.
+ DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5, // Specifies how to set the monitor. If the DisplayConfigSetDeviceInfo function is successful, DisplayConfigSetDeviceInfo uses info in the DISPLAYCONFIG_SET_TARGET_PERSISTENCE structure to force the output in a boot-persistent manner.
+ DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6, // Specifies how to set the base output technology for a given target ID. If the DisplayConfigGetDeviceInfo function is successful, DisplayConfigGetDeviceInfo returns base output technology info in the DISPLAYCONFIG_TARGET_BASE_TYPE structure.
+ // Supported by WDDM 1.3 and later user-mode display drivers running on Windows 8.1 and later.
+ DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = 7, // Specifies the state of virtual mode support. If the DisplayConfigGetDeviceInfo function is successful, DisplayConfigGetDeviceInfo returns virtual mode support information in the DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION structure. Supported starting in Windows 10.
+ DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = 8, // Specifies how to set the state of virtual mode support. If the DisplayConfigSetDeviceInfo function is successful, DisplayConfigSetDeviceInfo uses info in the DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION structure to change the state of virtual mode support. Supported starting in Windows 10.
+ DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO = 9, // Specifies information about the state of the HDR Color for a display
+ DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE = 10, // Enables or disables the HDR Color for a display
+ DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL = 11, // Specifies the current SDR white level for an HDR monitor. If the DisplayConfigGetDeviceInfo function is successful, DisplayConfigGetDeviceInfo return SDR white level info in the DISPLAYCONFIG_SDR_WHITE_LEVEL structure.
+ // Supported starting in Windows�10 Fall Creators Update (Version 1709).
+ DISPLAYCONFIG_DEVICE_INFO_GET_MONITOR_SPECIALIZATION = 12,
+ DISPLAYCONFIG_DEVICE_INFO_SET_MONITOR_SPECIALIZATION = 13,
+ DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32 = 0xFFFFFFFF // Only here to
}
[Flags]
- public enum DISPLAYCONFIG_COLOR_ENCODING : uint
+ public enum DISPLAYCONFIG_COLOR_ENCODING : UInt32
{
DISPLAYCONFIG_COLOR_ENCODING_RGB = 0,
DISPLAYCONFIG_COLOR_ENCODING_YCBCR444 = 1,
@@ -46,7 +51,7 @@ namespace DisplayMagicianShared.Windows
}
[Flags]
- public enum DISPLAYCONFIG_SCALING : uint
+ public enum DISPLAYCONFIG_SCALING : UInt32
{
Zero = 0,
DISPLAYCONFIG_SCALING_IDENTITY = 1,
@@ -59,7 +64,7 @@ namespace DisplayMagicianShared.Windows
}
[Flags]
- public enum DISPLAYCONFIG_ROTATION : uint
+ public enum DISPLAYCONFIG_ROTATION : UInt32
{
Zero = 0,
DISPLAYCONFIG_ROTATION_IDENTITY = 1,
@@ -70,7 +75,7 @@ namespace DisplayMagicianShared.Windows
}
[Flags]
- public enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY : uint
+ public enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY : UInt32
{
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER = 4294967295, // - 1
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15 = 0,
@@ -95,7 +100,7 @@ namespace DisplayMagicianShared.Windows
}
[Flags]
- public enum DISPLAYCONFIG_TOPOLOGY_ID : uint
+ public enum DISPLAYCONFIG_TOPOLOGY_ID : UInt32
{
Zero = 0x0,
DISPLAYCONFIG_TOPOLOGY_INTERNAL = 0x00000001,
@@ -106,7 +111,7 @@ namespace DisplayMagicianShared.Windows
}
[Flags]
- public enum DISPLAYCONFIG_PATH_FLAGS : uint
+ public enum DISPLAYCONFIG_PATH_FLAGS : UInt32
{
Zero = 0x0,
DISPLAYCONFIG_PATH_ACTIVE = 0x00000001,
@@ -115,14 +120,14 @@ namespace DisplayMagicianShared.Windows
}
[Flags]
- public enum DISPLAYCONFIG_SOURCE_FLAGS : uint
+ public enum DISPLAYCONFIG_SOURCE_FLAGS : UInt32
{
Zero = 0x0,
DISPLAYCONFIG_SOURCE_IN_USE = 0x00000001,
}
[Flags]
- public enum DISPLAYCONFIG_TARGET_FLAGS : uint
+ public enum DISPLAYCONFIG_TARGET_FLAGS : UInt32
{
Zero = 0x0,
DISPLAYCONFIG_TARGET_IN_USE = 0x00000001,
@@ -134,7 +139,7 @@ namespace DisplayMagicianShared.Windows
}
[Flags]
- public enum QDC : uint
+ public enum QDC : UInt32
{
Zero = 0x0,
// Get all paths
@@ -154,7 +159,7 @@ namespace DisplayMagicianShared.Windows
}
[Flags]
- public enum SDC : uint
+ public enum SDC : UInt32
{
Zero = 0x0,
SDC_TOPOLOGY_public = 0x00000001,
@@ -194,7 +199,7 @@ namespace DisplayMagicianShared.Windows
}
[Flags]
- public enum DISPLAYCONFIG_SCANLINE_ORDERING : uint
+ public enum DISPLAYCONFIG_SCANLINE_ORDERING : UInt32
{
DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0,
DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1,
@@ -205,7 +210,7 @@ namespace DisplayMagicianShared.Windows
}
[Flags]
- public enum DISPLAYCONFIG_PIXELFORMAT : uint
+ public enum DISPLAYCONFIG_PIXELFORMAT : UInt32
{
Zero = 0x0,
DISPLAYCONFIG_PIXELFORMAT_8BPP = 1,
@@ -217,7 +222,7 @@ namespace DisplayMagicianShared.Windows
}
[Flags]
- public enum DISPLAYCONFIG_MODE_INFO_TYPE : uint
+ public enum DISPLAYCONFIG_MODE_INFO_TYPE : UInt32
{
Zero = 0x0,
DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1,
@@ -227,7 +232,7 @@ namespace DisplayMagicianShared.Windows
}
[Flags]
- public enum D3D_VIDEO_SIGNAL_STANDARD : uint
+ public enum D3D_VIDEO_SIGNAL_STANDARD : UInt32
{
Uninitialized = 0,
VesaDmt = 1,
diff --git a/DisplayMagicianShared/Windows/TaskBarLayout.cs b/DisplayMagicianShared/Windows/TaskBarLayout.cs
new file mode 100644
index 0000000..25b278d
--- /dev/null
+++ b/DisplayMagicianShared/Windows/TaskBarLayout.cs
@@ -0,0 +1,861 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using DisplayMagicianShared;
+using Microsoft.Win32;
+using Newtonsoft.Json;
+
+// This file is based on Soroush Falahati's amazing HeliosDisplayManagement software
+// available at https://github.com/falahati/HeliosDisplayManagement
+
+// Substantial modifications made by Terry MacDonald 2022 onwards
+
+namespace DisplayMagicianShared.Windows
+{
+ public class TaskBarLayout
+ {
+
+ public enum TaskBarEdge : UInt32
+ {
+ Left = 0,
+ Top = 1,
+ Right = 2,
+ Bottom = 3
+ }
+
+ [Flags]
+ public enum TaskBarOptions : UInt32
+ {
+ None = 0,
+ AutoHide = 1 << 0,
+ KeepOnTop = 1 << 1,
+ UseSmallIcons = 1 << 2,
+ HideClock = 1 << 3,
+ HideVolume = 1 << 4,
+ HideNetwork = 1 << 5,
+ HidePower = 1 << 6,
+ WindowPreview = 1 << 7,
+ Unknown1 = 1 << 8,
+ Unknown2 = 1 << 9,
+ HideActionCenter = 1 << 10,
+ Unknown3 = 1 << 11,
+ HideLocation = 1 << 12,
+ HideLanguageBar = 1 << 13
+ }
+
+ private const string MainDisplayAddress =
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StuckRects{0:D}";
+
+ private const string MultiDisplayAddress =
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MMStuckRects{0:D}";
+
+ /*private static readonly Dictionary Headers = new Dictionary
+ {
+ {2, new byte[] {0x28, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {3, new byte[] {0x30, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF}}
+ };
+*/
+ public bool ReadFromRegistry(string regKeyValue)
+ {
+ bool MMStuckRectVerFound = false;
+ // Check if key exists
+ int version = 3;
+ string address = string.Format(MultiDisplayAddress, version);
+ if (Registry.CurrentUser.OpenSubKey(address) != null)
+ {
+ MMStuckRectVerFound = true;
+ SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found MMStuckRect3 registry key! {address}");
+ }
+ else
+ {
+ // If it's not version 3, then try version 2
+ version = 2;
+ address = string.Format(MultiDisplayAddress, version);
+ if (Registry.CurrentUser.OpenSubKey(address) != null)
+ {
+ MMStuckRectVerFound = true;
+ SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found MMStuckRect2 registry key! {address}");
+ }
+ else
+ {
+ // It's not v2 or v3, so it must be a single display
+ MMStuckRectVerFound = false;
+ SharedLogger.logger.Warn($"TaskBarStuckRectangle/TaskBarStuckRectangle: Couldn't find an MMStuckRect2 or MMStuckRect3 registry key! Going to test if it is a single display only.");
+ }
+ }
+
+ if (MMStuckRectVerFound)
+ {
+ // Check if value exists
+ if (version >= 2 && version <= 3)
+ {
+ using (var key = Registry.CurrentUser.OpenSubKey(
+ address,
+ RegistryKeyPermissionCheck.ReadSubTree))
+ {
+ var binary = key?.GetValue(regKeyValue) as byte[];
+ if (binary?.Length > 0)
+ {
+ MainScreen = false;
+ RegKeyValue = regKeyValue;
+ Binary = binary;
+ Version = version;
+
+ // Extract the values from the binary byte field
+ PopulateFieldsFromBinary();
+
+ SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: The taskbar for {RegKeyValue} is against the {Edge} edge, is positioned at ({TaskBarLocation.X},{TaskBarLocation.Y}) and is {TaskBarLocation.Width}x{TaskBarLocation.Height} in size.");
+
+ // If we get here then we're done and don't need to continue with the rest of the code.
+ return true;
+ }
+ else
+ {
+ SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Unable to get the TaskBarStuckRectangle binary settings from {regKeyValue} screen.");
+ }
+ }
+ }
+ else
+ {
+ SharedLogger.logger.Error($"TaskBarStuckRectangle/TaskBarStuckRectangle: A MMStuckRect entry was found, but the version of the field is wrong.");
+ }
+ }
+ else
+ {
+ SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: A MMStuckRect entry was NOT found. We will try to find the object in the StuckRect registry key instead");
+ }
+
+ bool StuckRectVerFound = false;
+ // Check if string exists
+ version = 3;
+ address = string.Format(MainDisplayAddress, version);
+ if (Registry.CurrentUser.OpenSubKey(address) != null)
+ {
+ StuckRectVerFound = true;
+ SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found StuckRect3 single display registry key! {address}");
+ }
+ else
+ {
+ // If it's not version 3, then try version 2
+ version = 2;
+ address = string.Format(MainDisplayAddress, version);
+ if (Registry.CurrentUser.OpenSubKey(address) != null)
+ {
+ StuckRectVerFound = true;
+ SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found StuckRect2 single display registry key! {address}");
+ }
+ else
+ {
+ SharedLogger.logger.Error($"TaskBarStuckRectangle/TaskBarStuckRectangle: Couldn't find an single display StuckRect2 or StuckRect3 registry key! So we have to just return after doing nothing as there is nothing we can do.");
+ return false;
+ }
+ }
+
+ if (StuckRectVerFound)
+ {
+ // Check if value exists
+ if (version >= 2 && version <= 3)
+ {
+ using (var key = Registry.CurrentUser.OpenSubKey(
+ address,
+ RegistryKeyPermissionCheck.ReadSubTree))
+ {
+ var binary = key?.GetValue(regKeyValue) as byte[];
+ if (binary?.Length > 0)
+ {
+ MainScreen = true;
+ RegKeyValue = regKeyValue;
+ Binary = binary;
+ Version = version;
+
+ // Extract the values from the binary byte field
+ PopulateFieldsFromBinary();
+
+ SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: The taskbar for {RegKeyValue} is against the {Edge} edge, is positioned at ({TaskBarLocation.X},{TaskBarLocation.Y}) and is {TaskBarLocation.Width}x{TaskBarLocation.Height} in size.");
+ return true;
+ }
+ else
+ {
+ SharedLogger.logger.Error($"TaskBarStuckRectangle/TaskBarStuckRectangle: Unable to get the TaskBarStuckRectangle binary settings from {regKeyValue} screen.");
+ return false;
+ }
+ }
+ }
+ else
+ {
+ SharedLogger.logger.Error($"TaskBarStuckRectangle/TaskBarStuckRectangle: A StuckRect entry was found, but the version of the field is wrong.");
+ return false;
+ }
+ }
+ else
+ {
+ SharedLogger.logger.Error($"TaskBarStuckRectangle/TaskBarStuckRectangle: A StuckRect entry was NOT found. This means we're unable to get the taskbar location, an unable to return a sensible TaskBarStuckRectangle object.");
+ return false;
+ }
+
+ }
+
+ public TaskBarLayout()
+ {
+ }
+
+ public byte[] Binary { get; set; }
+
+ public string RegKeyValue { get; set; }
+
+ public bool MainScreen { get; set; }
+
+ public UInt32 DPI { get; set; }
+
+ public TaskBarEdge Edge { get; set; }
+
+ public Rectangle TaskBarLocation { get; set; }
+
+ public Rectangle StartMenuLocation { get; set; }
+
+ public Rectangle MonitorLocation { get; set; }
+
+ public Size MinSize { get; set; }
+
+ public TaskBarOptions Options { get; set; }
+
+ public uint Rows { get; set; }
+
+ public int Version { get; set; }
+
+ public override bool Equals(object obj) => obj is TaskBarLayout other && this.Equals(other);
+ public bool Equals(TaskBarLayout other)
+ {
+ return Version == other.Version &&
+ RegKeyValue == other.RegKeyValue &&
+ MainScreen == other.MainScreen &&
+ DPI == other.DPI &&
+ Edge == other.Edge &&
+ TaskBarLocation == other.TaskBarLocation &&
+ MinSize == other.MinSize &&
+ Options == other.Options &&
+ Rows == other.Rows;
+ }
+
+ public override int GetHashCode()
+ {
+ return (Version, MainScreen, RegKeyValue, DPI, Edge, TaskBarLocation, MinSize, Options, Rows).GetHashCode();
+ }
+ public static bool operator ==(TaskBarLayout lhs, TaskBarLayout rhs) => lhs.Equals(rhs);
+
+ public static bool operator !=(TaskBarLayout lhs, TaskBarLayout rhs) => !(lhs == rhs);
+
+ static bool Xor(byte[] a, byte[] b)
+
+ {
+
+ int x = a.Length ^ b.Length;
+
+ for (int i = 0; i < a.Length && i < b.Length; ++i)
+
+ {
+
+ x |= a[i] ^ b[i];
+
+ }
+
+ return x == 0;
+
+ }
+
+ private bool PopulateFieldsFromBinary()
+ {
+ // Now we decipher the binary properties features to populate the stuckrectangle
+ // DPI
+ if (Binary.Length < 44)
+ {
+ DPI = 0;
+ }
+ else
+ {
+ DPI = BitConverter.ToUInt32(Binary, 40);
+ }
+ // Edge
+ if (Binary.Length < 16)
+ {
+ Edge = TaskBarEdge.Bottom;
+ }
+ else
+ {
+ Edge = (TaskBarEdge)BitConverter.ToUInt32(Binary, 12);
+ }
+ // Location
+ if (Binary.Length < 40)
+ {
+ TaskBarLocation = Rectangle.Empty;
+ }
+ else
+ {
+ var left = BitConverter.ToInt32(Binary, 24);
+ var top = BitConverter.ToInt32(Binary, 28);
+ var right = BitConverter.ToInt32(Binary, 32);
+ var bottom = BitConverter.ToInt32(Binary, 36);
+
+ TaskBarLocation = Rectangle.FromLTRB(left, top, right, bottom);
+ }
+ // MinSize
+ if (Binary.Length < 24)
+ {
+ MinSize = Size.Empty;
+ }
+ else
+ {
+ var width = BitConverter.ToInt32(Binary, 16);
+ var height = BitConverter.ToInt32(Binary, 20);
+
+ MinSize = new Size(width, height);
+ }
+ // Options
+ if (Binary.Length < 12)
+ {
+ Options = 0;
+ }
+ else
+ {
+ Options = (TaskBarOptions)BitConverter.ToUInt32(Binary, 8);
+ }
+ // Rows
+ if (Binary.Length < 48)
+ {
+ Rows = 1;
+ }
+ else
+ {
+ Rows = BitConverter.ToUInt32(Binary, 44);
+ }
+
+ SharedLogger.logger.Trace($"TaskBarStuckRectangle/PopulateFieldsFromBinary: Grabbed the following settings for {RegKeyValue} from the registry: DPI = {DPI}, Edge = {Edge}, Location = ({TaskBarLocation.X},{TaskBarLocation.Y}), MinSize = {TaskBarLocation.Width}x{TaskBarLocation.Height}, Options = {Options}, Rows = {Rows}.");
+
+ return true;
+ }
+
+ public bool PopulateBinaryFromFields()
+ {
+ // Set the DPI
+ if (Binary.Length < 44)
+ {
+ DPI = 0;
+ var bytes = BitConverter.GetBytes(DPI);
+ Array.Copy(bytes, 0, Binary, 40, 4);
+ }
+ else
+ {
+ var bytes = BitConverter.GetBytes(DPI);
+ Array.Copy(bytes, 0, Binary, 40, 4);
+ }
+ // Edge
+ if (Binary.Length < 16)
+ {
+ Edge = TaskBarEdge.Bottom;
+ var bytes = BitConverter.GetBytes((uint)Edge);
+ Array.Copy(bytes, 0, Binary, 12, 4);
+ }
+ else
+ {
+ var bytes = BitConverter.GetBytes((uint)Edge);
+ Array.Copy(bytes, 0, Binary, 12, 4);
+ }
+ // Location
+ if (Binary.Length < 40)
+ {
+ var bytes = BitConverter.GetBytes(0);
+ Array.Copy(bytes, 0, Binary, 24, 4);
+
+ bytes = BitConverter.GetBytes(0);
+ Array.Copy(bytes, 0, Binary, 28, 4);
+
+ bytes = BitConverter.GetBytes(0);
+ Array.Copy(bytes, 0, Binary, 32, 4);
+
+ bytes = BitConverter.GetBytes(0);
+ Array.Copy(bytes, 0, Binary, 36, 4);
+ }
+ else
+ {
+ var bytes = BitConverter.GetBytes(TaskBarLocation.Left);
+ Array.Copy(bytes, 0, Binary, 24, 4);
+
+ bytes = BitConverter.GetBytes(TaskBarLocation.Top);
+ Array.Copy(bytes, 0, Binary, 28, 4);
+
+ bytes = BitConverter.GetBytes(TaskBarLocation.Right);
+ Array.Copy(bytes, 0, Binary, 32, 4);
+
+ bytes = BitConverter.GetBytes(TaskBarLocation.Bottom);
+ Array.Copy(bytes, 0, Binary, 36, 4);
+ }
+ // MinSize
+ if (Binary.Length < 24)
+ {
+ var bytes = BitConverter.GetBytes(0);
+ Array.Copy(bytes, 0, Binary, 16, 4);
+
+ bytes = BitConverter.GetBytes(0);
+ Array.Copy(bytes, 0, Binary, 20, 4);
+ }
+ else
+ {
+ var bytes = BitConverter.GetBytes(MinSize.Width);
+ Array.Copy(bytes, 0, Binary, 16, 4);
+
+ bytes = BitConverter.GetBytes(MinSize.Height);
+ Array.Copy(bytes, 0, Binary, 20, 4);
+ }
+ // Options
+ if (Binary.Length < 12)
+ {
+ var bytes = BitConverter.GetBytes((uint)0);
+ Array.Copy(bytes, 0, Binary, 8, 4);
+ }
+ else
+ {
+ var bytes = BitConverter.GetBytes((uint)Options);
+ Array.Copy(bytes, 0, Binary, 8, 4);
+ }
+ // Rows
+ if (Binary.Length < 48)
+ {
+ var bytes = BitConverter.GetBytes(1);
+ Array.Copy(bytes, 0, Binary, 44, 4);
+ }
+ else
+ {
+ var bytes = BitConverter.GetBytes(Rows);
+ Array.Copy(bytes, 0, Binary, 44, 4);
+ }
+
+ SharedLogger.logger.Trace($"TaskBarStuckRectangle/PopulateBinaryFromFields: Set the following settings for {RegKeyValue} into registry: DPI = {DPI}, Edge = {Edge}, Location = ({TaskBarLocation.X},{TaskBarLocation.Y}), MinSize = {TaskBarLocation.Width}x{TaskBarLocation.Height}, Options = {Options}, Rows = {Rows}.");
+
+ return true;
+ }
+
+ public bool WriteToRegistry()
+ {
+ // Update the binary with the current settings from the object
+ //PopulateBinaryFromFields();
+
+ // Write the binary field to registry
+ string address;
+ if (MainScreen && RegKeyValue.Equals("Settings"))
+ {
+ address = string.Format(MainDisplayAddress, Version);
+ // Set the Main Screen
+ try
+ {
+ using (var key = Registry.CurrentUser.OpenSubKey(
+ address,
+ RegistryKeyPermissionCheck.ReadWriteSubTree))
+ {
+ key.SetValue(RegKeyValue, Binary);
+ SharedLogger.logger.Trace($"TaskBarStuckRectangle/Apply: Successfully applied TaskBarStuckRectangle registry settings for the {RegKeyValue} Screen in {address}!");
+ }
+ }
+ catch (Exception ex)
+ {
+ SharedLogger.logger.Error(ex, $"TaskBarStuckRectangle/GetCurrent: Unable to set the {RegKeyValue} TaskBarStuckRectangle registry settings in {address} due to an exception!");
+ }
+ }
+ else
+ {
+ address = string.Format(MultiDisplayAddress, Version);
+ // Grab the main screen taskbar placement
+ try
+ {
+ using (var key = Registry.CurrentUser.OpenSubKey(
+ address,
+ RegistryKeyPermissionCheck.ReadWriteSubTree))
+ {
+ key.SetValue(RegKeyValue, Binary);
+ SharedLogger.logger.Trace($"TaskBarStuckRectangle/WriteToRegistry: Successfully applied TaskBarStuckRectangle registry settings for the {RegKeyValue} Screen in {address}!");
+ }
+ }
+ catch (Exception ex)
+ {
+ SharedLogger.logger.Error(ex, $"TaskBarStuckRectangle/WriteToRegistry: Unable to set the {RegKeyValue} TaskBarStuckRectangle registry settings in {address} due to an exception!");
+ }
+ }
+
+ return true;
+ }
+
+ public static Dictionary GetAllCurrentTaskBarLayouts(Dictionary> displaySources)
+ {
+ Dictionary taskBarStuckRectangles = new Dictionary();
+ int state;
+
+ APPBARDATA abd = new APPBARDATA();
+
+ // Sleep delay just for testing so I can get the position of the Start Menu
+ // Note for future me, the Start menu window is moved around the desktop to be next to the start button that is pressed by the user.
+ // e.g. if you have two screens, and you click the right most start button, the Start menu window is moved to be the same as the WorkRect of the
+ // monitor that the start button is on.
+ //System.Threading.Thread.Sleep(5000);
+
+ // Firstly try to get the position of the main screen and main start menu
+ try
+ {
+ // Figure out which monitor this taskbar is on
+ IntPtr mainTaskbarHwnd = Utils.FindWindow("Shell_TrayWnd", "");
+ IntPtr mainMonitorHwnd = Utils.MonitorFromWindow(mainTaskbarHwnd, Utils.MONITOR_DEFAULTTOPRIMARY);
+ //IntPtr startMenuHwnd = Utils.FindWindow("Windows.UI.Core.CoreWindow", "Start");
+
+ //Utils.GetWindowRect(startMenuHwnd, out RECT lpRect);
+
+ // Figure out the monitor coordinates
+ MONITORINFOEX monitorInfo = new MONITORINFOEX();
+ monitorInfo.cbSize = (UInt32)Marshal.SizeOf(typeof(MONITORINFOEX));
+ //monitorInfo.szDevice = new char[Utils.CCHDEVICENAME];
+ Utils.GetMonitorInfo(mainMonitorHwnd, ref monitorInfo);
+
+ abd.hWnd = mainTaskbarHwnd;
+ abd.uEdge = ABEDGE.ABE_BOTTOM;
+ abd.lParam = 0x1;
+ abd.cbSize = Marshal.SizeOf(typeof(APPBARDATA));
+
+ state = Utils.SHAppBarMessage(Utils.ABM_GETTASKBARPOS, ref abd);
+
+ if (state == 1)
+ {
+ int tbWidth = Math.Abs(abd.rc.left - abd.rc.right);
+ int tbHeight = Math.Abs(abd.rc.top - abd.rc.bottom);
+ int monWidth = Math.Abs(monitorInfo.rcMonitor.left - monitorInfo.rcMonitor.right);
+ int monHeight = Math.Abs(monitorInfo.rcMonitor.top - monitorInfo.rcMonitor.bottom);
+
+ TaskBarLayout tbsr = new TaskBarLayout();
+ // Now we're at the point that we should be able to update the binary that we grabbed earlier when the object was created
+ tbsr.ReadFromRegistry(GetRegKeyValueFromDevicePath(displaySources[monitorInfo.szDevice][0].DevicePath));
+ tbsr.Edge = (TaskBarEdge)abd.uEdge;
+ tbsr.MonitorLocation = new System.Drawing.Rectangle(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, monWidth, monHeight);
+ switch (tbsr.Edge)
+ {
+ case TaskBarEdge.Left:
+ tbsr.TaskBarLocation = new System.Drawing.Rectangle(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, tbWidth, tbHeight);
+ break;
+ case TaskBarEdge.Top:
+ tbsr.TaskBarLocation = new System.Drawing.Rectangle(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, tbWidth, tbHeight);
+ break;
+ case TaskBarEdge.Right:
+ tbsr.TaskBarLocation = new System.Drawing.Rectangle(monitorInfo.rcWork.right, monitorInfo.rcWork.top, tbWidth, tbHeight);
+ break;
+ case TaskBarEdge.Bottom:
+ tbsr.TaskBarLocation = new System.Drawing.Rectangle(monitorInfo.rcWork.left, monitorInfo.rcWork.bottom, tbWidth, tbHeight);
+ break;
+ default:
+ // Default is bottom taskbar
+ tbsr.TaskBarLocation = new System.Drawing.Rectangle(monitorInfo.rcWork.left, monitorInfo.rcWork.bottom, tbWidth, tbHeight);
+ break;
+ }
+ tbsr.MainScreen = true;
+
+ // Now as a LAST step we update the Binary field just before we apply it to make sure that the correct binary settings are stored
+ tbsr.PopulateBinaryFromFields();
+
+ taskBarStuckRectangles.Add(monitorInfo.szDevice, tbsr);
+
+ // If it's a main screen, also add a duplicate so we track the main StuckRects settings separately too
+ TaskBarLayout tbsrMain = new TaskBarLayout();
+ tbsrMain.ReadFromRegistry("Settings");
+ tbsrMain.Edge = tbsr.Edge;
+ tbsrMain.MonitorLocation = tbsr.MonitorLocation;
+ tbsrMain.TaskBarLocation = tbsr.TaskBarLocation;
+ tbsrMain.MainScreen = tbsr.MainScreen;
+
+ // Now as a LAST step we update the Binary field just before we apply it to make sure that the correct binary settings are stored
+ tbsrMain.PopulateBinaryFromFields();
+ taskBarStuckRectangles.Add("Settings", tbsrMain);
+ }
+ }
+ catch (Exception ex)
+ {
+ SharedLogger.logger.Error(ex, $"WinLibrary/GetAllCurrentTaskBarPositions: Exception while trying to get the maintaskbar position");
+ }
+
+ // Then go through the secondary windows and get the position of them
+ // Tell Windows to refresh the Other Windows Taskbars if needed
+ IntPtr lastTaskBarWindowHwnd = (IntPtr)Utils.NULL;
+ for (int i = 0; i < 100; i++)
+ {
+ // Find the next "Shell_SecondaryTrayWnd" window
+ IntPtr nextTaskBarWindowHwnd = Utils.FindWindowEx((IntPtr)Utils.NULL, lastTaskBarWindowHwnd, "Shell_SecondaryTrayWnd", null);
+ if (nextTaskBarWindowHwnd == (IntPtr)Utils.NULL)
+ {
+ // No more windows taskbars to notify
+ break;
+ }
+
+ IntPtr secMonitorHwnd = Utils.MonitorFromWindow(nextTaskBarWindowHwnd, Utils.MONITOR_DEFAULTTONEAREST);
+
+ // Figure out the monitor coordinates
+ MONITORINFOEX monitorInfo = new MONITORINFOEX();
+ monitorInfo.cbSize = (UInt32)Marshal.SizeOf(typeof(MONITORINFOEX));
+ //monitorInfo.szDevice = new char[Utils.CCHDEVICENAME];
+ Utils.GetMonitorInfo(secMonitorHwnd, ref monitorInfo);
+
+ // Figure out the position of the taskbar ourselves
+ int monWidth = Math.Abs(monitorInfo.rcMonitor.left - monitorInfo.rcMonitor.right);
+ int monHeight = Math.Abs(monitorInfo.rcMonitor.top - monitorInfo.rcMonitor.bottom);
+ int wrkWidth = Math.Abs(monitorInfo.rcWork.left - monitorInfo.rcWork.right);
+ int wrkHeight = Math.Abs(monitorInfo.rcWork.top - monitorInfo.rcWork.bottom);
+ int tbWidth;
+ int tbHeight;
+
+ TaskBarLayout tbsr = new TaskBarLayout();
+ // Now we're at the point that we should be able to update the binary that we grabbed earlier when the object was created
+ tbsr.ReadFromRegistry(GetRegKeyValueFromDevicePath(displaySources[monitorInfo.szDevice][0].DevicePath));
+ if (monWidth == wrkWidth)
+ {
+ // Taskbar on top or bottom
+ if (monitorInfo.rcMonitor.left == monitorInfo.rcWork.left && monitorInfo.rcMonitor.top == monitorInfo.rcWork.top)
+ {
+ // Taskbar on bottom
+ tbWidth = monWidth;
+ tbHeight = monHeight - wrkHeight;
+ tbsr.TaskBarLocation = new System.Drawing.Rectangle(monitorInfo.rcMonitor.left, monitorInfo.rcWork.bottom, tbWidth, tbHeight);
+ tbsr.Edge = TaskBarEdge.Bottom;
+ }
+ else if (monitorInfo.rcMonitor.right == monitorInfo.rcWork.right && monitorInfo.rcMonitor.bottom == monitorInfo.rcWork.bottom)
+ {
+ // Taskbar on top
+ tbWidth = monWidth;
+ tbHeight = monHeight - wrkHeight;
+ tbsr.TaskBarLocation = new System.Drawing.Rectangle(monitorInfo.rcWork.left, monitorInfo.rcMonitor.top, tbWidth, tbHeight);
+ tbsr.Edge = TaskBarEdge.Top;
+ }
+ else
+ {
+ // Invalid state
+ SharedLogger.logger.Error($"WinLibrary/GetAllCurrentTaskBarPositions: Taskbar position was not on a horizontal edge of a monitor!");
+ }
+
+ }
+ else if (monHeight == wrkHeight)
+ {
+ // Taskbar on the sides
+ if (monitorInfo.rcMonitor.right == monitorInfo.rcWork.right && monitorInfo.rcMonitor.bottom == monitorInfo.rcWork.bottom)
+ {
+ // Taskbar on left
+ tbWidth = monWidth - wrkWidth;
+ tbHeight = monHeight;
+ tbsr.TaskBarLocation = new System.Drawing.Rectangle(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, tbWidth, tbHeight);
+ tbsr.Edge = TaskBarEdge.Left;
+ }
+ else if (monitorInfo.rcMonitor.left == monitorInfo.rcWork.left && monitorInfo.rcMonitor.top == monitorInfo.rcWork.top)
+ {
+ // Taskbar on right
+ tbWidth = monWidth - wrkWidth;
+ tbHeight = monHeight;
+ tbsr.TaskBarLocation = new System.Drawing.Rectangle(monitorInfo.rcWork.right, monitorInfo.rcMonitor.top, tbWidth, tbHeight);
+ tbsr.Edge = TaskBarEdge.Right;
+ }
+ else
+ {
+ // Invalid state
+ SharedLogger.logger.Error($"WinLibrary/GetAllCurrentTaskBarPositions: Taskbar position was not on a vertical edge of a monitor!");
+ }
+ }
+ else
+ {
+ // Invalid state
+ SharedLogger.logger.Error($"WinLibrary/GetAllCurrentTaskBarPositions: Taskbar position was not fully along one of the monitor edges!");
+ }
+
+ tbsr.MonitorLocation = new System.Drawing.Rectangle(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, monWidth, monHeight);
+ tbsr.MainScreen = false;
+
+ // Now as a LAST step we update the Binary field just before we apply it to make sure that the correct binary settings are stored
+ tbsr.PopulateBinaryFromFields();
+
+ if (!taskBarStuckRectangles.ContainsKey(monitorInfo.szDevice))
+ {
+ taskBarStuckRectangles.Add(monitorInfo.szDevice, tbsr);
+ }
+ else
+ {
+ SharedLogger.logger.Error($"WinLibrary/GetAllCurrentTaskBarPositions: Skipping grabbing Taskbar position from a cloned display {monitorInfo.szDevice}");
+ }
+
+ // Prep the next taskbar window so we continue through them
+ lastTaskBarWindowHwnd = nextTaskBarWindowHwnd;
+ }
+
+ return taskBarStuckRectangles;
+ }
+
+ public bool MoveTaskBar()
+ {
+ if (RegKeyValue.Equals("Settings") && MainScreen)
+ {
+ // We only want to set the position for the main screen if it has a "Settings" entry and is a main screen
+ // Find the window to move
+ IntPtr mainTaskbarHwnd = Utils.FindWindow("Shell_TrayWnd", "");
+ //IntPtr startButtonHandle = Utils.FindWindowEx(mainTaskbarHwnd, IntPtr.Zero, "Start", null);
+ IntPtr systemTrayNotifyHandle = Utils.FindWindowEx(mainTaskbarHwnd, IntPtr.Zero, "TrayNotifyWnd", null);
+ //IntPtr rebarWindowHandle = Utils.FindWindowEx(mainTaskbarHwnd, IntPtr.Zero, "ReBarWindow32", null);
+ //IntPtr trayDesktopShowButtonHandle = Utils.FindWindowEx(systemTrayNotifyHandle, IntPtr.Zero, "TrayShowDesktopButtonWClass", null);
+
+ IntPtr result;
+
+ // ===== MOVE THE MAIN TASKBAR WINDOW =====
+ // Prepare the taskbar for moving
+ Utils.SendMessageTimeout(mainTaskbarHwnd, Utils.WM_ENTERSIZEMOVE, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlag.SMTO_NORMAL, 10, out result);
+ // Move the taskbar window
+ Utils.MoveWindow(mainTaskbarHwnd, TaskBarLocation.X, TaskBarLocation.Y, TaskBarLocation.Width, TaskBarLocation.Height, false);
+
+ // ===== LOCK THE MAIN TASKBAR WINDOW BACK DOWN =====
+ // Tell the taskbar we've stopped moving it now
+ Utils.SendMessageTimeout(mainTaskbarHwnd, Utils.WM_EXITSIZEMOVE, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlag.SMTO_NORMAL, 10, out result);
+ // Tell the taskbar it needs to update it's theme
+ Utils.PostMessage(mainTaskbarHwnd, Utils.WM_THEMECHANGED, IntPtr.Zero, IntPtr.Zero);
+ // Tell the taskbar it needs to recalculate it's work area
+ Utils.SendMessageTimeout(systemTrayNotifyHandle, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, IntPtr.Zero, SendMessageTimeoutFlag.SMTO_NORMAL, 10, out result);
+
+ // We also save the taskbar position for the monitor in registry, so that Windows will actually properly update the position
+ // after 5 seconds (and this one will stick between reboots too!).
+ WriteToRegistry();
+
+ }
+ else if (MainScreen && !RegKeyValue.Equals("Settings"))
+ {
+ // If it's a main screen, but not "settings", then its the registry key only taskbar setting we need to change
+ // This is because hte only screen settings that matter are the StuckRect3 registry key (for the main screen) and
+ // all of the secondary windows
+ WriteToRegistry();
+ }
+ else
+ {
+ // This is a secondary screen, so we need to set it's position
+ // Then go through the secondary windows and get the position of them
+ // Tell Windows to refresh the Other Windows Taskbars if needed
+ //WriteToRegistry();
+
+ IntPtr mainTaskbarHwnd = Utils.FindWindow("Shell_TrayWnd", "");
+
+ IntPtr lastTaskBarWindowHwnd = (IntPtr)Utils.NULL;
+ for (int i = 0; i < 100; i++)
+ {
+ // Find the next "Shell_SecondaryTrayWnd" window
+ IntPtr nextTaskBarWindowHwnd = Utils.FindWindowEx((IntPtr)Utils.NULL, lastTaskBarWindowHwnd, "Shell_SecondaryTrayWnd", null);
+ if (nextTaskBarWindowHwnd == (IntPtr)Utils.NULL)
+ {
+ // No more windows taskbars to notify
+ break;
+ }
+
+ IntPtr secMonitorHwnd = Utils.MonitorFromWindow(nextTaskBarWindowHwnd, Utils.MONITOR_DEFAULTTONEAREST);
+
+ // Figure out this monitor coordinates
+ MONITORINFOEX monitorInfo = new MONITORINFOEX();
+ monitorInfo.cbSize = (UInt32)Marshal.SizeOf(typeof(MONITORINFOEX));
+ //monitorInfo.szDevice = new char[Utils.CCHDEVICENAME];
+ Utils.GetMonitorInfo(secMonitorHwnd, ref monitorInfo);
+
+ // Figure out the position of the taskbar ourselves
+ int monWidth = Math.Abs(monitorInfo.rcMonitor.left - monitorInfo.rcMonitor.right);
+ int monHeight = Math.Abs(monitorInfo.rcMonitor.top - monitorInfo.rcMonitor.bottom);
+ Rectangle thisMonitorLocation = new Rectangle(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top, monWidth, monHeight);
+ if (MonitorLocation.Equals(thisMonitorLocation))
+ {
+ // This is the right monitor, so we should move the taskbar on it.
+
+ IntPtr result;
+
+ // ===== MOVE THE MAIN TASKBAR WINDOW =====
+ // Prepare the taskbar for moving
+ Utils.SendMessageTimeout(nextTaskBarWindowHwnd, Utils.WM_ENTERSIZEMOVE, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlag.SMTO_NORMAL, 10, out result);
+ // Move the taskbar window
+ Utils.MoveWindow(nextTaskBarWindowHwnd, TaskBarLocation.X, TaskBarLocation.Y, TaskBarLocation.Width, TaskBarLocation.Height, true);
+
+ // ===== LOCK THE MAIN TASKBAR WINDOW BACK DOWN =====
+ // Tell the taskbar we've stopped moving it now
+ //Utils.SendMessageTimeout(nextTaskBarWindowHwnd, Utils.WM_EXITSIZEMOVE, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlag.SMTO_NORMAL, 10, out result);
+ // Tell the taskbar it needs to update it's theme
+ //Utils.PostMessage(nextTaskBarWindowHwnd, Utils.WM_THEMECHANGED, IntPtr.Zero, IntPtr.Zero);
+ // Tell the taskbar it needs to recalculate it's work area
+ //Utils.SendMessageTimeout(nextTaskBarWindowHwnd, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, IntPtr.Zero, SendMessageTimeoutFlag.SMTO_NORMAL, 10, out result);
+
+ // We also save the taskbar position for the monitor in registry, so that Windows will actually properly update the position
+ // after 5 seconds (and this one will stick between reboots too!).
+ WriteToRegistry();
+
+
+ // We then want to stop as we've found the correct taskbar to move!
+ break;
+
+ }
+
+ // Prep the next taskbar window so we continue through them
+ lastTaskBarWindowHwnd = nextTaskBarWindowHwnd;
+ }
+ }
+
+ return true;
+ }
+
+
+ public static string GetRegKeyValueFromDevicePath(string devicePath)
+ {
+ string regKeyValue = "";
+ // e.g. "\\\\?\\DISPLAY#NVS10DE#5&2b46c695&0&UID185344#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}"
+ string pattern = @"DISPLAY\#(.*)\#\{";
+ Match match = Regex.Match(devicePath, pattern);
+ if (match.Success)
+ {
+ regKeyValue = match.Groups[1].Value;
+ SharedLogger.logger.Trace($"TaskBarLayout/GetRegKeyValueFromDevicePath: Found regKeyValue {regKeyValue } in the devicePath {devicePath }.");
+ }
+ else
+ {
+ SharedLogger.logger.Warn($"TaskBarLayout/GetRegKeyValueFromDevicePath: We were unable to figure out the regKeyValue {regKeyValue } in the devicePath {devicePath }..");
+ }
+ return regKeyValue;
+ }
+
+ public static bool ForceTaskBarRedraw(IntPtr mainToolBarHWnd)
+ {
+ // Tell Windows to refresh the Main Screen Windows Taskbar registry settings by telling Explorer to update.
+ Utils.SendMessage(mainToolBarHWnd, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, (IntPtr)Utils.NULL);
+ // Tell Windows to refresh the child Windows in the taskbar
+ IntPtr lastChildWindowHwnd = (IntPtr)Utils.NULL;
+ for (int i = 0; i < 100; i++)
+ {
+ // Find the next "Shell_SecondaryTrayWnd" window
+ IntPtr nextChildWindowHwnd = Utils.FindWindowEx((IntPtr)Utils.NULL, mainToolBarHWnd, "", null);
+ if (nextChildWindowHwnd == (IntPtr)Utils.NULL)
+ {
+ // No more windows taskbars to notify
+ break;
+ }
+ // Send the "Shell_TrayWnd" window a WM_SETTINGCHANGE with a wParameter of SPI_SETWORKAREA
+ Utils.SendMessage(lastChildWindowHwnd, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, (IntPtr)Utils.NULL);
+ lastChildWindowHwnd = nextChildWindowHwnd;
+ }
+
+ //IntPtr explorerToolBarHWnd = Utils.FindWindow("Shell_TrayWnd", null);
+ //Utils.PostMessage((IntPtr)Utils.HWND_BROADCAST, Utils.SHELLHOOK, 0x13, (int) mainToolBarHWnd);
+ //Utils.PostMessage((IntPtr)Utils.HWND_BROADCAST, Utils.WM_SETTINGCHANGE, (int)Utils.SPI_SETWORKAREA, (int)Utils.NULL);
+ /*IntPtr result;
+ Utils.SendMessageTimeout((IntPtr)Utils.HWND_BROADCAST, Utils.WM_USER_1, (IntPtr)Utils.NULL, (IntPtr)Utils.NULL, Utils.SendMessageTimeoutFlag.SMTO_ABORTIFHUNG, 15, out result);*/
+ return true;
+ }
+
+ }
+
+ [global::System.Serializable]
+ public class TaskBarStuckRectangleException : Exception
+ {
+ public TaskBarStuckRectangleException() { }
+ public TaskBarStuckRectangleException(string message) : base(message) { }
+ public TaskBarStuckRectangleException(string message, Exception inner) : base(message, inner) { }
+ protected TaskBarStuckRectangleException(
+ System.Runtime.Serialization.SerializationInfo info,
+ System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
+ }
+}
\ No newline at end of file
diff --git a/DisplayMagicianShared/Windows/TaskBarSettings.cs b/DisplayMagicianShared/Windows/TaskBarSettings.cs
deleted file mode 100644
index 9b2965b..0000000
--- a/DisplayMagicianShared/Windows/TaskBarSettings.cs
+++ /dev/null
@@ -1,137 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Microsoft.Win32;
-
-// This file is taken from Soroush Falahati's amazing HeliosDisplayManagement software
-// available at https://github.com/falahati/HeliosDisplayManagement
-
-// Modifications made by Terry MacDonald
-
-namespace DisplayMagicianShared.Windows
-{
- public class TaskBarSettings
- {
- private const string AdvancedSettingsAddress =
- "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced";
-
- private static List WantedAdvancedSettingValues = new List
- {
- // Win10/11 registry keys (not all will be populated, only those that the user modified from default at least once)
- "MMTaskbarEnabled", // Multiple Taskbars: 0 for show taskbar on main screen only, 1 for show taskbar on all screens
- "MMTaskbarMode", // Show taskbar buttons on: 0 = all taskbars, 1 = main taskbar and where windows is open, 2 = taskbar where window is open
- "MMTaskbarGlomLevel", // Buttons on other taskbars: 0 = always combine, combine when the taskbar is full, 2 = never combine
- "NoTaskGrouping", // Disable all Task Grouping (overrides "TaskbarGroupSize"): 0 = enable task grouping, 1 = disable task grouping
- "SearchboxTaskbarMode", // Show Search Button in Taskbar: 0 = remove search button, 1 = show search button
- "ShowTaskViewButton", // Show Taskview Button in Taskbar: 0 = remove taskview button, 1 = show taskview button
- "TaskbarAl", // Start Button Alignment: 0 for left, 1 for center,
- "TaskbarDa", // Show Widgets button in Taskbar: 0 = remove widgets button, 1 = Show widgets button
- "TaskbarGlomLevel", // Buttons on main screen: 0 = always combine, combine when the taskbar is full, 2 = never combine
- "TaskbarGroupSize", // TaskBar left/right grouping by age: 0 = oldest first (default), 1 = roup by size largest first, 2 = group all with 2 or more, 3 = group all with 3 or more (see NoTaskGrouping to prevent Grouping )
- "TaskbarMn", // Show Chat Button in Taskbar: 0 = remove chat button, 1 = show chat button
- "TaskbarSi", // Taskbar Size: 0 = small, 1 = medium, 2 = Large
- "TaskbarSizeMove", // Lock the Taskbar (prevent resizing): 0 = taskbar size is locked, 1 = taskbar size is unlocked
- "TaskbarSmallIcons", // Small Taskbar Icons: 0 = normal sized icons, 1 = small icons
- "TaskbarSd", // Show Desktop Button in Taskbar: 0 for hid the show desktop button, 1 for show the Show desktop button
- };
-
-
- public Tuple[] Options { get; set; }
-
- public override bool Equals(object obj) => obj is TaskBarSettings other && this.Equals(other);
- public bool Equals(TaskBarSettings other)
- => Options.All(a => other.Options.Any(x => x.Item1 == a.Item1 && x.Item2 == a.Item2));
-
- public override int GetHashCode()
- {
- return (Options).GetHashCode();
- }
- public static bool operator ==(TaskBarSettings lhs, TaskBarSettings rhs) => lhs.Equals(rhs);
-
- public static bool operator !=(TaskBarSettings lhs, TaskBarSettings rhs) => !(lhs == rhs);
-
- public static TaskBarSettings GetCurrent()
- {
- var taskBarOptions = new List>();
-
- // Get modified and stored Taskbar options from the User Registry
- // Note: Only the taskbar options changed from default at least once in the past will be listed in Registry
- try
- {
- using (var key = Registry.CurrentUser.OpenSubKey(
- AdvancedSettingsAddress,
- RegistryKeyPermissionCheck.ReadSubTree))
- {
- if (key != null)
- {
- foreach (var valueName in WantedAdvancedSettingValues)
- {
- try
- {
-
- var value = key.GetValue(valueName, null,
- RegistryValueOptions.DoNotExpandEnvironmentNames);
-
- if (value != null && value is int intValue)
- {
- taskBarOptions.Add(new Tuple(valueName, intValue));
- }
- }
- catch (Exception)
- {
- // ignored, as this will happen
- }
- }
- }
- }
- }
- catch (Exception)
- {
- // ignored
- }
-
- if (taskBarOptions.Count == 0)
- {
- return null;
- }
-
- return new TaskBarSettings
- {
- Options = taskBarOptions.ToArray()
- };
- }
-
- public bool Apply()
- {
- if (Options.Length == 0)
- {
- throw new InvalidOperationException();
- }
-
- using (var optionsKey = Registry.CurrentUser.OpenSubKey(
- AdvancedSettingsAddress,
- RegistryKeyPermissionCheck.ReadWriteSubTree))
- {
- if (optionsKey == null)
- {
- return false;
- }
-
- // Write
- foreach (var option in Options)
- {
- try
- {
- optionsKey.SetValue(option.Item1, option.Item2);
- }
- catch (Exception)
- {
- // ignored
- }
- }
- }
-
- return true;
- }
- }
-}
\ No newline at end of file
diff --git a/DisplayMagicianShared/Windows/TaskBarStuckRectangle.cs b/DisplayMagicianShared/Windows/TaskBarStuckRectangle.cs
index a166816..9b2965b 100644
--- a/DisplayMagicianShared/Windows/TaskBarStuckRectangle.cs
+++ b/DisplayMagicianShared/Windows/TaskBarStuckRectangle.cs
@@ -1,561 +1,137 @@
using System;
using System.Collections.Generic;
-using System.Drawing;
-using System.Runtime.InteropServices;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using DisplayMagicianShared;
+using System.Linq;
using Microsoft.Win32;
-using Newtonsoft.Json;
// This file is taken from Soroush Falahati's amazing HeliosDisplayManagement software
// available at https://github.com/falahati/HeliosDisplayManagement
-// Substantial modifications made by Terry MacDonald 2022 onwards
+// Modifications made by Terry MacDonald
namespace DisplayMagicianShared.Windows
{
- public class TaskBarStuckRectangle
- {
+ public class TaskBarSettings
+ {
+ private const string AdvancedSettingsAddress =
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced";
- public enum TaskBarEdge : UInt32
+ private static List WantedAdvancedSettingValues = new List
{
- Left = 0,
- Top = 1,
- Right = 2,
- Bottom = 3
- }
-
- [Flags]
- public enum TaskBarOptions : UInt32
- {
- None = 0,
- AutoHide = 1 << 0,
- KeepOnTop = 1 << 1,
- UseSmallIcons = 1 << 2,
- HideClock = 1 << 3,
- HideVolume = 1 << 4,
- HideNetwork = 1 << 5,
- HidePower = 1 << 6,
- WindowPreview = 1 << 7,
- Unknown1 = 1 << 8,
- Unknown2 = 1 << 9,
- HideActionCenter = 1 << 10,
- Unknown3 = 1 << 11,
- HideLocation = 1 << 12,
- HideLanguageBar = 1 << 13
- }
-
- private const string MainDisplayAddress =
- "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StuckRects{0:D}";
-
- private const string MultiDisplayAddress =
- "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MMStuckRects{0:D}";
-
- /*private static readonly Dictionary Headers = new Dictionary
- {
- {2, new byte[] {0x28, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}},
- {3, new byte[] {0x30, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF}}
+ // Win10/11 registry keys (not all will be populated, only those that the user modified from default at least once)
+ "MMTaskbarEnabled", // Multiple Taskbars: 0 for show taskbar on main screen only, 1 for show taskbar on all screens
+ "MMTaskbarMode", // Show taskbar buttons on: 0 = all taskbars, 1 = main taskbar and where windows is open, 2 = taskbar where window is open
+ "MMTaskbarGlomLevel", // Buttons on other taskbars: 0 = always combine, combine when the taskbar is full, 2 = never combine
+ "NoTaskGrouping", // Disable all Task Grouping (overrides "TaskbarGroupSize"): 0 = enable task grouping, 1 = disable task grouping
+ "SearchboxTaskbarMode", // Show Search Button in Taskbar: 0 = remove search button, 1 = show search button
+ "ShowTaskViewButton", // Show Taskview Button in Taskbar: 0 = remove taskview button, 1 = show taskview button
+ "TaskbarAl", // Start Button Alignment: 0 for left, 1 for center,
+ "TaskbarDa", // Show Widgets button in Taskbar: 0 = remove widgets button, 1 = Show widgets button
+ "TaskbarGlomLevel", // Buttons on main screen: 0 = always combine, combine when the taskbar is full, 2 = never combine
+ "TaskbarGroupSize", // TaskBar left/right grouping by age: 0 = oldest first (default), 1 = roup by size largest first, 2 = group all with 2 or more, 3 = group all with 3 or more (see NoTaskGrouping to prevent Grouping )
+ "TaskbarMn", // Show Chat Button in Taskbar: 0 = remove chat button, 1 = show chat button
+ "TaskbarSi", // Taskbar Size: 0 = small, 1 = medium, 2 = Large
+ "TaskbarSizeMove", // Lock the Taskbar (prevent resizing): 0 = taskbar size is locked, 1 = taskbar size is unlocked
+ "TaskbarSmallIcons", // Small Taskbar Icons: 0 = normal sized icons, 1 = small icons
+ "TaskbarSd", // Show Desktop Button in Taskbar: 0 for hid the show desktop button, 1 for show the Show desktop button
};
-*/
- public TaskBarStuckRectangle(string devicePath)
- {
- bool MMStuckRectVerFound = false;
- // Check if key exists
- int version = 3;
- string address = string.Format(MultiDisplayAddress, version);
- if (Registry.CurrentUser.OpenSubKey(address) != null)
- {
- MMStuckRectVerFound = true;
- SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found MMStuckRect3 registry key! {address}");
- }
- else
- {
- // If it's not version 3, then try version 2
- version = 2;
- address = string.Format(MultiDisplayAddress, version);
- if (Registry.CurrentUser.OpenSubKey(address) != null)
- {
- MMStuckRectVerFound = true;
- SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found MMStuckRect2 registry key! {address}");
- }
- else
- {
- // It's not v2 or v3, so it must be a single display
- MMStuckRectVerFound = false;
- SharedLogger.logger.Warn($"TaskBarStuckRectangle/TaskBarStuckRectangle: Couldn't find an MMStuckRect2 or MMStuckRect3 registry key! Going to test if it is a single display only.");
- }
- }
- bool foundDevicePath = false;
- if (MMStuckRectVerFound)
- {
- // Check if value exists
- if (version >= 2 && version <= 3)
- {
- using (var key = Registry.CurrentUser.OpenSubKey(
- address,
- RegistryKeyPermissionCheck.ReadSubTree))
- {
- var binary = key?.GetValue(devicePath) as byte[];
- if (binary?.Length > 0)
- {
- foundDevicePath = true;
- MainScreen = false;
- DevicePath = devicePath;
- Binary = binary;
- OriginalBinary = new byte[binary.Length];
- binary.CopyTo(OriginalBinary, 0);
- Version = version;
- // Extract the values from the binary byte field
- PopulateFieldsFromBinary();
+ public Tuple[] Options { get; set; }
- SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: The taskbar for {DevicePath} is against the {Edge} edge, is positioned at ({Location.X},{Location.Y}) and is {Location.Width}x{Location.Height} in size.");
- }
- else
- {
- SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Unable to get the TaskBarStuckRectangle binary settings from {devicePath} screen.");
- }
- }
- }
- }
-
- if (!foundDevicePath)
- {
- bool StuckRectVerFound = false;
- // Check if string exists
- version = 3;
- address = string.Format(MainDisplayAddress, version);
- if (Registry.CurrentUser.OpenSubKey(address) != null)
- {
- StuckRectVerFound = true;
- SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found StuckRect3 single display registry key! {address}");
- }
- else
- {
- // If it's not version 3, then try version 2
- version = 2;
- address = string.Format(MainDisplayAddress, version);
- if (Registry.CurrentUser.OpenSubKey(address) != null)
- {
- StuckRectVerFound = true;
- SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found StuckRect2 single display registry key! {address}");
- }
- else
- {
- SharedLogger.logger.Error($"TaskBarStuckRectangle/TaskBarStuckRectangle: Couldn't find an single display StuckRect2 or StuckRect3 registry key! So we have to just return after doing nothing as there is nothing we can do.");
- return;
- }
- }
-
- if (StuckRectVerFound)
- {
- // Check if value exists
- if (version >= 2 && version <= 3)
- {
- using (var key = Registry.CurrentUser.OpenSubKey(
- address,
- RegistryKeyPermissionCheck.ReadSubTree))
- {
- var binary = key?.GetValue(devicePath) as byte[];
- if (binary?.Length > 0)
- {
- foundDevicePath = true;
- MainScreen = true;
- DevicePath = devicePath;
- Binary = binary;
- OriginalBinary = new byte[binary.Length];
- binary.CopyTo(OriginalBinary, 0);
- Version = version;
-
- // Extract the values from the binary byte field
- PopulateFieldsFromBinary();
-
- SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: The taskbar for {DevicePath} is against the {Edge} edge, is positioned at ({Location.X},{Location.Y}) and is {Location.Width}x{Location.Height} in size.");
- }
- else
- {
- SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Unable to get the TaskBarStuckRectangle binary settings from {devicePath} screen.");
- }
- }
- }
- }
- }
- }
-
- public TaskBarStuckRectangle()
- {
- }
-
- public byte[] Binary { get; set; }
-
- public byte[] OriginalBinary { get; set; }
-
- public string DevicePath { get; set; }
-
- public bool MainScreen { get; set; }
-
- public UInt32 DPI { get; set; }
-
- public TaskBarEdge Edge { get; set; }
-
- public Rectangle Location { get; set; }
-
- public Size MinSize { get; set; }
-
- public TaskBarOptions Options { get; set; }
-
- public uint Rows { get; set; }
-
- public int Version { get; set; }
-
- public override bool Equals(object obj) => obj is TaskBarStuckRectangle other && this.Equals(other);
- public bool Equals(TaskBarStuckRectangle other)
- {
- return Version == other.Version &&
- DevicePath == other.DevicePath &&
- MainScreen == other.MainScreen &&
- DPI == other.DPI &&
- Edge == other.Edge &&
- Location == other.Location &&
- MinSize == other.MinSize &&
- Options == other.Options &&
- Rows == other.Rows;
- }
+ public override bool Equals(object obj) => obj is TaskBarSettings other && this.Equals(other);
+ public bool Equals(TaskBarSettings other)
+ => Options.All(a => other.Options.Any(x => x.Item1 == a.Item1 && x.Item2 == a.Item2));
public override int GetHashCode()
{
- return (Version, MainScreen, DevicePath, DPI, Edge, Location, MinSize, Options, Rows).GetHashCode();
+ return (Options).GetHashCode();
}
- public static bool operator ==(TaskBarStuckRectangle lhs, TaskBarStuckRectangle rhs) => lhs.Equals(rhs);
+ public static bool operator ==(TaskBarSettings lhs, TaskBarSettings rhs) => lhs.Equals(rhs);
- public static bool operator !=(TaskBarStuckRectangle lhs, TaskBarStuckRectangle rhs) => !(lhs == rhs);
-
- static bool Xor(byte[] a, byte[] b)
+ public static bool operator !=(TaskBarSettings lhs, TaskBarSettings rhs) => !(lhs == rhs);
+ public static TaskBarSettings GetCurrent()
{
+ var taskBarOptions = new List>();
- int x = a.Length ^ b.Length;
-
- for (int i = 0; i < a.Length && i < b.Length; ++i)
-
+ // Get modified and stored Taskbar options from the User Registry
+ // Note: Only the taskbar options changed from default at least once in the past will be listed in Registry
+ try
{
-
- x |= a[i] ^ b[i];
-
- }
-
- return x == 0;
-
- }
-
- private bool PopulateFieldsFromBinary()
- {
- // Now we decipher the binary properties features to populate the stuckrectangle
- // DPI
- if (Binary.Length < 44)
- {
- DPI = 0;
- }
- else
- {
- DPI = BitConverter.ToUInt32(Binary, 40);
- }
- // Edge
- if (Binary.Length < 16)
- {
- Edge = TaskBarEdge.Bottom;
- }
- else
- {
- Edge = (TaskBarEdge)BitConverter.ToUInt32(Binary, 12);
- }
- // Location
- if (Binary.Length < 40)
- {
- Location = Rectangle.Empty;
- }
- else
- {
- var left = BitConverter.ToInt32(Binary, 24);
- var top = BitConverter.ToInt32(Binary, 28);
- var right = BitConverter.ToInt32(Binary, 32);
- var bottom = BitConverter.ToInt32(Binary, 36);
-
- Location = Rectangle.FromLTRB(left, top, right, bottom);
- }
- // MinSize
- if (Binary.Length < 24)
- {
- MinSize = Size.Empty;
- }
- else
- {
- var width = BitConverter.ToInt32(Binary, 16);
- var height = BitConverter.ToInt32(Binary, 20);
-
- MinSize = new Size(width, height);
- }
- // Options
- if (Binary.Length < 12)
- {
- Options = 0;
- }
- else
- {
- Options = (TaskBarOptions)BitConverter.ToUInt32(Binary, 8);
- }
- // Rows
- if (Binary.Length < 48)
- {
- Rows = 1;
- }
- else
- {
- Rows = BitConverter.ToUInt32(Binary, 44);
- }
-
- SharedLogger.logger.Trace($"TaskBarStuckRectangle/PopulateFieldsFromBinary: Grabbed the following settings for {DevicePath} from the registry: DPI = {DPI}, Edge = {Edge}, Location = ({Location.X},{Location.Y}), MinSize = {Location.Width}x{Location.Height}, Options = {Options}, Rows = {Rows}.");
-
- return true;
- }
-
- public bool PopulateBinaryFromFields()
- {
- // Set the DPI
- if (Binary.Length < 44)
- {
- DPI = 0;
- var bytes = BitConverter.GetBytes(DPI);
- Array.Copy(bytes, 0, Binary, 40, 4);
- }
- else
- {
- var bytes = BitConverter.GetBytes(DPI);
- Array.Copy(bytes, 0, Binary, 40, 4);
- }
- // Edge
- if (Binary.Length < 16)
- {
- Edge = TaskBarEdge.Bottom;
- var bytes = BitConverter.GetBytes((uint)Edge);
- Array.Copy(bytes, 0, Binary, 12, 1);
- }
- else
- {
- var bytes = BitConverter.GetBytes((uint)Edge);
- Array.Copy(bytes, 0, Binary, 12, 1);
- }
- // Location
- if (Binary.Length < 40)
- {
- var bytes = BitConverter.GetBytes(0);
- Array.Copy(bytes, 0, Binary, 24, 4);
-
- bytes = BitConverter.GetBytes(0);
- Array.Copy(bytes, 0, Binary, 28, 4);
-
- bytes = BitConverter.GetBytes(0);
- Array.Copy(bytes, 0, Binary, 32, 4);
-
- bytes = BitConverter.GetBytes(0);
- Array.Copy(bytes, 0, Binary, 36, 4);
- }
- else
- {
- var bytes = BitConverter.GetBytes(Location.Left);
- Array.Copy(bytes, 0, Binary, 24, 4);
-
- bytes = BitConverter.GetBytes(Location.Top);
- Array.Copy(bytes, 0, Binary, 28, 4);
-
- bytes = BitConverter.GetBytes(Location.Right);
- Array.Copy(bytes, 0, Binary, 32, 4);
-
- bytes = BitConverter.GetBytes(Location.Bottom);
- Array.Copy(bytes, 0, Binary, 36, 4);
- }
- // MinSize
- if (Binary.Length < 24)
- {
- var bytes = BitConverter.GetBytes(0);
- Array.Copy(bytes, 0, Binary, 16, 4);
-
- bytes = BitConverter.GetBytes(0);
- Array.Copy(bytes, 0, Binary, 20, 4);
- }
- else
- {
- var bytes = BitConverter.GetBytes(MinSize.Width);
- Array.Copy(bytes, 0, Binary, 16, 4);
-
- bytes = BitConverter.GetBytes(MinSize.Height);
- Array.Copy(bytes, 0, Binary, 20, 4);
- }
- // Options
- if (Binary.Length < 12)
- {
- var bytes = BitConverter.GetBytes((uint)0);
- Array.Copy(bytes, 0, Binary, 8, 4);
- }
- else
- {
- var bytes = BitConverter.GetBytes((uint)Options);
- Array.Copy(bytes, 0, Binary, 8, 4);
- }
- // Rows
- if (Binary.Length < 48)
- {
- var bytes = BitConverter.GetBytes(1);
- Array.Copy(bytes, 0, Binary, 44, 4);
- }
- else
- {
- var bytes = BitConverter.GetBytes(Rows);
- Array.Copy(bytes, 0, Binary, 44, 4);
- }
-
- SharedLogger.logger.Trace($"TaskBarStuckRectangle/PopulateBinaryFromFields: Set the following settings for {DevicePath} into registry: DPI = {DPI}, Edge = {Edge}, Location = ({Location.X},{Location.Y}), MinSize = {Location.Width}x{Location.Height}, Options = {Options}, Rows = {Rows}.");
-
- return true;
- }
-
- public bool WriteToRegistry()
- {
- // Update the binary with the current settings from the object
- PopulateBinaryFromFields();
-
- // Write the binary field to registry
- string address;
- if (MainScreen)
- {
- address = string.Format(MainDisplayAddress, Version);
- // Set the Main Screen
- try
+ using (var key = Registry.CurrentUser.OpenSubKey(
+ AdvancedSettingsAddress,
+ RegistryKeyPermissionCheck.ReadSubTree))
{
- using (var key = Registry.CurrentUser.OpenSubKey(
- address,
- RegistryKeyPermissionCheck.ReadWriteSubTree))
+ if (key != null)
{
- key.SetValue(DevicePath, Binary);
- SharedLogger.logger.Trace($"TaskBarStuckRectangle/Apply: Successfully applied TaskBarStuckRectangle registry settings for the {DevicePath} Screen in {address}!");
+ foreach (var valueName in WantedAdvancedSettingValues)
+ {
+ try
+ {
+
+ var value = key.GetValue(valueName, null,
+ RegistryValueOptions.DoNotExpandEnvironmentNames);
+
+ if (value != null && value is int intValue)
+ {
+ taskBarOptions.Add(new Tuple(valueName, intValue));
+ }
+ }
+ catch (Exception)
+ {
+ // ignored, as this will happen
+ }
+ }
}
}
- catch (Exception ex)
- {
- SharedLogger.logger.Error(ex, $"TaskBarStuckRectangle/GetCurrent: Unable to set the {DevicePath} TaskBarStuckRectangle registry settings in {address} due to an exception!");
- }
}
- else
+ catch (Exception)
{
- address = string.Format(MultiDisplayAddress, Version);
- // Grab the main screen taskbar placement
- try
+ // ignored
+ }
+
+ if (taskBarOptions.Count == 0)
+ {
+ return null;
+ }
+
+ return new TaskBarSettings
+ {
+ Options = taskBarOptions.ToArray()
+ };
+ }
+
+ public bool Apply()
+ {
+ if (Options.Length == 0)
+ {
+ throw new InvalidOperationException();
+ }
+
+ using (var optionsKey = Registry.CurrentUser.OpenSubKey(
+ AdvancedSettingsAddress,
+ RegistryKeyPermissionCheck.ReadWriteSubTree))
+ {
+ if (optionsKey == null)
{
- using (var key = Registry.CurrentUser.OpenSubKey(
- address,
- RegistryKeyPermissionCheck.ReadWriteSubTree))
+ return false;
+ }
+
+ // Write
+ foreach (var option in Options)
+ {
+ try
{
- key.SetValue(DevicePath, Binary);
- SharedLogger.logger.Trace($"TaskBarStuckRectangle/WriteToRegistry: Successfully applied TaskBarStuckRectangle registry settings for the {DevicePath} Screen in {address}!");
+ optionsKey.SetValue(option.Item1, option.Item2);
+ }
+ catch (Exception)
+ {
+ // ignored
}
}
- catch (Exception ex)
- {
- SharedLogger.logger.Error(ex, $"TaskBarStuckRectangle/WriteToRegistry: Unable to set the {DevicePath} TaskBarStuckRectangle registry settings in {address} due to an exception!");
- }
}
return true;
}
-
- public static bool RepositionMainTaskBar(TaskBarEdge edge)
- {
- // Tell Windows to refresh the Main Screen Windows Taskbar
- // Find the "Shell_TrayWnd" window
- IntPtr mainToolBarHWnd = Utils.FindWindow("Shell_TrayWnd", null);
- // Send the "Shell_TrayWnd" window a WM_USER_REFRESHTASKBAR with a wParameter of 0006 and a lParamater of the position (e.g. 0000 for left, 0001 for top, 0002 for right and 0003 for bottom)
- IntPtr taskBarPositionBuffer = new IntPtr((Int32)edge);
- Utils.SendMessage(mainToolBarHWnd, Utils.WM_USER_REFRESHTASKBAR, (IntPtr)Utils.wParam_SHELLTRAY, taskBarPositionBuffer);
- return true;
- }
-
- public static bool RepositionSecondaryTaskBars()
- {
- // Tell Windows to refresh the Other Windows Taskbars if needed
- IntPtr lastTaskBarWindowHwnd = (IntPtr)Utils.NULL;
- for (int i = 0; i < 100; i++)
- {
- // Find the next "Shell_SecondaryTrayWnd" window
- IntPtr nextTaskBarWindowHwnd = Utils.FindWindowEx((IntPtr)Utils.NULL, lastTaskBarWindowHwnd, "Shell_SecondaryTrayWnd", null);
- if (nextTaskBarWindowHwnd == (IntPtr)Utils.NULL)
- {
- // No more windows taskbars to notify
- break;
- }
- // Send the "Shell_TrayWnd" window a WM_SETTINGCHANGE with a wParameter of SPI_SETWORKAREA
- Utils.SendMessage(lastTaskBarWindowHwnd, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, (IntPtr)Utils.NULL);
- lastTaskBarWindowHwnd = nextTaskBarWindowHwnd;
- }
- return true;
- }
-
- public static void RefreshTrayArea()
- {
- // Finds the Shell_TrayWnd -> TrayNotifyWnd -> SysPager -> "Notification Area" containing the visible notification area icons (windows 7 version)
- IntPtr systemTrayContainerHandle = Utils.FindWindow("Shell_TrayWnd", null);
- IntPtr systemTrayHandle = Utils.FindWindowEx(systemTrayContainerHandle, IntPtr.Zero, "TrayNotifyWnd", null);
- IntPtr sysPagerHandle = Utils.FindWindowEx(systemTrayHandle, IntPtr.Zero, "SysPager", null);
- IntPtr notificationAreaHandle = Utils.FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "Notification Area");
- // If the visible notification area icons (Windows 7 aren't found, then we're on a later version of windows, and we need to look for different window names
- if (notificationAreaHandle == IntPtr.Zero)
- {
- // Finds the Shell_TrayWnd -> TrayNotifyWnd -> SysPager -> "User Promoted Notification Area" containing the visible notification area icons (windows 10+ version)
- notificationAreaHandle = Utils.FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "User Promoted Notification Area");
- // Also attempt to find the NotifyIconOverflowWindow -> "Overflow Notification Area' window which is the hidden windoww that notification icons live when they are
- // too numberous or are hidden by the user.
- IntPtr notifyIconOverflowWindowHandle = Utils.FindWindow("NotifyIconOverflowWindow", null);
- IntPtr overflowNotificationAreaHandle = Utils.FindWindowEx(notifyIconOverflowWindowHandle, IntPtr.Zero, "ToolbarWindow32", "Overflow Notification Area");
- // Fool the "Overflow Notification Area' window into thinking the mouse is moving over it
- // which will force windows to refresh the "Overflow Notification Area' window and remove old icons.
- RefreshTrayArea(overflowNotificationAreaHandle);
- notifyIconOverflowWindowHandle = IntPtr.Zero;
- overflowNotificationAreaHandle = IntPtr.Zero;
- }
- // Fool the "Notification Area" or "User Promoted Notification Area" window (depends on the version of windows) into thinking the mouse is moving over it
- // which will force windows to refresh the "Notification Area" or "User Promoted Notification Area" window and remove old icons.
- RefreshTrayArea(notificationAreaHandle);
- systemTrayContainerHandle = IntPtr.Zero;
- systemTrayHandle = IntPtr.Zero;
- sysPagerHandle = IntPtr.Zero;
- notificationAreaHandle = IntPtr.Zero;
-
- }
-
-
- private static void RefreshTrayArea(IntPtr windowHandle)
- {
- // Moves the mouse around within the window area of the supplied window
- Utils.RECT rect;
- Utils.GetClientRect(windowHandle, out rect);
- for (var x = 0; x < rect.right; x += 5)
- for (var y = 0; y < rect.bottom; y += 5)
- Utils.SendMessage(windowHandle, Utils.WM_MOUSEMOVE, 0, (y << 16) + x);
- }
-
- /*public void DoMouseLeftClick(IntPtr handle, Point x)
- {
- Utils.SendMessage(handle, (int)Utils.WM_MOUSEMOVE, 0, Utils.MakeLParam(x.X, x.Y));
- //SendMessage(handle, (int)Utils.WM_LBUTTONUP, 0, Utils.MakeLParam(x.X, x.Y));
-
- return;
-
- //I have tried PostMessage, and SendMessage, and both of them at the same time, and neither works.
-
- Utils.PostMessage(handle, Utils.WM_MOUSEMOVE, 0, Utils.MakeLParam(x.X, x.Y));
- //PostMessage(handle, (uint)Utils.WM_LBUTTONUP, 0, Utils.MakeLParam(x.X, x.Y));
- }
-*/
}
}
\ No newline at end of file
diff --git a/DisplayMagicianShared/Windows/WinLibrary.cs b/DisplayMagicianShared/Windows/WinLibrary.cs
index b1a1dec..bb1a800 100644
--- a/DisplayMagicianShared/Windows/WinLibrary.cs
+++ b/DisplayMagicianShared/Windows/WinLibrary.cs
@@ -9,6 +9,8 @@ using System.IO;
using System.ComponentModel;
using Microsoft.Win32;
using System.Threading.Tasks;
+using static DisplayMagicianShared.Windows.TaskBarLayout;
+using System.Diagnostics;
namespace DisplayMagicianShared.Windows
{
@@ -37,6 +39,27 @@ namespace DisplayMagicianShared.Windows
public static bool operator !=(ADVANCED_HDR_INFO_PER_PATH lhs, ADVANCED_HDR_INFO_PER_PATH rhs) => !(lhs == rhs);
}
+ [StructLayout(LayoutKind.Sequential)]
+ public struct DISPLAY_SOURCE : IEquatable
+ {
+ public LUID AdapterId;
+ public UInt32 SourceId;
+ public UInt32 TargetId;
+ public string DevicePath;
+
+ public override bool Equals(object obj) => obj is DISPLAY_SOURCE other && this.Equals(other);
+ public bool Equals(DISPLAY_SOURCE other)
+ => true;
+ public override int GetHashCode()
+ {
+ return 300;
+ }
+
+ public static bool operator ==(DISPLAY_SOURCE lhs, DISPLAY_SOURCE rhs) => lhs.Equals(rhs);
+
+ public static bool operator !=(DISPLAY_SOURCE lhs, DISPLAY_SOURCE rhs) => !(lhs == rhs);
+ }
+
[StructLayout(LayoutKind.Sequential)]
public struct WINDOWS_DISPLAY_CONFIG : IEquatable
{
@@ -45,13 +68,13 @@ namespace DisplayMagicianShared.Windows
public DISPLAYCONFIG_MODE_INFO[] DisplayConfigModes;
public List DisplayHDRStates;
public Dictionary GdiDisplaySettings;
- public List TaskBarLayout;
+ public Dictionary TaskBarLayout;
public TaskBarSettings TaskBarSettings;
public bool IsCloned;
// Note: We purposely have left out the DisplaySources from the Equals as it's order keeps changing after each reboot and after each profile swap
// and it is informational only and doesn't contribute to the configuration (it's used for generating the Screens structure, and therefore for
// generating the profile icon.
- public Dictionary> DisplaySources;
+ public Dictionary> DisplaySources;
public List DisplayIdentifiers;
public override bool Equals(object obj) => obj is WINDOWS_DISPLAY_CONFIG other && this.Equals(other);
@@ -64,9 +87,12 @@ namespace DisplayMagicianShared.Windows
// Additionally, we had to disable the DEviceKey from the equality testing within the GDI library itself as that waould also change after changing back from NVIDIA surround
// This still allows us to detect when refresh rates change, which will allow DisplayMagician to detect profile differences.
GdiDisplaySettings.Values.SequenceEqual(other.GdiDisplaySettings.Values) &&
- DisplayIdentifiers.SequenceEqual(other.DisplayIdentifiers) &&
- TaskBarLayout.SequenceEqual(other.TaskBarLayout) &&
- TaskBarSettings.Equals(other.TaskBarSettings);
+ DisplayIdentifiers.SequenceEqual(other.DisplayIdentifiers);
+ // NOTE: I have disabled the TaskBar specific matching for now due to errors I cannot fix
+ // WinLibrary will still track the location of the taskbars, but won't actually set them as the setting of the taskbars doesnt work at the moment.
+ /*&&
+ TaskBarLayout.SequenceEqual(other.TaskBarLayout) &&
+ TaskBarSettings.Equals(other.TaskBarSettings);*/
public override int GetHashCode()
{
@@ -180,9 +206,9 @@ namespace DisplayMagicianShared.Windows
myDefaultConfig.DisplayConfigPaths = new DISPLAYCONFIG_PATH_INFO[0];
myDefaultConfig.DisplayHDRStates = new List();
myDefaultConfig.DisplayIdentifiers = new List();
- myDefaultConfig.DisplaySources = new Dictionary>();
+ myDefaultConfig.DisplaySources = new Dictionary>();
myDefaultConfig.GdiDisplaySettings = new Dictionary();
- myDefaultConfig.TaskBarLayout = new List();
+ myDefaultConfig.TaskBarLayout = new Dictionary();
myDefaultConfig.TaskBarSettings = new TaskBarSettings();
myDefaultConfig.IsCloned = false;
@@ -292,6 +318,34 @@ namespace DisplayMagicianShared.Windows
}
}
+ SharedLogger.logger.Trace($"WinLibrary/PatchAdapterIDs: Going through the display sources list info to update the adapter id");
+ // Update the DisplaySources with the current adapter id
+ for (int i = 0; i < savedDisplayConfig.DisplaySources.Count; i++)
+ {
+ List dsList = savedDisplayConfig.DisplaySources.ElementAt(i).Value;
+ if (dsList.Count > 0)
+ {
+ for (int j = 0; j < dsList.Count; j++)
+ {
+ DISPLAY_SOURCE ds = dsList[j];
+ // Change the Display Source AdapterID
+ if (adapterOldToNewMap.ContainsKey(ds.AdapterId.Value))
+ {
+ // We get here if there is a matching adapter
+ newAdapterValue = adapterOldToNewMap[ds.AdapterId.Value];
+ ds.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 in Display Sources! It's possible the adapter was swapped or disabled. Attempting to use adapter {newAdapterValue} instead.");
+ ds.AdapterId = AdapterValueToLUID(newAdapterValue);
+ }
+ }
+ }
+ }
}
public bool UpdateActiveConfig()
@@ -320,6 +374,10 @@ namespace DisplayMagicianShared.Windows
private WINDOWS_DISPLAY_CONFIG GetWindowsDisplayConfig(QDC selector = QDC.QDC_ONLY_ACTIVE_PATHS | QDC.QDC_INCLUDE_HMD)
{
+
+ // Prepare the empty windows display config
+ WINDOWS_DISPLAY_CONFIG windowsDisplayConfig = CreateDefaultConfig();
+
// 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;
@@ -368,12 +426,6 @@ namespace DisplayMagicianShared.Windows
throw new WinLibraryException($"QueryDisplayConfig returned WIN32STATUS {err} when trying to query all available displays.");
}
- // Prepare the empty windows display config
- WINDOWS_DISPLAY_CONFIG windowsDisplayConfig = new WINDOWS_DISPLAY_CONFIG();
- windowsDisplayConfig.DisplayAdapters = new Dictionary();
- windowsDisplayConfig.DisplayHDRStates = new List();
- windowsDisplayConfig.DisplaySources = new Dictionary>();
- windowsDisplayConfig.IsCloned = false;
// First of all generate the current displayIdentifiers
windowsDisplayConfig.DisplayIdentifiers = GetCurrentDisplayIdentifiers();
@@ -393,6 +445,7 @@ namespace DisplayMagicianShared.Windows
// Now cycle through the paths and grab the HDR state information
// and map the adapter name to adapter id
+ // and populate the display source information
List targetPathIdsToChange = new List();
List targetModeIdsToChange = new List();
List targetIdsFound = new List();
@@ -432,7 +485,11 @@ namespace DisplayMagicianShared.Windows
if (windowsDisplayConfig.DisplaySources.ContainsKey(sourceInfo.ViewGdiDeviceName))
{
// We already have at least one display using this source, so we need to add the other cloned display to the existing list
- windowsDisplayConfig.DisplaySources[sourceInfo.ViewGdiDeviceName].Add(paths[i].SourceInfo.Id);
+ DISPLAY_SOURCE ds = new DISPLAY_SOURCE();
+ ds.AdapterId = paths[i].SourceInfo.AdapterId;
+ ds.SourceId = paths[i].SourceInfo.Id;
+ ds.TargetId = paths[i].TargetInfo.Id;
+ windowsDisplayConfig.DisplaySources[sourceInfo.ViewGdiDeviceName].Add(ds);
isClonedPath = true;
isClonedProfile = true;
windowsDisplayConfig.IsCloned = true;
@@ -440,9 +497,13 @@ namespace DisplayMagicianShared.Windows
else
{
// This is the first display to use this source
- List sourceIds = new List();
- sourceIds.Add(paths[i].SourceInfo.Id);
- windowsDisplayConfig.DisplaySources.Add(sourceInfo.ViewGdiDeviceName, sourceIds);
+ List sources = new List();
+ DISPLAY_SOURCE ds = new DISPLAY_SOURCE();
+ ds.AdapterId = paths[i].SourceInfo.AdapterId;
+ ds.SourceId = paths[i].SourceInfo.Id;
+ ds.TargetId = paths[i].TargetInfo.Id;
+ sources.Add(ds);
+ windowsDisplayConfig.DisplaySources.Add(sourceInfo.ViewGdiDeviceName, sources);
}
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Found Display Source {sourceInfo.ViewGdiDeviceName} for source {paths[i].SourceInfo.Id}.");
@@ -618,33 +679,58 @@ namespace DisplayMagicianShared.Windows
modes[i].Id = targetIdMap[modes[i].Id];
}
}
+
+ // And then we need to go through the list of display sources and patch the 'cloned' displays with a real display ID so the display layout is right in cloned displays
+ for (int i = 0; i < windowsDisplayConfig.DisplaySources.Count; i++)
+ {
+ string key = windowsDisplayConfig.DisplaySources.ElementAt(i).Key;
+ DISPLAY_SOURCE[] dsList = windowsDisplayConfig.DisplaySources.ElementAt(i).Value.ToArray();
+ for (int j = 0; j < dsList.Length; j++)
+ {
+ // We only change the ids that match in InfoType for target displays
+ if (targetIdMap.ContainsKey(dsList[j].TargetId))
+ {
+ // Patch the cloned ids with a real working one!
+ dsList[j].TargetId = targetIdMap[dsList[j].TargetId];
+
+ }
+ }
+ windowsDisplayConfig.DisplaySources[key] = dsList.ToList();
+ }
}
+ // Now we need to find the DevicePaths for the DisplaySources (as at this point the cloned display sources have been corrected)
+ for (int i = 0; i < windowsDisplayConfig.DisplaySources.Count; i++)
+ {
+ string key = windowsDisplayConfig.DisplaySources.ElementAt(i).Key;
+ DISPLAY_SOURCE[] dsList = windowsDisplayConfig.DisplaySources.ElementAt(i).Value.ToArray();
+ for (int j = 0; j < dsList.Length; j++)
+ {
+ // get display target name
+ var targetInfo = new DISPLAYCONFIG_TARGET_DEVICE_NAME();
+ targetInfo.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
+ targetInfo.Header.Size = (uint)Marshal.SizeOf();
+ targetInfo.Header.AdapterId = dsList[j].AdapterId;
+ targetInfo.Header.Id = dsList[j].TargetId;
+ err = CCDImport.DisplayConfigGetDeviceInfo(ref targetInfo);
+ if (err == WIN32STATUS.ERROR_SUCCESS)
+ {
+ SharedLogger.logger.Trace($"WinLibrary/GetSomeDisplayIdentifiers: Successfully got the target info from {dsList[j].TargetId}.");
+ dsList[j].DevicePath = targetInfo.MonitorDevicePath;
+ }
+ else
+ {
+ SharedLogger.logger.Warn($"WinLibrary/GetSomeDisplayIdentifiers: WARNING - DisplayConfigGetDeviceInfo returned WIN32STATUS {err} when trying to get the target info for display #{dsList[j].TargetId}");
+ }
+ }
+ windowsDisplayConfig.DisplaySources[key] = dsList.ToList();
+ }
+
+
+ Dictionary taskBarStuckRectangles = new Dictionary();
+
// Now attempt to get the windows taskbar location for each display
- // We use the information we already got from the display identifiers
- SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Attempting to get the Windows Taskbar layout.");
- List taskBarStuckRectangles = new List();
- foreach (var displayId in windowsDisplayConfig.DisplayIdentifiers)
- {
- // e.g. "WINAPI|\\\\?\\PCI#VEN_10DE&DEV_2482&SUBSYS_408E1458&REV_A1#4&2283f625&0&0019#{5b45201d-f2f2-4f3b-85bb-30ff1f953599}|DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DVI|54074|4318|\\\\?\\DISPLAY#NVS10DE#5&2b46c695&0&UID185344#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}|NV Surround"
- string[] winapiLine = displayId.Split('|');
- string pattern = @"DISPLAY\#(.*)\#\{";
- Match match = Regex.Match(winapiLine[5], pattern);
- if (match.Success)
- {
- string devicePath = match.Groups[1].Value;
- TaskBarStuckRectangle taskBarStuckRectangle = new TaskBarStuckRectangle(devicePath);
- taskBarStuckRectangles.Add(taskBarStuckRectangle);
- }
- else
- {
- SharedLogger.logger.Warn($"WinLibrary/GetWindowsDisplayConfig: We were unable to figure out the DevicePath for the '{displayId}' display identifier.");
- }
-
- }
- // And we get the Main Screen taskbar too
- TaskBarStuckRectangle mainTaskBarStuckRectangle = new TaskBarStuckRectangle("Settings");
- taskBarStuckRectangles.Add(mainTaskBarStuckRectangle);
+ taskBarStuckRectangles = TaskBarLayout.GetAllCurrentTaskBarLayouts(windowsDisplayConfig.DisplaySources);
// Now we try to get the taskbar settings too
SharedLogger.logger.Trace($"WinLibrary/GetWindowsDisplayConfig: Attempting to get the Windows Taskbar settings.");
@@ -655,7 +741,6 @@ namespace DisplayMagicianShared.Windows
windowsDisplayConfig.DisplayConfigModes = modes;
windowsDisplayConfig.GdiDisplaySettings = GetGdiDisplaySettings();
windowsDisplayConfig.TaskBarLayout = taskBarStuckRectangles;
- //windowsDisplayConfig.OriginalTaskBarLayout = new List(taskBarStuckRectangles);
windowsDisplayConfig.TaskBarSettings = taskBarSettings;
return windowsDisplayConfig;
@@ -1380,36 +1465,65 @@ namespace DisplayMagicianShared.Windows
}
+ // NOTE: I have disabled the TaskBar setting logic for now due to errors I cannot fix in this code.
+ // WinLibrary will still track the location of the taskbars, but won't actually set them as the setting of the taskbars doesnt work at the moment.
+ // I hope to eventually fix this code, but I don't want to hold up a new DisplayMagician release while troubleshooting this.
+ /*
// Now set the taskbar position for each screen
- if (displayConfig.TaskBarLayout.Count > 0)
+ if (displayConfig.TaskBarLayout.Count > 0 && allWindowsDisplayConfig.TaskBarLayout.Count > 0)
{
- SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Setting the taskbar layout.");
- foreach (TaskBarStuckRectangle tbsr in displayConfig.TaskBarLayout)
+ foreach (var tbrDictEntry in displayConfig.TaskBarLayout)
{
- if (tbsr.Version >= 2 && tbsr.Version <= 3)
+ // Look up the monitor location of the current monitor and find the matching taskbar location in the taskbar settings
+ if (allWindowsDisplayConfig.TaskBarLayout.ContainsKey(tbrDictEntry.Key))
{
- // Write the settings to registry
- tbsr.WriteToRegistry();
-
- if (tbsr.MainScreen)
+ // check the current monitor taskbar location
+ // if the current monitor location is the same as the monitor we want to set then
+ TaskBarLayout currentLayout = displayConfig.TaskBarLayout[tbrDictEntry.Key];
+ TaskBarLayout wantedLayout = allWindowsDisplayConfig.TaskBarLayout[tbrDictEntry.Key];
+ if (currentLayout.Equals(wantedLayout))
{
- TaskBarStuckRectangle.RepositionMainTaskBar(tbsr.Edge);
+ SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Display {tbrDictEntry.Key} ({tbrDictEntry.Value.RegKeyValue}) has the taskbar with the correct position, size and settings, so no need to move it");
+ }
+ else
+ {
+ // if the current monitor taskbar location is not where we want it then
+ // move the taskbar manually
+ TaskBarLayout tbr = tbrDictEntry.Value;
+ tbr.MoveTaskBar();
}
-
}
else
{
- SharedLogger.logger.Error($"WinLibrary/SetActiveConfig: Unable to set the {tbsr.DevicePath} TaskBarStuckRectangle registry settings as the version isn't v2 or v3!");
+ SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Display {tbrDictEntry.Key} ({tbrDictEntry.Value.RegKeyValue}) is not currently in use, so cannot set any taskbars on it!");
}
}
-
- // Tell Windows to refresh the Other Windows Taskbars if needed
- IntPtr lastTaskBarWindowHwnd = (IntPtr)Utils.NULL;
- if (displayConfig.TaskBarLayout.Count > 1)
+ // This will actually move the taskbars by forcing Explorer to read from registry key
+ /*RestartManagerSession.RestartExplorer();
+ Process[] explorers = Process.GetProcessesByName("Explorer");
+ for (int i = 0; i < explorers.Length; i++)
{
- TaskBarStuckRectangle.RepositionSecondaryTaskBars();
+ kill
}
+ // Enum all the monitors
+ //List currentMonitors = Utils.EnumMonitors();
+ // Go through each monitor
+ //foreach (MONITORINFOEX mi in currentMonitors)
+ //{
+ // Look up the monitor location of the current monitor and find the matching taskbar location in the taskbar settings
+ //if (current)
+ // check the current monitor taskbar location
+ // if the current monitor location is the same as the monitor we want to set then
+ // if the current monitor taskbar location where we want it then
+ // move the taskbar manually
+ // Find the registry key for the monitor we are modifying
+ // save the taskbar position for the monitor in registry
+ // else
+ // log the fact that the monitor is in the right place so skipping moving it
+ // if we didn't find a taskbar location for this monitor
+ // log the fact that the taskbar location wasnt foound for this monitor
+ //}
}
else
@@ -1437,7 +1551,7 @@ namespace DisplayMagicianShared.Windows
{
// The settings are the same, so we should skip applying them
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: The current taskbar settings are the same as the one's we want, so skipping setting them!");
- }
+ }*/
return true;
}
@@ -1958,7 +2072,118 @@ namespace DisplayMagicianShared.Windows
{
return false;
}
- }
+ }
+
+
+
+ public static bool RepositionMainTaskBar(TaskBarEdge edge)
+ {
+ // Tell Windows to refresh the Main Screen Windows Taskbar
+ // Find the "Shell_TrayWnd" window
+ IntPtr systemTrayContainerHandle = Utils.FindWindow("Shell_TrayWnd", null);
+ IntPtr startButtonHandle = Utils.FindWindowEx(systemTrayContainerHandle, IntPtr.Zero, "Start", null);
+ IntPtr systemTrayHandle = Utils.FindWindowEx(systemTrayContainerHandle, IntPtr.Zero, "TrayNotifyWnd", null);
+ IntPtr rebarWindowHandle = Utils.FindWindowEx(systemTrayContainerHandle, IntPtr.Zero, "ReBarWindow32", null);
+ IntPtr taskBarPositionBuffer = new IntPtr((Int32)edge);
+ IntPtr trayDesktopShowButtonHandle = Utils.FindWindowEx(systemTrayHandle, IntPtr.Zero, "TrayShowDesktopButtonWClass", null);
+ IntPtr trayInputIndicatorHandle = Utils.FindWindowEx(systemTrayHandle, IntPtr.Zero, "TrayInputIndicatorWClass", null);
+
+ // Send messages
+ // Send the "TrayNotifyWnd" window a WM_USER+13 (0x040D) message with a wParameter of 0x0 and a lParameter of the position (e.g. 0x0000 for left, 0x0001 for top, 0x0002 for right and 0x0003 for bottom)
+ Utils.SendMessage(systemTrayHandle, Utils.WM_USER_13, IntPtr.Zero, taskBarPositionBuffer);
+ Utils.SendMessage(systemTrayHandle, Utils.WM_USER_100, (IntPtr)0x3e, (IntPtr)0x21c);
+ Utils.SendMessage(systemTrayHandle, Utils.WM_THEMECHANGED, (IntPtr)0xffffffffffffffff, (IntPtr)0x000000008000001);
+ // Next, send the "TrayShowDesktopButtonWClass" window a WM_USER+13 (0x040D) message with a wParameter of 0x0 and a lParameter of the position (e.g. 0x0000 for left, 0x0001 for top, 0x0002 for right and 0x0003 for bottom)
+ Utils.SendMessage(trayDesktopShowButtonHandle, Utils.WM_USER_13, IntPtr.Zero, taskBarPositionBuffer);
+ Utils.SendMessage(startButtonHandle, Utils.WM_USER_440, (IntPtr)0x0, (IntPtr)0x0);
+ Utils.SendMessage(systemTrayHandle, Utils.WM_USER_1, (IntPtr)0x0, (IntPtr)0x0);
+ Utils.SendMessage(systemTrayContainerHandle, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, (IntPtr)Utils.NULL);
+ Utils.PostMessage(systemTrayHandle, Utils.WM_SETTINGCHANGE, Utils.SPI_SETWORKAREA, Utils.NULL);
+ Utils.SendMessage(systemTrayContainerHandle, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, (IntPtr)Utils.NULL);
+ Utils.SendMessage(rebarWindowHandle, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, (IntPtr)Utils.NULL);
+ //Utils.SendMessage(trayInputIndicatorHandle, Utils.WM_USER_100, (IntPtr)0x3e, (IntPtr)0x21c);
+ //Utils.SendMessage(systemTrayHandle, Utils.WM_USER_1, (IntPtr)0x0, (IntPtr)0x0);
+ // Move all the taskbars to this location
+ //Utils.SendMessage(systemTrayContainerHandle, Utils.WM_USER_REFRESHTASKBAR, (IntPtr)Utils.wParam_SHELLTRAY, taskBarPositionBuffer);
+ //Utils.SendMessage(systemTrayContainerHandle, Utils.WM_USER_REFRESHTASKBAR, (IntPtr)Utils.wParam_SHELLTRAY, taskBarPositionBuffer);
+ return true;
+ }
+
+ public static bool RepositionAllTaskBars(TaskBarEdge edge)
+ {
+ // Tell Windows to refresh the Main Screen Windows Taskbar
+ // Find the "Shell_TrayWnd" window
+ IntPtr mainToolBarHWnd = Utils.FindWindow("Shell_TrayWnd", null);
+ // Send the "Shell_TrayWnd" window a WM_USER_REFRESHTASKBAR with a wParameter of 0006 and a lParameter of the position (e.g. 0000 for left, 0001 for top, 0002 for right and 0003 for bottom)
+ IntPtr taskBarPositionBuffer = new IntPtr((Int32)edge);
+ Utils.SendMessage(mainToolBarHWnd, Utils.WM_USER_REFRESHTASKBAR, (IntPtr)Utils.wParam_SHELLTRAY, taskBarPositionBuffer);
+ return true;
+ }
+
+ public static bool RepositionSecondaryTaskBars()
+ {
+ // Tell Windows to refresh the Other Windows Taskbars if needed
+ IntPtr lastTaskBarWindowHwnd = (IntPtr)Utils.NULL;
+ for (int i = 0; i < 100; i++)
+ {
+ // Find the next "Shell_SecondaryTrayWnd" window
+ IntPtr nextTaskBarWindowHwnd = Utils.FindWindowEx((IntPtr)Utils.NULL, lastTaskBarWindowHwnd, "Shell_SecondaryTrayWnd", null);
+ if (nextTaskBarWindowHwnd == (IntPtr)Utils.NULL)
+ {
+ // No more windows taskbars to notify
+ break;
+ }
+ // Send the "Shell_TrayWnd" window a WM_SETTINGCHANGE with a wParameter of SPI_SETWORKAREA
+ Utils.SendMessage(lastTaskBarWindowHwnd, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, (IntPtr)Utils.NULL);
+ lastTaskBarWindowHwnd = nextTaskBarWindowHwnd;
+ }
+ return true;
+ }
+
+
+
+ public static void RefreshTrayArea()
+ {
+ // Finds the Shell_TrayWnd -> TrayNotifyWnd -> SysPager -> "Notification Area" containing the visible notification area icons (windows 7 version)
+ IntPtr systemTrayContainerHandle = Utils.FindWindow("Shell_TrayWnd", null);
+ IntPtr systemTrayHandle = Utils.FindWindowEx(systemTrayContainerHandle, IntPtr.Zero, "TrayNotifyWnd", null);
+ IntPtr sysPagerHandle = Utils.FindWindowEx(systemTrayHandle, IntPtr.Zero, "SysPager", null);
+ IntPtr notificationAreaHandle = Utils.FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "Notification Area");
+ // If the visible notification area icons (Windows 7 aren't found, then we're on a later version of windows, and we need to look for different window names
+ if (notificationAreaHandle == IntPtr.Zero)
+ {
+ // Finds the Shell_TrayWnd -> TrayNotifyWnd -> SysPager -> "User Promoted Notification Area" containing the visible notification area icons (windows 10+ version)
+ notificationAreaHandle = Utils.FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "User Promoted Notification Area");
+ // Also attempt to find the NotifyIconOverflowWindow -> "Overflow Notification Area' window which is the hidden windoww that notification icons live when they are
+ // too numberous or are hidden by the user.
+ IntPtr notifyIconOverflowWindowHandle = Utils.FindWindow("NotifyIconOverflowWindow", null);
+ IntPtr overflowNotificationAreaHandle = Utils.FindWindowEx(notifyIconOverflowWindowHandle, IntPtr.Zero, "ToolbarWindow32", "Overflow Notification Area");
+ // Fool the "Overflow Notification Area' window into thinking the mouse is moving over it
+ // which will force windows to refresh the "Overflow Notification Area' window and remove old icons.
+ RefreshTrayArea(overflowNotificationAreaHandle);
+ notifyIconOverflowWindowHandle = IntPtr.Zero;
+ overflowNotificationAreaHandle = IntPtr.Zero;
+ }
+ // Fool the "Notification Area" or "User Promoted Notification Area" window (depends on the version of windows) into thinking the mouse is moving over it
+ // which will force windows to refresh the "Notification Area" or "User Promoted Notification Area" window and remove old icons.
+ RefreshTrayArea(notificationAreaHandle);
+ systemTrayContainerHandle = IntPtr.Zero;
+ systemTrayHandle = IntPtr.Zero;
+ sysPagerHandle = IntPtr.Zero;
+ notificationAreaHandle = IntPtr.Zero;
+
+ }
+
+
+ private static void RefreshTrayArea(IntPtr windowHandle)
+ {
+ // Moves the mouse around within the window area of the supplied window
+ RECT rect;
+ Utils.GetClientRect(windowHandle, out rect);
+ for (var x = 0; x < rect.right; x += 5)
+ for (var y = 0; y < rect.bottom; y += 5)
+ Utils.SendMessage(windowHandle, Utils.WM_MOUSEMOVE, 0, (y << 16) + x);
+ }
}