diff --git a/ColorControl/ColorControl.csproj b/ColorControl/ColorControl.csproj
index eb6152e..3efac85 100644
--- a/ColorControl/ColorControl.csproj
+++ b/ColorControl/ColorControl.csproj
@@ -18,8 +18,8 @@
Maassoft
Maassoft
0
- 9.7.0.0
- 9.7.0.0
+ 9.7.1.0
+ 9.7.1.0
false
true
false
@@ -38,6 +38,7 @@
Properties\app.manifest
true
ColorControl_TemporaryKey.pfx
+ false
bin\x64\Debug\
diff --git a/ColorControl/MainForm.cs b/ColorControl/MainForm.cs
index 015ddd8..a48f044 100644
--- a/ColorControl/MainForm.cs
+++ b/ColorControl/MainForm.cs
@@ -266,8 +266,9 @@ namespace ColorControl
Logger.Debug("Initializing NVIDIA...Done.");
var rpcService = _serviceProvider.GetRequiredService();
+ var winAdminService = _serviceProvider.GetRequiredService();
- _nvPanel = new NvPanel(_serviceManager.NvService, _trayIcon, Handle, appContextProvider, rpcService);
+ _nvPanel = new NvPanel(_serviceManager.NvService, _trayIcon, Handle, appContextProvider, rpcService, winAdminService);
_nvPanel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
InitShortcut(NvPanel.SHORTCUTID_NVQA, _config.NvQuickAccessShortcut, _serviceManager.NvService.ToggleQuickAccessForm);
diff --git a/ColorControl/Services/LG/LgPanel.Designer.cs b/ColorControl/Services/LG/LgPanel.Designer.cs
index 14645f7..b04a24c 100644
--- a/ColorControl/Services/LG/LgPanel.Designer.cs
+++ b/ColorControl/Services/LG/LgPanel.Designer.cs
@@ -418,19 +418,19 @@
mnuLgSetSvcMenuFlag.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { miLgFullServiceMenuEnable, miLgFullServiceMenuDisable });
mnuLgSetSvcMenuFlag.Name = "mnuLgSetSvcMenuFlag";
mnuLgSetSvcMenuFlag.Size = new System.Drawing.Size(320, 22);
- mnuLgSetSvcMenuFlag.Text = "Enable Full Service Menu (C3/G3 only)";
+ mnuLgSetSvcMenuFlag.Text = "Enable Full Service Menu (B3/C3/G3 only)";
//
// miLgFullServiceMenuEnable
//
miLgFullServiceMenuEnable.Name = "miLgFullServiceMenuEnable";
- miLgFullServiceMenuEnable.Size = new System.Drawing.Size(112, 22);
+ miLgFullServiceMenuEnable.Size = new System.Drawing.Size(180, 22);
miLgFullServiceMenuEnable.Text = "Enable";
miLgFullServiceMenuEnable.Click += miLgFullServiceMenuEnable_Click;
//
// miLgFullServiceMenuDisable
//
miLgFullServiceMenuDisable.Name = "miLgFullServiceMenuDisable";
- miLgFullServiceMenuDisable.Size = new System.Drawing.Size(112, 22);
+ miLgFullServiceMenuDisable.Size = new System.Drawing.Size(180, 22);
miLgFullServiceMenuDisable.Text = "Disable";
miLgFullServiceMenuDisable.Click += miLgFullServiceMenuDisable_Click;
//
diff --git a/ColorControl/Services/LG/LgPanel.cs b/ColorControl/Services/LG/LgPanel.cs
index 551ac9e..41e5375 100644
--- a/ColorControl/Services/LG/LgPanel.cs
+++ b/ColorControl/Services/LG/LgPanel.cs
@@ -829,7 +829,7 @@ Do you want to continue?"
mnuLgOLEDMotionPro.Visible = visible;
miLgEnableMotionPro.Visible = enableVisible;
- var svcMenuFlagVisible = new[] { "C3", "G3" }.Any(m => device?.ModelName?.Contains(m) == true);
+ var svcMenuFlagVisible = new[] { "B3", "C3", "G3" }.Any(m => device?.ModelName?.Contains(m) == true);
mnuLgSetSvcMenuFlag.Visible = svcMenuFlagVisible;
diff --git a/ColorControl/Services/LG/LgPanel.resx b/ColorControl/Services/LG/LgPanel.resx
index 6a20818..203d97e 100644
--- a/ColorControl/Services/LG/LgPanel.resx
+++ b/ColorControl/Services/LG/LgPanel.resx
@@ -1,4 +1,64 @@
-
+
+
+
diff --git a/ColorControl/Services/NVIDIA/NvPanel.cs b/ColorControl/Services/NVIDIA/NvPanel.cs
index 5656c19..b46d86b 100644
--- a/ColorControl/Services/NVIDIA/NvPanel.cs
+++ b/ColorControl/Services/NVIDIA/NvPanel.cs
@@ -38,8 +38,9 @@ namespace ColorControl.Services.NVIDIA
private string _lastDisplayRefreshRates = string.Empty;
private NotifyIcon _trayIcon;
private RpcClientService _rpcService;
+ private readonly WinApiAdminService _winApiAdminService;
- public NvPanel(NvService nvService, NotifyIcon trayIcon, IntPtr handle, AppContextProvider appContextProvider, RpcClientService rpcService)
+ public NvPanel(NvService nvService, NotifyIcon trayIcon, IntPtr handle, AppContextProvider appContextProvider, RpcClientService rpcService, WinApiAdminService winApiAdminService)
{
_nvService = nvService;
_trayIcon = trayIcon;
@@ -47,7 +48,7 @@ namespace ColorControl.Services.NVIDIA
_appContextProvider = appContextProvider;
_config = appContextProvider.GetAppContext().Config;
_rpcService = rpcService;
-
+ _winApiAdminService = winApiAdminService;
_rpcService.Name = "NvService";
InitializeComponent();
@@ -441,6 +442,13 @@ namespace ColorControl.Services.NVIDIA
FormUtils.BuildDropDownMenu(mnuNvOtherSettings, "Scaling", typeof(Scaling), preset, "scaling", nvPresetScalingMenuItem_Click, unchanged: true, skipValues: new object[] { Scaling.Customized })
.DropDownItems[0].Visible = !isCurrentDisplay;
+ var itemNameProfile = $"{mnuNvOtherSettings.Name}_Profile";
+ var profileMenu = FormUtils.BuildMenuItem(mnuNvOtherSettings.DropDownItems, itemNameProfile, "Color Profile");
+
+ var subItemNameProfile = $"{itemNameProfile}_SubItem";
+ var subItemProfile = FormUtils.BuildMenuItem(profileMenu.DropDownItems, subItemNameProfile, "", onClick: nvPresetColorProfileMenuItem_Click);
+ subItemProfile.Text = (!preset.ColorProfileSettings.ProfileName.IsNullOrWhiteSpace() ? $"{preset.ColorProfileSettings.ProfileName}" : "Unset") + " (click to change)";
+
FormUtils.BuildDropDownMenu(mnuNvHdmiSettings, "Content type", typeof(InfoFrameVideoContentType), preset.HdmiInfoFrameSettings, "ContentType", nvPresetHdmiContentTypeMenuItem_Click, unchanged: true)
.DropDownItems[0].Visible = !isCurrentDisplay;
FormUtils.BuildDropDownMenu(mnuNvHdmiSettings, "Colorimetry", typeof(InfoFrameVideoColorimetry), preset.HdmiInfoFrameSettings, "Colorimetry", nvPresetHdmiColorimetryMenuItem_Click, unchanged: true)
@@ -847,6 +855,70 @@ namespace ColorControl.Services.NVIDIA
AddOrUpdateItem();
}
+ private void nvPresetColorProfileMenuItem_Click(object sender, EventArgs e)
+ {
+ var preset = GetSelectedNvPreset(true);
+
+ _nvService.ResolveDisplay(preset);
+
+ if (preset.Display == null)
+ {
+ MessageForms.WarningOk($"Display {preset.displayName} not found");
+ return;
+ }
+
+ var display = preset.Display.Name;
+ if (!CCD.GetUsePerUserDisplayProfiles(display))
+ {
+ if (MessageForms.QuestionYesNo("To be able to select a color profile, user specific settings have to be enabled. Do you want to enable this?") != DialogResult.Yes)
+ {
+ return;
+ }
+
+ CCD.SetUsePerUserDisplayProfiles(display, true);
+ }
+
+ var profiles = CCD.GetDisplayColorProfiles(display);
+
+ if (!profiles.Any())
+ {
+ if (MessageForms.QuestionYesNo("There are no profiles associated with this display. You have to manually add these through the Color Management app. Do you want to open this?") != DialogResult.Yes)
+ {
+ return;
+ }
+
+ _winApiAdminService.StartProcess("colorcpl.exe");
+
+ return;
+ }
+
+ profiles.Insert(0, "None");
+
+ var value = SelectStringValue(preset.ColorProfileSettings.ProfileName, "Color Profile", profiles);
+
+ if (value == null)
+ {
+ return;
+ }
+
+ if (value == "None")
+ {
+ value = null;
+ }
+
+ if (preset.IsDisplayPreset)
+ {
+ _nvService.SetColorProfile(preset.Display, value);
+
+ UpdateDisplayInfoItems();
+ return;
+ }
+
+ preset.ColorProfileSettings.ProfileName = value;
+
+ AddOrUpdateItem();
+ }
+
private void refreshRateMenuItem_Click(object sender, EventArgs e)
{
var refreshRate = (uint)((ToolStripItem)sender).Tag;
@@ -1357,6 +1429,33 @@ namespace ColorControl.Services.NVIDIA
return settingValue;
}
+ private string SelectStringValue(string currentValue, string label, IEnumerable values)
+ {
+ var field = new FieldDefinition
+ {
+ Label = label,
+ FieldType = FieldType.DropDown,
+ Values = values,
+ Value = currentValue
+ };
+
+ var resultFields = MessageForms.ShowDialog(field.Label, new[] { field });
+
+ if (!resultFields.Any())
+ {
+ return null;
+ }
+
+ var strValue = (string)resultFields.First().Value;
+
+ if (string.IsNullOrWhiteSpace(strValue))
+ {
+ return null;
+ }
+
+ return strValue;
+ }
+
private void miNvProfileInspector_Click(object sender, EventArgs e)
{
StartNvProfileInspector();
diff --git a/ColorControl/Services/NVIDIA/NvPreset.cs b/ColorControl/Services/NVIDIA/NvPreset.cs
index 6eb0a77..fb87d36 100644
--- a/ColorControl/Services/NVIDIA/NvPreset.cs
+++ b/ColorControl/Services/NVIDIA/NvPreset.cs
@@ -4,6 +4,7 @@ using ColorControl.Shared.Contracts;
using ColorControl.Shared.Contracts.NVIDIA;
using Newtonsoft.Json;
using nspector.Common;
+using NStandard;
using NvAPIWrapper.Display;
using NvAPIWrapper.Native.Display;
using System;
@@ -43,9 +44,10 @@ namespace ColorControl.Services.NVIDIA
public bool applyHdmiSettings { get; set; }
public NvHdmiInfoFrameSettings HdmiInfoFrameSettings { get; set; }
+ public NvColorProfileSettings ColorProfileSettings { get; set; }
[JsonIgnore]
- public bool IsDisplayPreset => Display != null;
+ public bool IsDisplayPreset { get; set; }
[JsonIgnore]
public Display Display { get; set; }
[JsonIgnore]
@@ -72,6 +74,7 @@ namespace ColorControl.Services.NVIDIA
driverSettings = new Dictionary();
ocSettings = new List();
HdmiInfoFrameSettings = new NvHdmiInfoFrameSettings();
+ ColorProfileSettings = new NvColorProfileSettings();
}
public NvPreset(ColorData colorData) : this()
@@ -106,6 +109,7 @@ namespace ColorControl.Services.NVIDIA
SDRBrightness = preset.SDRBrightness;
scaling = preset.scaling;
+ ColorProfileSettings = new NvColorProfileSettings(preset.ColorProfileSettings);
applyOther = preset.applyOther;
HdmiInfoFrameSettings = new NvHdmiInfoFrameSettings(preset.HdmiInfoFrameSettings);
@@ -279,6 +283,10 @@ namespace ColorControl.Services.NVIDIA
{
values.Add($"Scaling: {scaling.Value.GetDescription()}");
}
+ if (!ColorProfileSettings.ProfileName.IsNullOrWhiteSpace())
+ {
+ values.Add($"Color profile: {ColorProfileSettings.ProfileName}");
+ }
if (!values.Any())
{
diff --git a/ColorControl/Services/NVIDIA/NvService.cs b/ColorControl/Services/NVIDIA/NvService.cs
index 8237fca..c80da57 100644
--- a/ColorControl/Services/NVIDIA/NvService.cs
+++ b/ColorControl/Services/NVIDIA/NvService.cs
@@ -28,6 +28,7 @@ using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
+using static ColorControl.Shared.Native.CCD;
namespace ColorControl.Services.NVIDIA
{
@@ -241,15 +242,18 @@ namespace ColorControl.Services.NVIDIA
}
private void SetCurrentDisplay(NvPreset preset)
+ {
+ _currentDisplay = GetPresetDisplay(preset);
+ }
+
+ private Display GetPresetDisplay(NvPreset preset)
{
if (preset.primaryDisplay)
{
- _currentDisplay = GetPrimaryDisplay();
- }
- else
- {
- _currentDisplay = Display.GetDisplays().FirstOrDefault(x => x.Name.Equals(preset.displayName));
+ return GetPrimaryDisplay();
}
+
+ return Display.GetDisplays().FirstOrDefault(x => x.Name.Equals(preset.displayName));
}
public Display GetPrimaryDisplay()
@@ -346,6 +350,11 @@ namespace ColorControl.Services.NVIDIA
{
SetSDRBrightness(display, preset.SDRBrightness.Value);
}
+
+ if (preset.ColorProfileSettings.ProfileName != null)
+ {
+ CCD.SetDisplayDefaultColorProfile(display.Name, preset.ColorProfileSettings.ProfileName);
+ }
}
if (preset.applyHdmiSettings)
@@ -903,9 +912,25 @@ namespace ColorControl.Services.NVIDIA
return pathInfos.FirstOrDefault(c => c.TargetsInfo.Any(ti => ti.DisplayId == display.DisplayDevice.DisplayId));
}
+ public void SetColorProfile(Display display, string name)
+ {
+ CCD.SetDisplayDefaultColorProfile(display.Name, name);
+ }
+
public void TestResolution()
{
//var display = GetCurrentDisplay();
+
+ //CCD.GetUsePerUserDisplayProfiles(display.Name);
+
+ //CCD.GetDisplayColorProfiles(display.Name);
+
+ //CCD.InstallColorProfile(@"H:\srgb2000.icm");
+
+ //CCD.AddDisplayColorProfile(display.Name, "srgb2000.icm");
+
+ //CCD.SetDisplayDefaultColorProfile(display.Name, "srgb2000.icm");
+
//var displayDevice = display.DisplayDevice;
//var config = DisplayApi.GetDisplayConfig();
@@ -1071,13 +1096,16 @@ namespace ColorControl.Services.NVIDIA
}
var isPrimaryDisplay = displayCount == 1 || display.DisplayDevice.DisplayId == DisplayDevice.GetGDIPrimaryDisplayDevice()?.DisplayId;
- var preset = new NvPreset { Display = display, applyColorData = false, primaryDisplay = isPrimaryDisplay };
+ var preset = new NvPreset { Display = display, IsDisplayPreset = true, applyColorData = false, primaryDisplay = isPrimaryDisplay };
+
+ preset.HDREnabled = IsHDREnabled(display);
preset.displayName = FormUtils.ExtendedDisplayName(display.Name);
preset.colorData = GetCurrentColorData(display);
preset.HdmiInfoFrameSettings = GetHdmiSettings(display);
preset.SDRBrightness = GetSDRBrightness(display);
preset.scaling = GetScaling(display);
+ preset.ColorProfileSettings.ProfileName = CCD.GetDisplayDefaultColorProfile(display.Name, preset.HDREnabled ? COLORPROFILESUBTYPE.CPST_EXTENDED_DISPLAY_COLOR_MODE : COLORPROFILESUBTYPE.CPST_STANDARD_DISPLAY_COLOR_MODE);
var mode = GetCurrentMode(display.Name);
@@ -1100,8 +1128,6 @@ namespace ColorControl.Services.NVIDIA
preset.ditheringMode = (uint)ditherInfo.mode;
}
- preset.HDREnabled = IsHDREnabled(display);
-
if (Config.ShowOverclocking)
{
var gpus = GetGPUs();
@@ -1311,5 +1337,15 @@ namespace ColorControl.Services.NVIDIA
{
Utils.WriteObject(_configFilename, Config);
}
+
+ internal void ResolveDisplay(NvPreset preset)
+ {
+ if (preset.Display != null)
+ {
+ return;
+ }
+
+ preset.Display = GetPresetDisplay(preset);
+ }
}
}
diff --git a/ColorControl/Services/Samsung/SamTvConnection.cs b/ColorControl/Services/Samsung/SamTvConnection.cs
index 3ebebcb..6e50ba6 100644
--- a/ColorControl/Services/Samsung/SamTvConnection.cs
+++ b/ColorControl/Services/Samsung/SamTvConnection.cs
@@ -25,7 +25,7 @@ namespace ColorControl.Services.Samsung
{
public static SynchronizationContext SyncContext { get; set; }
- public bool ConnectionClosed { get; private set; }
+ public bool? ConnectionClosed { get; private set; }
public bool ClosedByDispose { get; private set; }
private MessageWebSocket _connection;
@@ -133,7 +133,7 @@ namespace ColorControl.Services.Samsung
_tokens.TryAdd(id, taskSource);
await SendMessageAsync(message);
- if (ConnectionClosed)
+ if (ConnectionClosed == true)
{
throw new Exception("Connection closed");
}
@@ -143,7 +143,7 @@ namespace ColorControl.Services.Samsung
else
{
await SendMessageAsync(message);
- if (ConnectionClosed)
+ if (ConnectionClosed == true)
{
throw new Exception("Connection closed");
}
diff --git a/ColorControl/Services/Samsung/SamsungService.cs b/ColorControl/Services/Samsung/SamsungService.cs
index 1f3dc55..8973b7f 100644
--- a/ColorControl/Services/Samsung/SamsungService.cs
+++ b/ColorControl/Services/Samsung/SamsungService.cs
@@ -205,7 +205,7 @@ namespace ColorControl.Services.Samsung
}
else
{
- var _ = SelectedDevice.ConnectAsync();
+ //var _ = SelectedDevice.ConnectAsync();
}
}
}
diff --git a/Shared/Contracts/NVIDIA/NvColorProfileSettings.cs b/Shared/Contracts/NVIDIA/NvColorProfileSettings.cs
new file mode 100644
index 0000000..d178442
--- /dev/null
+++ b/Shared/Contracts/NVIDIA/NvColorProfileSettings.cs
@@ -0,0 +1,25 @@
+namespace ColorControl.Shared.Contracts.NVIDIA
+{
+ public class NvColorProfileSettings
+ {
+ public string ProfileName { get; set; }
+
+ public NvColorProfileSettings()
+ {
+ }
+
+ public NvColorProfileSettings(NvColorProfileSettings settings)
+ {
+ settings ??= new NvColorProfileSettings();
+
+ ProfileName = settings.ProfileName;
+ }
+
+ public override string ToString()
+ {
+ var value = string.Empty;
+
+ return value;
+ }
+ }
+}
diff --git a/Shared/Native/CCD.cs b/Shared/Native/CCD.cs
index b238ebb..e3e5e0e 100644
--- a/Shared/Native/CCD.cs
+++ b/Shared/Native/CCD.cs
@@ -1,4 +1,5 @@
-using NWin32;
+using ColorControl.Shared.Forms;
+using NWin32;
using System.ComponentModel;
using System.Runtime.InteropServices;
@@ -8,6 +9,7 @@ namespace ColorControl.Shared.Native
public static class CCD
{
private static bool? IsHDRActive = null;
+ delegate (T, bool) DisplayConfigModeInfoDelegate(DisplayConfigModeInfo modeInfo);
public enum DisplayTopology
{
@@ -60,7 +62,7 @@ namespace ColorControl.Shared.Native
}
}
- public static void SetHDRState(bool enabled, string displayName = null, float? SDRWhiteLevelInNits = null)
+ public static void SetHDRState(bool enabled, string displayName = null)
{
uint pathCount, modeCount;
@@ -120,7 +122,271 @@ namespace ColorControl.Shared.Native
}
}
+ public static LUID GetAdapterId(string displayName = null)
+ {
+ return ExecuteForModeConfig((modeInfo) =>
+ {
+ if (modeInfo.infoType == DisplayConfigModeInfoType.Target)
+ {
+ return (modeInfo.adapterId, false);
+ }
+
+ return (default(LUID), true);
+ }, displayName
+ );
+ }
+
+ public static uint GetSourceId(string displayName = null)
+ {
+ return ExecuteForModeConfig((modeInfo) =>
+ {
+ if (modeInfo.infoType == DisplayConfigModeInfoType.Source)
+ {
+ return (modeInfo.id, false);
+ }
+
+ return (0u, true);
+ }, displayName
+ );
+ }
+
+ public static bool InstallColorProfile(string profileName)
+ {
+ var result = NativeMethods.InstallColorProfileW(null, profileName);
+
+ if (!result)
+ {
+ var err = NWin32.NativeMethods.GetLastError();
+
+ throw new Win32Exception((int)err);
+ }
+
+ return true;
+ }
+
+ private static bool MinRequiredVersion = true;
+
+ public static bool AddDisplayColorProfile(string displayName, string profileName, bool setAsDefault = true)
+ {
+ var adapterId = GetAdapterId(displayName);
+ var sourceId = GetSourceId(displayName);
+
+ var err = NativeMethods.ColorProfileAddDisplayAssociation(WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER, profileName, adapterId, sourceId, setAsDefault, true);
+
+ if (err != NativeConstants.ERROR_SUCCESS)
+ {
+ throw new Win32Exception(err);
+ }
+
+ return err == NativeConstants.ERROR_SUCCESS;
+ }
+
+ public static bool RemoveDisplayColorProfile(string displayName, string profileName)
+ {
+ var adapterId = GetAdapterId(displayName);
+ var sourceId = GetSourceId(displayName);
+
+ var err = NativeMethods.ColorProfileRemoveDisplayAssociation(WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER, profileName, adapterId, sourceId, true);
+
+ if (err != NativeConstants.ERROR_SUCCESS)
+ {
+ throw new Win32Exception(err);
+ }
+
+ return err == NativeConstants.ERROR_SUCCESS;
+ }
+
+ public static bool SetDisplayDefaultColorProfile(string displayName, string profileName)
+ {
+ var adapterId = GetAdapterId(displayName);
+ var sourceId = GetSourceId(displayName);
+
+ var subType = COLORPROFILESUBTYPE.CPST_PERCEPTUAL;
+
+ if (profileName == null)
+ {
+ profileName = GetDisplayDefaultColorProfile(displayName, COLORPROFILESUBTYPE.CPST_EXTENDED_DISPLAY_COLOR_MODE);
+
+ if (profileName == null)
+ {
+ return true;
+ }
+
+ return RemoveDisplayColorProfile(displayName, profileName) && AddDisplayColorProfile(displayName, profileName, false);
+ }
+
+ var err = NativeMethods.ColorProfileSetDisplayDefaultAssociation(WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER, profileName, COLORPROFILETYPE.CPT_ICC, subType, adapterId, sourceId);
+
+ if (err != NativeConstants.ERROR_SUCCESS)
+ {
+ throw new Win32Exception(err);
+ }
+
+ return err == NativeConstants.ERROR_SUCCESS;
+ }
+
+ public static string GetDisplayDefaultColorProfile(string displayName, COLORPROFILESUBTYPE profileSubType = COLORPROFILESUBTYPE.CPST_STANDARD_DISPLAY_COLOR_MODE)
+ {
+ if (!MinRequiredVersion)
+ {
+ return null;
+ }
+
+ var adapterId = GetAdapterId(displayName);
+ var sourceId = GetSourceId(displayName);
+
+ var scope = GetUsePerUserDisplayProfiles(displayName) ? WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER : WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_SYSTEM_WIDE;
+ try
+ {
+ var pointer = new IntPtr();
+ var err = NativeMethods.ColorProfileGetDisplayDefault(scope, adapterId, sourceId, COLORPROFILETYPE.CPT_ICC, profileSubType, pointer);
+
+ if (err != NativeConstants.ERROR_SUCCESS)
+ {
+ // No default profile set
+ if (err == -2147024894)
+ {
+ return null;
+ }
+
+ throw new Win32Exception(err);
+ }
+ var profileName = Marshal.PtrToStringUni(pointer);
+
+ return profileName;
+ }
+ catch (Exception)
+ {
+ MinRequiredVersion = false;
+ }
+ return null;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct UnmanagedStruct
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
+ public IntPtr[] listOfStrings;
+ }
+
+ public static List GetDisplayColorProfiles(string displayName)
+ {
+ var adapterId = GetAdapterId(displayName);
+ var sourceId = GetSourceId(displayName);
+
+ var pointer = IntPtr.Zero;
+
+ var scope = GetUsePerUserDisplayProfiles(displayName) ? WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER : WCS_PROFILE_MANAGEMENT_SCOPE.WCS_PROFILE_MANAGEMENT_SCOPE_SYSTEM_WIDE;
+
+ var err = NativeMethods.ColorProfileGetDisplayList(scope, adapterId, sourceId, pointer, out var profileCount);
+
+ if (err != NativeConstants.ERROR_SUCCESS)
+ {
+ throw new Win32Exception(err);
+ }
+
+ // No items
+ if (pointer == IntPtr.Zero)
+ {
+ return new List();
+ }
+
+ var data = Marshal.PtrToStructure(pointer);
+ var list = data.listOfStrings.Take((int)profileCount).Select(p => Marshal.PtrToStringUni(p)).ToList();
+
+ return list;
+ }
+
+ public static bool GetUsePerUserDisplayProfiles(string displayName)
+ {
+ var deviceKey = GetDisplayDeviceKey(displayName);
+
+ if (deviceKey == null)
+ {
+ return false;
+ }
+
+ var result = NativeMethods.WcsGetUsePerUserProfiles(deviceKey, DeviceClassFlags.CLASS_MONITOR, out var usePerUserProfiles);
+
+ if (!result)
+ {
+ //if (err != NativeConstants.ERROR_SUCCESS)
+ //{
+ // throw new Win32Exception(err);
+ //}
+ }
+
+ return usePerUserProfiles;
+ }
+
+ public static bool SetUsePerUserDisplayProfiles(string displayName, bool usePerUserProfiles)
+ {
+ var deviceKey = GetDisplayDeviceKey(displayName);
+
+ if (deviceKey == null)
+ {
+ return false;
+ }
+
+ var result = NativeMethods.WcsSetUsePerUserProfiles(deviceKey, DeviceClassFlags.CLASS_MONITOR, usePerUserProfiles);
+
+ return result;
+ }
+
+ private static string GetDisplayDeviceKey(string displayName)
+ {
+ var hMonitor = FormUtils.GetMonitorForDisplayName(displayName);
+
+ if (hMonitor == IntPtr.Zero)
+ {
+ return null;
+ }
+
+ var mInfo = new MONITORINFOEX();
+ mInfo.cbSize = (uint)Marshal.SizeOf(mInfo);
+ if (!NativeMethods.GetMonitorInfo(hMonitor, ref mInfo))
+ {
+ return null;
+ }
+
+ var dd = new DISPLAYDEVICE();
+ dd.cb = (uint)Marshal.SizeOf(dd);
+ if (!NativeMethods.EnumDisplayDevices(mInfo.szDevice, 0, ref dd, 0))
+ {
+ return null;
+ }
+
+ return dd.DeviceKey;
+ }
+
public static uint GetSDRWhiteLevel(string displayName = null)
+ {
+ return ExecuteForModeConfig((modeInfo) =>
+ {
+ if (modeInfo.infoType == DisplayConfigModeInfoType.Target)
+ {
+ var requestpacket = new DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO();
+ requestpacket.header = new DISPLAYCONFIG_DEVICE_INFO_HEADER();
+ requestpacket.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO;
+ requestpacket.header.size = Marshal.SizeOf();
+
+ requestpacket.header.adapterId = modeInfo.adapterId;
+ requestpacket.header.id = modeInfo.id;
+
+ var err = NativeMethods.DisplayConfigGetDeviceInfo(ref requestpacket);
+
+ if (err == NativeConstants.ERROR_SUCCESS && requestpacket.advancedColorSupported)
+ {
+ return (GetSDRWhiteLevelForDisplayConfig(modeInfo), false);
+ }
+ }
+
+ return (0, true);
+ }, displayName
+ );
+ }
+
+ private static T ExecuteForModeConfig(DisplayConfigModeInfoDelegate infoDelegate, string displayName = null)
{
uint pathCount, modeCount;
@@ -142,24 +408,13 @@ namespace ColorControl.Shared.Native
continue;
}
- var requestpacket = new DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO();
- requestpacket.header = new DISPLAYCONFIG_DEVICE_INFO_HEADER();
- requestpacket.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO;
- requestpacket.header.size = Marshal.SizeOf();
-
for (int i = 0; i < modeCount; i++)
{
- if (modesArray[i].infoType == DisplayConfigModeInfoType.Target)
+ var result = infoDelegate(modesArray[i]);
+
+ if (!result.Item2)
{
- requestpacket.header.adapterId = modesArray[i].adapterId;
- requestpacket.header.id = modesArray[i].id;
-
- err = NativeMethods.DisplayConfigGetDeviceInfo(ref requestpacket);
-
- if (err == NativeConstants.ERROR_SUCCESS && requestpacket.advancedColorSupported)
- {
- return GetSDRWhiteLevelForDisplayConfig(modesArray[i]);
- }
+ return result.Item1;
}
}
}
@@ -171,7 +426,7 @@ namespace ColorControl.Shared.Native
throw new Win32Exception(err);
}
- return 0;
+ return default;
}
public static bool IsHDREnabled(string displayName = null)
@@ -314,7 +569,7 @@ namespace ColorControl.Shared.Native
}
[StructLayout(LayoutKind.Sequential)]
- struct LUID
+ public struct LUID
{
uint LowPart;
uint HighPart;
@@ -682,6 +937,87 @@ namespace ColorControl.Shared.Native
public string viewGdiDeviceName;
}
+ enum WCS_PROFILE_MANAGEMENT_SCOPE
+ {
+ WCS_PROFILE_MANAGEMENT_SCOPE_SYSTEM_WIDE,
+ WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER
+ };
+
+ enum COLORPROFILETYPE
+ {
+ CPT_ICC,
+ CPT_DMP,
+ CPT_CAMP,
+ CPT_GMMP
+ };
+
+ public enum COLORPROFILESUBTYPE
+ {
+ CPST_PERCEPTUAL,
+ CPST_RELATIVE_COLORIMETRIC,
+ CPST_SATURATION,
+ CPST_ABSOLUTE_COLORIMETRIC,
+ CPST_NONE,
+ CPST_RGB_WORKING_SPACE,
+ CPST_CUSTOM_WORKING_SPACE,
+ CPST_STANDARD_DISPLAY_COLOR_MODE,
+ CPST_EXTENDED_DISPLAY_COLOR_MODE
+ };
+
+ enum DeviceClassFlags : UInt32
+ {
+ // from: c:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\um\Icm.h
+ ///
+ ///#define CLASS_MONITOR 'mntr'
+ ///
+ CLASS_MONITOR = 0x6d6e7472,
+
+ ///
+ /// #define CLASS_PRINTER 'prtr'
+ ///
+ CLASS_PRINTER = 0x70727472,
+
+ ///
+ /// #define CLASS_SCANNER 'scnr'
+ ///
+ CLASS_SCANNER = 0x73636e72
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int Left;
+ public int Top;
+ public int Right;
+ public int Bottom;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct MONITORINFOEX
+ {
+ public uint cbSize;
+ public RECT rcMonitor;
+ public RECT rcWork;
+ public uint dwFlags;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
+ public string szDevice;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ public struct DISPLAYDEVICE
+ {
+ public uint cb;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
+ public string DeviceName;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
+ public string DeviceString;
+ public uint StateFlags;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
+ public string DeviceID;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
+ public string DeviceKey;
+ }
+
#endregion
static class NativeMethods
@@ -710,8 +1046,29 @@ namespace ColorControl.Shared.Native
[DllImport("user32")]
public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_SDR_WHITE_LEVEL requestPacket);
- [DllImport("user32")]
- public static extern int DisplayConfigSetDeviceInfo(ref DISPLAYCONFIG_SDR_WHITE_LEVEL setPacket);
+ [DllImport("mscms", CharSet = CharSet.Unicode)]
+ public static extern bool InstallColorProfileW(string machineName, string profilename);
+
+ [DllImport("mscms", CharSet = CharSet.Unicode)]
+ public static extern int ColorProfileSetDisplayDefaultAssociation(WCS_PROFILE_MANAGEMENT_SCOPE scope, string profilename, COLORPROFILETYPE profiletype, COLORPROFILESUBTYPE profilesubtype, LUID targetadapterid, uint sourceid);
+
+ [DllImport("mscms", CharSet = CharSet.Unicode)]
+ public static extern int ColorProfileAddDisplayAssociation(WCS_PROFILE_MANAGEMENT_SCOPE scope, string profilename, LUID targetadapterid, uint sourceid, bool setAsDefault, bool associateAsAdvancedColor);
+
+ [DllImport("mscms", CharSet = CharSet.Unicode)]
+ public static extern int ColorProfileRemoveDisplayAssociation(WCS_PROFILE_MANAGEMENT_SCOPE scope, string profilename, LUID targetadapterid, uint sourceid, bool associateAsAdvancedColor);
+ [DllImport("mscms", CharSet = CharSet.Unicode)]
+ public static extern int ColorProfileGetDisplayList(WCS_PROFILE_MANAGEMENT_SCOPE scope, LUID targetadapterid, uint sourceid, in IntPtr pointer, out uint profileCount);
+ [DllImport("mscms", CharSet = CharSet.Unicode)]
+ public static extern int ColorProfileGetDisplayDefault(WCS_PROFILE_MANAGEMENT_SCOPE scope, LUID targetadapterid, uint sourceid, COLORPROFILETYPE profiletype, COLORPROFILESUBTYPE profilesubtype, in IntPtr pointer);
+ [DllImport("mscms", CharSet = CharSet.Unicode, SetLastError = true)]
+ public static extern bool WcsGetUsePerUserProfiles(string deviceName, DeviceClassFlags deviceClass, out bool usePerUserProfiles);
+ [DllImport("mscms", CharSet = CharSet.Unicode, SetLastError = true)]
+ public static extern bool WcsSetUsePerUserProfiles(string deviceName, DeviceClassFlags deviceClass, bool usePerUserProfiles);
+ [DllImport("user32.dll")]
+ public extern static bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFOEX lpmi);
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ public static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAYDEVICE lpDisplayDevice, uint dwFlags);
}
}
}
diff --git a/Shared/Services/RpcServerService.cs b/Shared/Services/RpcServerService.cs
index b2a29f7..5d0a2f4 100644
--- a/Shared/Services/RpcServerService.cs
+++ b/Shared/Services/RpcServerService.cs
@@ -34,8 +34,7 @@ public class RpcServerService
var arg = message.Arguments[i];
var methodParam = methodParams[i];
- var convertedArg = ConvertArgument(arg, methodParam.ParameterType);
- convertedArgs.Add(arg);
+ AddArgument(arg, methodParam.ParameterType, convertedArgs);
}
Logger.Debug($"Executing RPC: {message.ServiceName}.{message.MethodName}({string.Join(", ", convertedArgs)})");
@@ -54,21 +53,22 @@ public class RpcServerService
}
}
- private object ConvertArgument(object arg, Type type)
+ private void AddArgument(object arg, Type type, List