fix Novideo, add Game launcher auto-apply, add some LG actions, move winapi/admin functions to designated services

This commit is contained in:
Vincent Maas committed 2023-10-28 14:53:17 +02:00
1 parent 6eae7db459
commit 9fd8e8f9bb
63 files changed
+3297 -2344

No files matched your search

+5 -2
View File
@@ -18,8 +18,8 @@
<PublisherName>Maassoft</PublisherName>
<Company>Maassoft</Company>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>9.6.4.0</ApplicationVersion>
<Version>9.6.4.0</Version>
<ApplicationVersion>9.7.0.0</ApplicationVersion>
<Version>9.7.0.0</Version>
<UseApplicationTrust>false</UseApplicationTrust>
<PublishWizardCompleted>true</PublishWizardCompleted>
<BootstrapperEnabled>false</BootstrapperEnabled>
@@ -63,6 +63,9 @@
<Compile Update="services\lg\RemoteControlPanel.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Update="Services\NVIDIA\NvInfoPanel.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Update="Services\NVIDIA\NvPanel.cs" />
<Compile Update="Services\Samsung\SamsungPanel.cs">
<SubType>UserControl</SubType>
+4 -45
View File
@@ -5,6 +5,7 @@ using ColorControl.Services.NVIDIA;
using ColorControl.Services.Samsung;
using ColorControl.Shared.Common;
using ColorControl.Shared.Contracts;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
@@ -16,55 +17,11 @@ namespace ColorControl
{
public static async Task<bool> HandleStartupParams(StartUpParams startUpParams, Process existingProcess)
{
if (startUpParams.ActivateChromeFontFix || startUpParams.DeactivateChromeFontFix)
{
Utils.InstallChromeFix(startUpParams.ActivateChromeFontFix, startUpParams.ChromeFontFixApplicationDataFolder);
return true;
}
if (startUpParams.EnableAutoStart || startUpParams.DisableAutoStart)
{
Utils.RegisterTask(Program.TS_TASKNAME, startUpParams.EnableAutoStart, startUpParams.AutoStartRunLevel);
return true;
}
if (startUpParams.SetProcessAffinity)
{
Utils.SetProcessAffinity(startUpParams.ProcessId, startUpParams.AffinityMask);
return true;
}
if (startUpParams.SetProcessPriority)
{
Utils.SetProcessPriority(startUpParams.ProcessId, startUpParams.PriorityClass);
return true;
}
if (startUpParams.StartElevated)
{
StartElevated();
return true;
}
if (startUpParams.SendWol)
{
return WOL.WakeFunction(startUpParams.WolMacAddress, startUpParams.WolIpAddress);
}
if (startUpParams.InstallService)
{
Utils.InstallService();
return true;
}
if (startUpParams.UninstallService)
{
Utils.UninstallService();
return true;
}
if (startUpParams.StartService)
{
Utils.StartService();
return true;
}
if (startUpParams.StopService)
{
Utils.StopService();
return true;
}
var useConsole = startUpParams.NoGui || existingProcess != null;
@@ -152,7 +109,9 @@ Options:
{
try
{
Application.Run(new ElevatedForm());
var elevatedForm = Program.ServiceProvider.GetRequiredService<ElevatedForm>();
Application.Run(elevatedForm);
}
catch (Exception ex)
{
+39 -71
View File
@@ -1,85 +1,53 @@
using ColorControl.Shared.Contracts;
using ColorControl.Shared.Native;
using NWin32;
using ColorControl.Svc;
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ColorControl.Forms
namespace ColorControl.Forms;
public partial class ElevatedForm : Form
{
public partial class ElevatedForm : Form
private ColorControlBackgroundService _backgroundService;
public ElevatedForm(ColorControlBackgroundService backgroundService)
{
public ElevatedForm()
InitializeComponent();
FormBorderStyle = FormBorderStyle.None;
ShowInTaskbar = false;
Load += ElevatedForm_Load;
Shown += ElevatedForm_Shown;
Task.Run(CheckMutexAsync);
_backgroundService = backgroundService;
_backgroundService.PipeName = "elevatedpipe";
Task.Run(async () => await _backgroundService.StartAsync(CancellationToken.None));
}
private void ElevatedForm_Shown(object sender, EventArgs e)
{
Hide();
}
protected void ElevatedForm_Load(object sender, EventArgs e)
{
Size = new Size(0, 0);
}
private void CheckMutexAsync()
{
var mutex = new Mutex(false, Shared.Common.GlobalContext.CurrentContext.MutexId, out var created);
try
{
InitializeComponent();
FormBorderStyle = FormBorderStyle.None;
ShowInTaskbar = false;
Load += ElevatedForm_Load;
Shown += ElevatedForm_Shown;
var filterStatus = new WinApi.CHANGEFILTERSTRUCT();
filterStatus.size = (uint)Marshal.SizeOf(filterStatus);
filterStatus.info = 0;
WinApi.ChangeWindowMessageFilterEx(Handle, NativeConstants.WM_COPYDATA, WinApi.ChangeWindowMessageFilterExAction.Allow, ref filterStatus);
Task.Run(CheckMutexAsync);
mutex.WaitOne();
}
private void ElevatedForm_Shown(object sender, EventArgs e)
catch (AbandonedMutexException)
{
Hide();
}
protected void ElevatedForm_Load(object sender, EventArgs e)
{
Size = new Size(0, 0);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == NativeConstants.WM_COPYDATA)
{
var container = (WinApi.COPYDATASTRUCT)m.GetLParam(typeof(WinApi.COPYDATASTRUCT));
var message = Marshal.PtrToStringAnsi(container.lpData);
HandleMessage(message);
}
base.WndProc(ref m);
}
private void HandleMessage(string message)
{
var args = message.Split(' ');
var startUpParams = StartUpParams.Parse(args);
try
{
var _ = CommandLineHandler.HandleStartupParams(startUpParams, null);
}
catch (Exception)
{
}
}
private void CheckMutexAsync()
{
var mutex = new Mutex(false, Shared.Common.AppContext.CurrentContext.MutexId, out var created);
try
{
mutex.WaitOne();
}
catch (AbandonedMutexException)
{
}
BeginInvoke(Application.Exit);
}
BeginInvoke(Application.Exit);
}
}
-44
View File
@@ -59,9 +59,6 @@
chkStartMinimized = new System.Windows.Forms.CheckBox();
chkStartAfterLogin = new System.Windows.Forms.CheckBox();
tabInfo = new System.Windows.Forms.TabPage();
grpNVIDIAInfo = new System.Windows.Forms.GroupBox();
btnRefreshNVIDIAInfo = new System.Windows.Forms.Button();
tvNVIDIAInfo = new System.Windows.Forms.TreeView();
groupBox3 = new System.Windows.Forms.GroupBox();
lbPlugins = new System.Windows.Forms.ListBox();
label7 = new System.Windows.Forms.Label();
@@ -73,7 +70,6 @@
grpMiscellaneousOptions.SuspendLayout();
grpGeneralOptions.SuspendLayout();
tabInfo.SuspendLayout();
grpNVIDIAInfo.SuspendLayout();
groupBox3.SuspendLayout();
SuspendLayout();
//
@@ -441,7 +437,6 @@
//
// tabInfo
//
tabInfo.Controls.Add(grpNVIDIAInfo);
tabInfo.Controls.Add(groupBox3);
tabInfo.Location = new System.Drawing.Point(4, 24);
tabInfo.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
@@ -452,41 +447,6 @@
tabInfo.Text = "Info";
tabInfo.UseVisualStyleBackColor = true;
//
// grpNVIDIAInfo
//
grpNVIDIAInfo.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
grpNVIDIAInfo.Controls.Add(btnRefreshNVIDIAInfo);
grpNVIDIAInfo.Controls.Add(tvNVIDIAInfo);
grpNVIDIAInfo.Location = new System.Drawing.Point(463, 7);
grpNVIDIAInfo.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
grpNVIDIAInfo.Name = "grpNVIDIAInfo";
grpNVIDIAInfo.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3);
grpNVIDIAInfo.Size = new System.Drawing.Size(643, 511);
grpNVIDIAInfo.TabIndex = 4;
grpNVIDIAInfo.TabStop = false;
grpNVIDIAInfo.Text = "NVIDIA info";
//
// btnRefreshNVIDIAInfo
//
btnRefreshNVIDIAInfo.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left;
btnRefreshNVIDIAInfo.Location = new System.Drawing.Point(7, 478);
btnRefreshNVIDIAInfo.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
btnRefreshNVIDIAInfo.Name = "btnRefreshNVIDIAInfo";
btnRefreshNVIDIAInfo.Size = new System.Drawing.Size(88, 27);
btnRefreshNVIDIAInfo.TabIndex = 1;
btnRefreshNVIDIAInfo.Text = "Refresh";
btnRefreshNVIDIAInfo.UseVisualStyleBackColor = true;
btnRefreshNVIDIAInfo.Click += btnRefreshNVIDIAInfo_Click;
//
// tvNVIDIAInfo
//
tvNVIDIAInfo.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
tvNVIDIAInfo.Location = new System.Drawing.Point(7, 22);
tvNVIDIAInfo.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
tvNVIDIAInfo.Name = "tvNVIDIAInfo";
tvNVIDIAInfo.Size = new System.Drawing.Size(628, 448);
tvNVIDIAInfo.TabIndex = 0;
//
// groupBox3
//
groupBox3.Controls.Add(lbPlugins);
@@ -579,7 +539,6 @@
grpGeneralOptions.ResumeLayout(false);
grpGeneralOptions.PerformLayout();
tabInfo.ResumeLayout(false);
grpNVIDIAInfo.ResumeLayout(false);
groupBox3.ResumeLayout(false);
groupBox3.PerformLayout();
ResumeLayout(false);
@@ -597,9 +556,6 @@
private System.Windows.Forms.ListBox lbPlugins;
private System.Windows.Forms.Label label7;
private System.Windows.Forms.Label lblInfo;
private System.Windows.Forms.GroupBox grpNVIDIAInfo;
private System.Windows.Forms.TreeView tvNVIDIAInfo;
private System.Windows.Forms.Button btnRefreshNVIDIAInfo;
private System.Windows.Forms.GroupBox grpMiscellaneousOptions;
private System.Windows.Forms.CheckBox chkFixChromeFonts;
private System.Windows.Forms.Label lblFixChromeFontsDescription;
+41 -77
View File
@@ -15,7 +15,6 @@ using Linearstar.Windows.RawInput;
using Microsoft.Extensions.DependencyInjection;
using NLog;
using novideo_srgb;
using NvAPIWrapper.Display;
using NWin32;
using System;
using System.Collections.Generic;
@@ -39,10 +38,12 @@ namespace ColorControl
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly PowerEventDispatcher _powerEventDispatcher;
private readonly ServiceManager _serviceManager;
private readonly IServiceProvider _serviceProvider;
private readonly WinApiAdminService _winApiAdminService;
private readonly WinApiService _winApiService;
private string _dataDir;
private NvPanel _nvPanel;
private NvDitherPanel _nvDitherPanel;
private NotifyIcon _trayIcon;
private bool _initialized = false;
@@ -76,7 +77,8 @@ namespace ColorControl
private Dictionary<int, Action> _shortcuts = new();
private Dictionary<string, Func<UserControl>> _modules = new();
public MainForm(AppContextProvider appContextProvider, PowerEventDispatcher powerEventDispatcher, ServiceManager serviceManager)
public MainForm(AppContextProvider appContextProvider, PowerEventDispatcher powerEventDispatcher, ServiceManager serviceManager,
IServiceProvider serviceProvider, WinApiAdminService winApiAdminService, WinApiService winApiService)
{
InitializeComponent();
@@ -87,6 +89,9 @@ namespace ColorControl
_powerEventDispatcher = powerEventDispatcher;
_serviceManager = serviceManager;
_serviceProvider = serviceProvider;
_winApiAdminService = winApiAdminService;
_winApiService = winApiService;
_dataDir = Program.DataDir;
_config = Program.Config;
@@ -130,17 +135,17 @@ namespace ColorControl
_trayIcon.ContextMenuStrip.Opened += trayIconContextMenu_Popup;
_trayIcon.BalloonTipClicked += trayIconBalloonTip_Clicked;
chkStartAfterLogin.Checked = Utils.TaskExists(Program.TS_TASKNAME);
chkStartAfterLogin.Checked = _winApiService.TaskExists(Program.TS_TASKNAME);
chkFixChromeFonts.Enabled = Utils.IsChromeInstalled();
chkFixChromeFonts.Enabled = _winApiService.IsChromeInstalled();
if (chkFixChromeFonts.Enabled)
{
var fixInstalled = Utils.IsChromeFixInstalled();
var fixInstalled = _winApiService.IsChromeFixInstalled();
if (_config.FixChromeFonts && !fixInstalled)
{
Utils.ExecuteElevated(StartUpParams.ActivateChromeFontFixParam);
_winApiAdminService.InstallChromeFix(true, Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));
}
chkFixChromeFonts.Checked = Utils.IsChromeFixInstalled();
chkFixChromeFonts.Checked = _winApiService.IsChromeFixInstalled();
}
InitShortcut(SHORTCUTID_SCREENSAVER, _config.ScreenSaverShortcut, StartScreenSaver);
@@ -230,12 +235,12 @@ namespace ColorControl
var text = "Use Windows Service";
btnStartStopService.Enabled = true;
if (Utils.IsServiceRunning())
if (_winApiService.IsServiceRunning())
{
text += " (running)";
btnStartStopService.Text = "Stop";
}
else if (Utils.IsServiceInstalled())
else if (_winApiService.IsServiceInstalled())
{
text += " (installed, not running)";
btnStartStopService.Text = "Start";
@@ -256,11 +261,11 @@ namespace ColorControl
{
//throw new Exception("bla");
Logger.Debug("Initializing NVIDIA...");
var appContextProvider = Program.ServiceProvider.GetRequiredService<AppContextProvider>();
_serviceManager.NvService = new NvService(appContextProvider);
var appContextProvider = _serviceProvider.GetRequiredService<AppContextProvider>();
_serviceManager.NvService = _serviceProvider.GetRequiredService<NvService>();
Logger.Debug("Initializing NVIDIA...Done.");
var rpcService = Program.ServiceProvider.GetRequiredService<RpcService>();
var rpcService = _serviceProvider.GetRequiredService<RpcClientService>();
_nvPanel = new NvPanel(_serviceManager.NvService, _trayIcon, Handle, appContextProvider, rpcService);
_nvPanel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
@@ -282,7 +287,7 @@ namespace ColorControl
{
try
{
var appContextProvider = Program.ServiceProvider.GetRequiredService<AppContextProvider>();
var appContextProvider = _serviceProvider.GetRequiredService<AppContextProvider>();
_serviceManager.AmdService = new AmdService(appContextProvider);
_amdPanel = new AmdPanel(_serviceManager.AmdService, _trayIcon, Handle);
@@ -305,7 +310,7 @@ namespace ColorControl
{
try
{
_serviceManager.GameService = Program.ServiceProvider.GetRequiredService<GameService>();
_serviceManager.GameService = _serviceProvider.GetRequiredService<GameService>();
_gamePanel = new GamePanel(_serviceManager.GameService, _serviceManager.NvService, _serviceManager.AmdService, _serviceManager.LgService, _serviceManager.SamsungService, _trayIcon, Handle);
_gamePanel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
@@ -336,7 +341,7 @@ namespace ColorControl
{
try
{
_serviceManager.LgService = Program.ServiceProvider.GetRequiredService<LgService>();
_serviceManager.LgService = _serviceProvider.GetRequiredService<LgService>();
_lgPanel = new LgPanel(_serviceManager.LgService, _serviceManager.NvService, _serviceManager.AmdService, _trayIcon, Handle);
_lgPanel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
@@ -360,7 +365,7 @@ namespace ColorControl
{
try
{
_serviceManager.SamsungService = Program.ServiceProvider.GetRequiredService<SamsungService>();
_serviceManager.SamsungService = _serviceProvider.GetRequiredService<SamsungService>();
//_serviceManager.SamsungService.Init();
@@ -387,7 +392,7 @@ namespace ColorControl
Text = Application.ProductName + " " + Application.ProductVersion;
if (Utils.IsAdministrator())
if (_winApiService.IsAdministrator())
{
Text += " (administrator)";
}
@@ -435,7 +440,7 @@ namespace ColorControl
{
if (_updateHtmlUrl != null)
{
Utils.StartProcess(_updateHtmlUrl);
_winApiAdminService.StartProcess(_updateHtmlUrl);
}
}
@@ -691,7 +696,7 @@ namespace ColorControl
private void CheckElevationMethod()
{
if (Utils.IsAdministrator())
if (_winApiService.IsAdministrator())
{
return;
}
@@ -703,15 +708,15 @@ namespace ColorControl
return;
}
if (_config.ElevationMethod == ElevationMethod.UseService && !Utils.IsServiceInstalled() &&
if (_config.ElevationMethod == ElevationMethod.UseService && !_winApiService.IsServiceInstalled() &&
(MessageForms.QuestionYesNo("The elevation method is set to Windows Service but it is not installed. Do you want to install it now?") == DialogResult.Yes))
{
Utils.InstallService();
_winApiAdminService.InstallService();
}
else if (_config.ElevationMethod == ElevationMethod.UseService && !Utils.IsServiceRunning() &&
else if (_config.ElevationMethod == ElevationMethod.UseService && !_winApiService.IsServiceRunning() &&
(MessageForms.QuestionYesNo("The elevation method is set to Windows Service but it is not running. Do you want to start it now?") == DialogResult.Yes))
{
Utils.StartService();
_winApiAdminService.StartService();
}
return;
@@ -764,7 +769,6 @@ NOTE: installing the service may cause a User Account Control popup.");
{
if (tcMain.SelectedTab == tabInfo)
{
LoadInfo();
}
else if (tcMain.SelectedTab == tabOptions)
{
@@ -786,26 +790,6 @@ NOTE: installing the service may cause a User Account Control popup.");
}
}
if (_serviceManager.NvService != null)
{
if (_nvDitherPanel == null)
{
_nvDitherPanel = new NvDitherPanel(_serviceManager.NvService);
tabOptions.Controls.Add(_nvDitherPanel);
_nvDitherPanel.Top = grpGeneralOptions.Top;
_nvDitherPanel.Left = grpGeneralOptions.Left + grpGeneralOptions.Width + 4;
_nvDitherPanel.Width = tabOptions.Width - _nvDitherPanel.Left - 4;
_nvDitherPanel.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
}
else
{
_nvDitherPanel.UpdateInfo();
}
}
_initialized = false;
try
{
@@ -944,24 +928,8 @@ NOTE: installing the service may cause a User Account Control popup.");
await _samsungPanel?.ApplyPreset(preset);
}
private void LoadInfo()
{
grpNVIDIAInfo.Visible = _serviceManager.NvService != null;
}
private void btnRefreshNVIDIAInfo_Click(object sender, EventArgs e)
{
if (_serviceManager.NvService != null)
{
tvNVIDIAInfo.Nodes.Clear();
var displays = Display.GetDisplays();
for (var i = 0; i < displays.Length; i++)
{
var display = displays[i];
var node = TreeNodeBuilder.CreateTree(display, $"Display[{i}]");
tvNVIDIAInfo.Nodes.Add(node);
}
}
}
private void btnSetShortcutScreenSaver_Click(object sender, EventArgs e)
@@ -1063,7 +1031,7 @@ NOTE: installing the service may cause a User Account Control popup.");
{
_updateHtmlUrl = latest.html_url.Value;
if (latest.assets != null && Utils.IsServiceRunning())
if (latest.assets != null && _winApiService.IsServiceRunning())
{
var asset = latest.assets[0];
_downloadUrl = asset.browser_download_url.Value;
@@ -1196,8 +1164,6 @@ NOTE: installing the service may cause a User Account Control popup.");
{
_config.ElevationMethod = elevationMethod;
Utils.UseDedicatedElevatedProcess = _config.ElevationMethod == ElevationMethod.UseElevatedProcess;
var _ = _config.ElevationMethod switch
{
ElevationMethod.None => SetElevationMethodNone(),
@@ -1217,7 +1183,7 @@ NOTE: installing the service may cause a User Account Control popup.");
RegisterScheduledTask();
}
Utils.UninstallService();
_winApiAdminService.UninstallService();
return true;
}
@@ -1230,16 +1196,16 @@ NOTE: installing the service may cause a User Account Control popup.");
RegisterScheduledTask();
}
Utils.UninstallService();
_winApiAdminService.UninstallService();
return true;
}
private bool SetElevationMethodUseService()
{
Utils.InstallService();
_winApiAdminService.InstallService();
if (Utils.IsServiceInstalled())
if (_winApiService.IsServiceInstalled())
{
MessageForms.InfoOk("Service installed successfully.");
return true;
@@ -1257,14 +1223,14 @@ NOTE: installing the service may cause a User Account Control popup.");
RegisterScheduledTask();
}
Utils.UninstallService();
_winApiAdminService.UninstallService();
return true;
}
private void RegisterScheduledTask(bool enabled = true)
{
Utils.RegisterTask(Program.TS_TASKNAME, enabled, _config.ElevationMethod == ElevationMethod.RunAsAdmin ? Microsoft.Win32.TaskScheduler.TaskRunLevel.Highest : Microsoft.Win32.TaskScheduler.TaskRunLevel.LUA);
_winApiAdminService.RegisterTask(Program.TS_TASKNAME, enabled, _config.ElevationMethod == ElevationMethod.RunAsAdmin ? Microsoft.Win32.TaskScheduler.TaskRunLevel.Highest : Microsoft.Win32.TaskScheduler.TaskRunLevel.LUA);
}
private void btnElevationInfo_Click(object sender, EventArgs e)
@@ -1273,7 +1239,7 @@ NOTE: installing the service may cause a User Account Control popup.");
NOTE: if ColorControl itself already runs as administrator this is indicated in the title: ColorControl {Application.ProductVersion} (administrator).
Currently ColorControl is {(Utils.IsAdministrator() ? "" : "not ")}running as administrator.
Currently ColorControl is {(_winApiService.IsAdministrator() ? "" : "not ")}running as administrator.
");
}
@@ -1286,11 +1252,11 @@ Currently ColorControl is {(Utils.IsAdministrator() ? "" : "not ")}running as ad
if (start)
{
Utils.StartService();
_winApiAdminService.StartService();
}
else
{
Utils.StopService();
_winApiAdminService.StopService();
}
var wait = 1500;
@@ -1299,7 +1265,7 @@ Currently ColorControl is {(Utils.IsAdministrator() ? "" : "not ")}running as ad
{
await Task.Delay(100);
if (start == Utils.IsServiceRunning())
if (start == _winApiService.IsServiceRunning())
{
break;
}
@@ -1376,11 +1342,9 @@ Currently ColorControl is {(Utils.IsAdministrator() ? "" : "not ")}running as ad
{
_config.FixChromeFonts = chkFixChromeFonts.Checked;
var param = chkFixChromeFonts.Checked ? StartUpParams.ActivateChromeFontFixParam : StartUpParams.DeactivateChromeFontFixParam;
var folder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
Utils.ExecuteElevated($"{param} {folder}");
_winApiAdminService.InstallChromeFix(chkFixChromeFonts.Checked, folder);
}
}
+53 -24
View File
@@ -1,13 +1,16 @@
using ColorControl.Services.Common;
using ColorControl.Forms;
using ColorControl.Services.Common;
using ColorControl.Services.EventDispatcher;
using ColorControl.Services.GameLauncher;
using ColorControl.Services.LG;
using ColorControl.Services.NVIDIA;
using ColorControl.Services.Samsung;
using ColorControl.Shared.Common;
using ColorControl.Shared.Contracts;
using ColorControl.Shared.Native;
using ColorControl.Shared.Services;
using ColorControl.Svc;
using ColorControl.XForms;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
@@ -31,7 +34,7 @@ namespace ColorControl
public static string ConfigFilename { get; private set; }
public static string LogFilename { get; private set; }
public static Config Config { get; private set; }
public static Shared.Common.AppContext AppContext { get; private set; }
public static GlobalContext AppContext { get; private set; }
public static bool IsRestarting { get; private set; }
public static bool UserExit = false;
@@ -59,27 +62,23 @@ namespace ColorControl
//Utils.UpdateFiles(@"H:\temp\ColorControl\ColorControl", @"C:\Users\vinni\source\repos\ColorControl\ColorControl\bin\Debug\net6.0-windows10.0.20348.0");
//Utils.UnZipFile(@"H:\temp\ColorControl\ColorControl.zip", @"H:\temp\ColorControl\temp");
var runAsService = args.Contains("--service") || Utils.IsAdministrator() && Process.GetCurrentProcess().Parent()?.ProcessName?.Equals("services", StringComparison.InvariantCultureIgnoreCase) == true;
var runAsService = args.Contains("--service") || WinApiService.IsAdministratorStatic() && Process.GetCurrentProcess().Parent()?.ProcessName?.Equals("services", StringComparison.InvariantCultureIgnoreCase) == true;
var runElevated = args.Contains("--elevated");
InitLogger(runAsService);
InitLogger(runAsService, runElevated);
Logger.Debug($"Using data path: {DataDir}");
//Logger.Debug("Parent process: " + Process.GetCurrentProcess().Parent()?.ProcessName);
var host = CreateHostBuilder().Build();
ServiceProvider = host.Services;
var appContextProvider = ServiceProvider.GetRequiredService<AppContextProvider>();
if (runAsService)
{
AppContext = new Shared.Common.AppContext(null, new StartUpParams(), DataDir, _loggingRule);
appContextProvider.SetAppContext(AppContext);
await RunService(args);
return;
}
var host = CreateHostBuilder().Build();
ServiceProvider = host.Services;
var mutexId = $"Global\\{typeof(MainForm).GUID}";
var currentDomain = AppDomain.CurrentDomain;
@@ -90,16 +89,17 @@ namespace ColorControl
LoadConfig();
var appContextProvider = ServiceProvider.GetRequiredService<AppContextProvider>();
var startUpParams = StartUpParams.Parse(args);
AppContext = new GlobalContext(Config, startUpParams, DataDir, _loggingRule, mutexId);
appContextProvider.SetAppContext(AppContext);
if (Config.UseGdiScaling)
{
Application.SetHighDpiMode(HighDpiMode.DpiUnawareGdiScaled);
}
var startUpParams = StartUpParams.Parse(args);
AppContext = new Shared.Common.AppContext(Config, startUpParams, DataDir, _loggingRule, mutexId);
appContextProvider.SetAppContext(AppContext);
var existingProcess = Utils.GetProcessByName("ColorControl");
try
@@ -145,12 +145,26 @@ namespace ColorControl
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if (Debugger.IsAttached)
{
var winApiService = ServiceProvider.GetRequiredService<WinApiService>();
if (winApiService.IsAdministrator())
{
var backgroundService = ServiceProvider.GetRequiredService<ColorControlBackgroundService>();
backgroundService.PipeName = PipeUtils.ElevatedPipe;
Task.Run(async () => await backgroundService.StartAsync(CancellationToken.None));
}
}
_mainForm = ServiceProvider.GetRequiredService<MainForm>();
Application.Run(_mainForm);
if (Debugger.IsAttached && !IsRestarting)
{
Utils.StopService();
var winApiAdminService = ServiceProvider.GetRequiredService<WinApiAdminService>();
winApiAdminService.StopService();
}
}
catch (Exception ex)
@@ -181,12 +195,12 @@ namespace ColorControl
Environment.Exit(0);
}
private static void InitLogger(bool runAsService)
private static void InitLogger(bool runAsService, bool runElevated)
{
var config = new LoggingConfiguration();
// Targets where to log to: File and Console
var logFileAppendix = runAsService ? "_svc" : "";
var logFileAppendix = runAsService ? "_svc" : runElevated ? "_elevated" : "";
LogFilename = Path.Combine(DataDir, $"LogFile{logFileAppendix}.txt");
@@ -220,8 +234,6 @@ namespace ColorControl
}
Config ??= new Config();
Utils.UseDedicatedElevatedProcess = Config.UseDedicatedElevatedProcess;
var minLogLevel = LogLevel.FromString(Config.LogLevel);
if (minLogLevel != LogLevel.Trace)
@@ -245,9 +257,9 @@ namespace ColorControl
services.AddSingleton<PowerEventDispatcher>();
services.AddSingleton<ProcessEventDispatcher>();
services.AddSingleton<MainForm>();
services.AddSingleton<ServiceManager>();
services.AddSingleton<ElevatedForm>();
services.AddSingleton<LogWindow>();
services.AddSingleton<RestartDetector>();
services.AddTransient<RpcService>();
});
}
private static async Task RunService(string[] args)
@@ -266,6 +278,12 @@ namespace ColorControl
})
.Build();
ServiceProvider = host.Services;
var appContextProvider = ServiceProvider.GetRequiredService<AppContextProvider>();
AppContext = new GlobalContext(null, new StartUpParams(), DataDir, _loggingRule);
appContextProvider.SetAppContext(AppContext);
await host.RunAsync();
}
@@ -273,6 +291,17 @@ namespace ColorControl
{
services.AddSingleton<AppContextProvider>();
services.AddSingleton<SessionSwitchDispatcher>();
services.AddSingleton<WinApiAdminService>();
services.AddSingleton<WinApiService>();
services.AddSingleton<WinElevatedProcessManager>();
services.AddTransient<RpcClientService>();
services.AddTransient<RpcServerService>();
services.AddSingleton<NvService>();
services.AddSingleton<WolService>();
services.AddSingleton<ColorControlBackgroundService>();
services.AddSingleton<ServiceManager>();
RpcServerService.ServiceTypes.Add(typeof(NvService));
}
public static int EnumThreadWindows(IntPtr handle, IntPtr param)
+2 -2
View File
@@ -30,7 +30,7 @@ namespace ColorControl.Services.AMD
_trayIcon = trayIcon;
_mainHandle = handle;
_config = Shared.Common.AppContext.CurrentContext.Config;
_config = Shared.Common.GlobalContext.CurrentContext.Config;
InitializeComponent();
@@ -127,7 +127,7 @@ namespace ColorControl.Services.AMD
private async Task ApplyAmdPresetOnStartup(int attempts = 5)
{
var startUpParams = Shared.Common.AppContext.CurrentContext.StartUpParams;
var startUpParams = Shared.Common.GlobalContext.CurrentContext.StartUpParams;
var presetIdOrName = !string.IsNullOrEmpty(startUpParams.AmdPresetIdOrName) ? startUpParams.AmdPresetIdOrName : _config.AmdPresetId_ApplyOnStartup.ToString();
if (!string.IsNullOrEmpty(presetIdOrName))
+58 -52
View File
@@ -3,70 +3,76 @@ using ColorControl.Services.GameLauncher;
using ColorControl.Services.LG;
using ColorControl.Services.NVIDIA;
using ColorControl.Services.Samsung;
using ColorControl.Shared.Common;
using ColorControl.Shared.Services;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace ColorControl.Services.Common
namespace ColorControl.Services.Common;
public class ServiceManager
{
public class ServiceManager
private readonly WinApiAdminService _winApiAdminService;
internal NvService NvService { get; set; }
internal LgService LgService { get; set; }
internal AmdService AmdService { get; set; }
internal GameService GameService { get; set; }
internal SamsungService SamsungService { get; set; }
public ServiceManager(WinApiAdminService winApiAdminService)
{
internal NvService NvService { get; set; }
internal LgService LgService { get; set; }
internal AmdService AmdService { get; set; }
internal GameService GameService { get; set; }
internal SamsungService SamsungService { get; set; }
_winApiAdminService = winApiAdminService;
}
public async Task<bool> HandleExternalServiceAsync(string serviceName, string[] parameters)
public async Task<bool> HandleExternalServiceAsync(string serviceName, string[] parameters)
{
if (string.IsNullOrEmpty(serviceName) || parameters.Length == 0)
{
if (string.IsNullOrEmpty(serviceName) || parameters.Length == 0)
{
return false;
}
if (NvService != null && serviceName.Equals("NvPreset", StringComparison.OrdinalIgnoreCase))
{
return await NvService.ApplyPreset(parameters[0]);
}
if (NvService != null && serviceName.Equals("GsyncEnabled", StringComparison.OrdinalIgnoreCase))
{
return NvService.IsGsyncEnabled();
}
if (AmdService != null && serviceName.Equals("AmdPreset", StringComparison.OrdinalIgnoreCase))
{
return await AmdService.ApplyPreset(parameters[0]);
}
if (LgService != null && serviceName.Equals("LgPreset", StringComparison.OrdinalIgnoreCase))
{
await LgService.ApplyPreset(parameters[0]);
return true;
}
if (SamsungService != null && serviceName.Equals("SamsungPreset", StringComparison.OrdinalIgnoreCase))
{
await SamsungService.ApplyPreset(parameters[0]);
return true;
}
if (serviceName.Equals("StartProgram", StringComparison.OrdinalIgnoreCase))
{
Utils.StartProcess(parameters[0], parameters.Length > 1 ? string.Join(" ", parameters.Skip(1)) : null, setWorkingDir: true);
return true;
}
return false;
}
public void Save()
if (NvService != null && serviceName.Equals("NvPreset", StringComparison.OrdinalIgnoreCase))
{
NvService?.GlobalSave();
AmdService?.GlobalSave();
LgService?.GlobalSave();
GameService?.GlobalSave();
SamsungService?.GlobalSave();
return await NvService.ApplyPreset(parameters[0]);
}
if (NvService != null && serviceName.Equals("GsyncEnabled", StringComparison.OrdinalIgnoreCase))
{
return NvService.IsGsyncEnabled();
}
if (AmdService != null && serviceName.Equals("AmdPreset", StringComparison.OrdinalIgnoreCase))
{
return await AmdService.ApplyPreset(parameters[0]);
}
if (LgService != null && serviceName.Equals("LgPreset", StringComparison.OrdinalIgnoreCase))
{
await LgService.ApplyPreset(parameters[0]);
return true;
}
if (SamsungService != null && serviceName.Equals("SamsungPreset", StringComparison.OrdinalIgnoreCase))
{
await SamsungService.ApplyPreset(parameters[0]);
return true;
}
if (serviceName.Equals("StartProgram", StringComparison.OrdinalIgnoreCase))
{
_winApiAdminService.StartProcess(parameters[0], parameters.Length > 1 ? string.Join(" ", parameters.Skip(1)) : null, setWorkingDir: true);
return true;
}
return false;
}
public void Save()
{
NvService?.GlobalSave();
AmdService?.GlobalSave();
LgService?.GlobalSave();
GameService?.GlobalSave();
SamsungService?.GlobalSave();
}
}
@@ -16,6 +16,10 @@ public class EventDispatcher<T> where T : EventArgs
{
eventHandlers.Add(eventName, eventHandler);
}
else
{
eventHandlers[eventName] += eventHandler;
}
}
public void RegisterAsyncEventHandler(string eventName, AsyncEventHandler<T> eventHandler)
@@ -24,6 +28,10 @@ public class EventDispatcher<T> where T : EventArgs
{
asyncEventHandlers.Add(eventName, eventHandler);
}
else
{
asyncEventHandlers[eventName] += eventHandler;
}
}
public void UnregisterEventHandler(string eventName)
@@ -28,10 +28,10 @@ namespace ColorControl.Services.EventDispatcher
{
public const string Event_ProcessChanged = "ProcessChanged";
public bool IsRunning { get; set; }
public ProcessChangedEventArgs MonitorContext { get; private set; }
protected static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
private ProcessChangedEventArgs MonitorContext { get; set; }
private AppContextProvider _appContextProvider { get; }
public ProcessEventDispatcher(AppContextProvider appContextProvider)
@@ -88,6 +88,8 @@ namespace ColorControl.Services.EventDispatcher
{
var processes = Process.GetProcesses();
context.StartedProcesses = processes.Where(p => context.RunningProcesses?.Any(rp => rp.Id == p.Id) == false).ToList();
context.StoppedProcesses = context.RunningProcesses?.Where(p => processes.Any(rp => rp.Id == p.Id) == false).ToList();
context.RunningProcesses = processes;
context.IsNotificationDisabled = FormUtils.IsNotificationDisabled();
+37 -18
View File
@@ -34,6 +34,7 @@
mnuGameOptions = new System.Windows.Forms.ContextMenuStrip(components);
miGameProcessorAffinity = new System.Windows.Forms.ToolStripMenuItem();
miGameProcessPriority = new System.Windows.Forms.ToolStripMenuItem();
miPresetNVIDIAProfileInspector = new System.Windows.Forms.ToolStripMenuItem();
chkGameQuickAccess = new System.Windows.Forms.CheckBox();
btnGameSettings = new System.Windows.Forms.Button();
mnuGameActions = new System.Windows.Forms.ContextMenuStrip(components);
@@ -51,6 +52,7 @@
mnuGameNvidiaPresets = new System.Windows.Forms.ToolStripMenuItem();
mnuGameAmdPresets = new System.Windows.Forms.ToolStripMenuItem();
mnuGameLgPresets = new System.Windows.Forms.ToolStripMenuItem();
mnuGameSamsungPresets = new System.Windows.Forms.ToolStripMenuItem();
mnuGameStartProgram = new System.Windows.Forms.ToolStripMenuItem();
label4 = new System.Windows.Forms.Label();
edtGameName = new System.Windows.Forms.TextBox();
@@ -60,7 +62,7 @@
btnGameAdd = new System.Windows.Forms.Button();
btnGameLaunch = new System.Windows.Forms.Button();
lvGamePresets = new System.Windows.Forms.ListView();
mnuGameSamsungPresets = new System.Windows.Forms.ToolStripMenuItem();
miGameOptionsAutoApplySettings = new System.Windows.Forms.ToolStripMenuItem();
mnuGameOptions.SuspendLayout();
mnuGameActions.SuspendLayout();
mnuGameAddStep.SuspendLayout();
@@ -96,24 +98,31 @@
// mnuGameOptions
//
mnuGameOptions.ImageScalingSize = new System.Drawing.Size(20, 20);
mnuGameOptions.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { miGameProcessorAffinity, miGameProcessPriority });
mnuGameOptions.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { miGameProcessorAffinity, miGameProcessPriority, miPresetNVIDIAProfileInspector, miGameOptionsAutoApplySettings });
mnuGameOptions.Name = "mnuLgButtons";
mnuGameOptions.Size = new System.Drawing.Size(166, 48);
mnuGameOptions.Size = new System.Drawing.Size(202, 114);
//
// miGameProcessorAffinity
//
miGameProcessorAffinity.Name = "miGameProcessorAffinity";
miGameProcessorAffinity.Size = new System.Drawing.Size(165, 22);
miGameProcessorAffinity.Size = new System.Drawing.Size(201, 22);
miGameProcessorAffinity.Text = "Processor affinity";
miGameProcessorAffinity.Click += btnGameProcessAffinity_Click;
//
// miGameProcessPriority
//
miGameProcessPriority.Name = "miGameProcessPriority";
miGameProcessPriority.Size = new System.Drawing.Size(165, 22);
miGameProcessPriority.Size = new System.Drawing.Size(201, 22);
miGameProcessPriority.Text = "Process priority";
miGameProcessPriority.Click += miGameProcessPriority_Click;
//
// miPresetNVIDIAProfileInspector
//
miPresetNVIDIAProfileInspector.Name = "miPresetNVIDIAProfileInspector";
miPresetNVIDIAProfileInspector.Size = new System.Drawing.Size(201, 22);
miPresetNVIDIAProfileInspector.Text = "NVIDIA Profile Inspector";
miPresetNVIDIAProfileInspector.Click += miPresetNVIDIAProfileInspector_Click;
//
// chkGameQuickAccess
//
chkGameQuickAccess.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left;
@@ -145,21 +154,21 @@
mnuGameActions.ImageScalingSize = new System.Drawing.Size(20, 20);
mnuGameActions.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { mnuGameNvInspector, miGameSetQuickAccessShortcut });
mnuGameActions.Name = "mnuLgButtons";
mnuGameActions.Size = new System.Drawing.Size(212, 48);
mnuGameActions.Size = new System.Drawing.Size(202, 48);
mnuGameActions.Opening += mnuGameActions_Opening;
//
// mnuGameNvInspector
//
mnuGameNvInspector.Name = "mnuGameNvInspector";
mnuGameNvInspector.Size = new System.Drawing.Size(211, 22);
mnuGameNvInspector.Size = new System.Drawing.Size(201, 22);
mnuGameNvInspector.Text = "NVIDIA Profile Inspector";
mnuGameNvInspector.Click += mnuGameNvInspector_Click;
//
// miGameSetQuickAccessShortcut
//
miGameSetQuickAccessShortcut.Name = "miGameSetQuickAccessShortcut";
miGameSetQuickAccessShortcut.Size = new System.Drawing.Size(211, 22);
miGameSetQuickAccessShortcut.Text = "Set Quick Access Shortcut";
miGameSetQuickAccessShortcut.Size = new System.Drawing.Size(201, 22);
miGameSetQuickAccessShortcut.Text = "Settings...";
miGameSetQuickAccessShortcut.Click += miGameSetQuickAccessShortcut_Click;
//
// chkGameRunAsAdmin
@@ -261,31 +270,37 @@
mnuGameAddStep.ImageScalingSize = new System.Drawing.Size(20, 20);
mnuGameAddStep.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { mnuGameNvidiaPresets, mnuGameAmdPresets, mnuGameLgPresets, mnuGameSamsungPresets, mnuGameStartProgram });
mnuGameAddStep.Name = "mnuLgButtons";
mnuGameAddStep.Size = new System.Drawing.Size(181, 136);
mnuGameAddStep.Size = new System.Drawing.Size(164, 114);
mnuGameAddStep.Opening += mnuGameAddStep_Opening;
//
// mnuGameNvidiaPresets
//
mnuGameNvidiaPresets.Name = "mnuGameNvidiaPresets";
mnuGameNvidiaPresets.Size = new System.Drawing.Size(180, 22);
mnuGameNvidiaPresets.Size = new System.Drawing.Size(163, 22);
mnuGameNvidiaPresets.Text = "NVIDIA presets";
//
// mnuGameAmdPresets
//
mnuGameAmdPresets.Name = "mnuGameAmdPresets";
mnuGameAmdPresets.Size = new System.Drawing.Size(180, 22);
mnuGameAmdPresets.Size = new System.Drawing.Size(163, 22);
mnuGameAmdPresets.Text = "AMD presets";
//
// mnuGameLgPresets
//
mnuGameLgPresets.Name = "mnuGameLgPresets";
mnuGameLgPresets.Size = new System.Drawing.Size(180, 22);
mnuGameLgPresets.Size = new System.Drawing.Size(163, 22);
mnuGameLgPresets.Text = "LG presets";
//
// mnuGameSamsungPresets
//
mnuGameSamsungPresets.Name = "mnuGameSamsungPresets";
mnuGameSamsungPresets.Size = new System.Drawing.Size(163, 22);
mnuGameSamsungPresets.Text = "Samsung presets";
//
// mnuGameStartProgram
//
mnuGameStartProgram.Name = "mnuGameStartProgram";
mnuGameStartProgram.Size = new System.Drawing.Size(180, 22);
mnuGameStartProgram.Size = new System.Drawing.Size(163, 22);
mnuGameStartProgram.Text = "Start Program";
mnuGameStartProgram.Click += mnuGameStartProgram_Click;
//
@@ -379,6 +394,7 @@
lvGamePresets.AllowDrop = true;
lvGamePresets.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
lvGamePresets.CheckBoxes = true;
lvGamePresets.ContextMenuStrip = mnuGameOptions;
lvGamePresets.FullRowSelect = true;
lvGamePresets.Location = new System.Drawing.Point(8, 8);
lvGamePresets.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
@@ -396,11 +412,12 @@
lvGamePresets.DragEnter += lvGamePresets_DragEnter;
lvGamePresets.DoubleClick += lvGamePresets_DoubleClick;
//
// mnuGameSamsungPresets
// miGameOptionsAutoApplySettings
//
mnuGameSamsungPresets.Name = "mnuGameSamsungPresets";
mnuGameSamsungPresets.Size = new System.Drawing.Size(180, 22);
mnuGameSamsungPresets.Text = "Samsung presets";
miGameOptionsAutoApplySettings.Name = "miGameOptionsAutoApplySettings";
miGameOptionsAutoApplySettings.Size = new System.Drawing.Size(201, 22);
miGameOptionsAutoApplySettings.Text = "Auto apply settings...";
miGameOptionsAutoApplySettings.Click += miGameOptionsAutoApplySettings_Click;
//
// GamePanel
//
@@ -470,5 +487,7 @@
private System.Windows.Forms.ToolStripMenuItem miGameProcessPriority;
private System.Windows.Forms.ComboBox cbxGameStepType;
private System.Windows.Forms.ToolStripMenuItem mnuGameSamsungPresets;
private System.Windows.Forms.ToolStripMenuItem miPresetNVIDIAProfileInspector;
private System.Windows.Forms.ToolStripMenuItem miGameOptionsAutoApplySettings;
}
}
@@ -43,7 +43,7 @@ namespace ColorControl.Services.GameLauncher
_amdService = amdService;
_lgService = lgService;
_samsungService = samsungService;
_config = Shared.Common.AppContext.CurrentContext.Config;
_config = Shared.Common.GlobalContext.CurrentContext.Config;
InitializeComponent();
@@ -139,7 +139,7 @@ namespace ColorControl.Services.GameLauncher
var preset = GetSelectedGamePreset();
var enabled = preset != null;
FormUtils.EnableControls(this, enabled, new List<Control> { lvGamePresets, btnGameAdd });
FormUtils.EnableControls(this, enabled, new List<Control> { lvGamePresets, btnGameAdd, btnGameSettings });
if (preset != null)
{
@@ -361,16 +361,44 @@ namespace ColorControl.Services.GameLauncher
private void miGameSetQuickAccessShortcut_Click(object sender, EventArgs e)
{
var shortcut = FormUtils.EditShortcut(_config.GameQuickAccessShortcut);
EditGameSettings();
}
if (shortcut == null)
private void EditGameSettings()
{
var quickAccessField = new FieldDefinition
{
Label = "Quick Access shortcut",
FieldType = FieldType.Shortcut,
Value = _config.GameQuickAccessShortcut
};
var applyExternallyLaunched = new FieldDefinition
{
Label = "Apply presets when launching games externally",
SubLabel = "This will monitor processes and automatically apply the preset whenever a known game is launched",
FieldType = FieldType.CheckBox,
Value = _gameService.Config.ApplyExternallyLaunched
};
var values = MessageForms.ShowDialog("Game launcher settings", new[] {
quickAccessField,
applyExternallyLaunched
});
if (!values.Any())
{
return;
}
var shortcut = (string)quickAccessField.Value;
_config.GameQuickAccessShortcut = shortcut;
KeyboardShortcutManager.RegisterShortcut(SHORTCUTID_GAMEQA, _config.GameQuickAccessShortcut);
_gameService.Config.ApplyExternallyLaunched = applyExternallyLaunched.ValueAsBool;
UpdateInfo();
}
private void mnuGameActions_Opening(object sender, CancelEventArgs e)
@@ -490,5 +518,52 @@ namespace ColorControl.Services.GameLauncher
{
FormUtils.ListViewSort(sender, e);
}
private void miPresetNVIDIAProfileInspector_Click(object sender, EventArgs e)
{
var form = new frmDrvSettings();
form.Show();
var preset = GetSelectedGamePreset();
var executable = Path.GetFileName(preset.Path);
form.SetProfileByExecutable(executable);
}
private void miGameOptionsAutoApplySettings_Click(object sender, EventArgs e)
{
var preset = GetSelectedGamePreset();
var allowAutoApplyField = new FieldDefinition
{
Label = "Allow this preset to be automatically executed when the process starts",
FieldType = FieldType.CheckBox,
Value = preset.AutoSettings.AllowAutoApply
};
var processActions = new[] { ProcessAutoAction.None, ProcessAutoAction.Suspend }.Select(t => Utils.GetDescription(t));
var processActionField = new FieldDefinition
{
Label = "Optional action to perform directly after the process starts",
SubLabel = "Temporarily suspending the process may help when enabling/disabling HDR or other settings",
FieldType = FieldType.DropDown,
Values = processActions,
Value = preset.AutoSettings.ProcessAutoAction
};
var values = MessageForms.ShowDialog("Auto apply settings", new[] {
allowAutoApplyField,
processActionField
});
if (!values.Any())
{
return;
}
preset.AutoSettings.AllowAutoApply = allowAutoApplyField.ValueAsBool;
preset.AutoSettings.ProcessAutoAction = processActionField.ValueAsEnum<ProcessAutoAction>();
}
}
}
@@ -18,7 +18,7 @@
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing"">Blue</data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
@@ -26,6 +26,19 @@ namespace ColorControl.Services.GameLauncher
RealTime = NativeConstants.REALTIME_PRIORITY_CLASS
}
public enum ProcessAutoAction
{
None = 0,
Suspend = 1,
Restart = 2
}
class AutoSettings
{
public bool AllowAutoApply { get; set; }
public ProcessAutoAction ProcessAutoAction { get; set; }
}
class GamePreset : PresetBase
{
public string Path { get; set; }
@@ -36,12 +49,14 @@ namespace ColorControl.Services.GameLauncher
public List<string> FinalizeSteps { get; set; }
public uint ProcessAffinityMask { get; set; }
public uint ProcessPriorityClass { get; set; }
public AutoSettings AutoSettings { get; set; }
public GamePreset() : base()
{
PreLaunchSteps = new List<string>();
PostLaunchSteps = new List<string>();
FinalizeSteps = new List<string>();
AutoSettings = new AutoSettings();
}
public GamePreset(GamePreset preset) : this()
@@ -73,15 +88,16 @@ namespace ColorControl.Services.GameLauncher
public override List<string> GetDisplayValues(Config config = null)
{
var values = new List<string>();
var values = new List<string>
{
name,
Path,
Parameters,
values.Add(name);
values.Add(Path);
values.Add(Parameters);
values.Add(string.Join(", ", PreLaunchSteps));
values.Add(string.Join(", ", PostLaunchSteps));
values.Add(string.Join(", ", FinalizeSteps));
string.Join(", ", PreLaunchSteps),
string.Join(", ", PostLaunchSteps),
string.Join(", ", FinalizeSteps)
};
return values;
}
+156 -12
View File
@@ -1,27 +1,120 @@
using ColorControl.Services.Common;
using ColorControl.Services.EventDispatcher;
using ColorControl.Shared.Common;
using ColorControl.Shared.Services;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace ColorControl.Services.GameLauncher
{
class GameService : ServiceBase<GamePreset>
{
//private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
public override string ServiceName => "Game";
protected override string PresetsBaseFilename => "GamePresets.json";
private ProcessEventDispatcher _processEventDispatcher;
private readonly WinApiAdminService _winApiAdminService;
private readonly WinApiService _winApiService;
private ServiceManager _serviceManager;
private int _lastStartedProcessId;
private System.DateTime _lastStartedPresetDateTime = System.DateTime.MinValue;
private string _lastStartedProcessPath;
private string _configFilename;
public GameService(AppContextProvider appContextProvider, ServiceManager serviceManager) : base(appContextProvider)
public GameServiceConfig Config { get; private set; }
public GameService(AppContextProvider appContextProvider, ServiceManager serviceManager, ProcessEventDispatcher processEventDispatcher, WinApiAdminService winApiAdminService, WinApiService winApiService) : base(appContextProvider)
{
LoadConfig();
LoadPresets();
_serviceManager = serviceManager;
_processEventDispatcher = processEventDispatcher;
_winApiAdminService = winApiAdminService;
_winApiService = winApiService;
_processEventDispatcher.RegisterAsyncEventHandler(ProcessEventDispatcher.Event_ProcessChanged, ProcessChanged);
}
private async Task ProcessChanged(object sender, ProcessChangedEventArgs e, CancellationToken token)
{
if (e.StartedProcesses?.Any() != true || !Config.ApplyExternallyLaunched)
{
return;
}
if (_lastStartedPresetDateTime > System.DateTime.Now.AddSeconds(-5))
{
return;
}
_lastStartedProcessId = 0;
var startedProcesses = e.StartedProcesses;
foreach (var startedProcess in startedProcesses)
{
try
{
if (await HandleStartedProcess(startedProcess))
{
return;
}
}
catch (System.Exception) { }
}
}
private async Task<bool> HandleStartedProcess(Process process)
{
GamePreset preset;
if (_winApiService.IsAdministrator())
{
var fileName = process.MainModule.FileName;
preset = _presets.FirstOrDefault(p => fileName.Contains(Path.GetDirectoryName(p.Path), System.StringComparison.OrdinalIgnoreCase));
}
else
{
var name = process.ProcessName.Replace("-Win64-Shipping", "");
preset = _presets.FirstOrDefault(p => Path.GetFileName(p.Path).Contains(name, System.StringComparison.OrdinalIgnoreCase));
}
if (preset == null || !preset.AutoSettings.AllowAutoApply)
{
return false;
}
if (_lastStartedProcessId != process.Id)
{
Logger.Debug($"Auto-starting preset {preset.name} for process {process.ProcessName}");
var mainThreadId = 0;
var suspended = false;
if (preset.AutoSettings.ProcessAutoAction == ProcessAutoAction.Suspend)
{
mainThreadId = _winApiAdminService.SuspendMainThread(process.Id);
suspended = true;
}
else if (preset.AutoSettings.ProcessAutoAction == ProcessAutoAction.Restart)
{
_winApiAdminService.StopProcess(process.Id);
process = null;
}
var _ = ExecutePreset(preset, process, suspended ? mainThreadId : 0);
return true;
}
return false;
}
protected override List<GamePreset> GetDefaultPresets()
@@ -37,6 +130,7 @@ namespace ColorControl.Services.GameLauncher
public void GlobalSave()
{
SavePresets();
SaveConfig();
}
public async Task<bool> ApplyPreset(string idOrName)
@@ -57,17 +151,34 @@ namespace ColorControl.Services.GameLauncher
return await ApplyPreset(preset, Program.AppContext);
}
public async Task<bool> ApplyPreset(GamePreset preset, AppContext appContext)
public async Task<bool> ApplyPreset(GamePreset preset, GlobalContext _)
{
var result = await ExecutePreset(preset);
_lastAppliedPreset = preset;
PresetApplied();
return result;
}
private async Task<bool> ExecutePreset(GamePreset preset, Process process = null, int resumeThreadId = default)
{
var result = true;
await ExecuteSteps(preset.PreLaunchSteps);
Process process = null;
if (!string.IsNullOrEmpty(preset.Path))
if (process == null && !string.IsNullOrEmpty(preset.Path))
{
process = Utils.StartProcess(preset.Path, preset.Parameters, setWorkingDir: true, elevate: preset.RunAsAdministrator, affinityMask: preset.ProcessAffinityMask, priorityClass: preset.ProcessPriorityClass);
process = _winApiAdminService.StartProcess(preset.Path, preset.Parameters, setWorkingDir: true, elevate: preset.RunAsAdministrator, affinityMask: preset.ProcessAffinityMask, priorityClass: preset.ProcessPriorityClass);
_lastStartedPresetDateTime = System.DateTime.Now;
_lastStartedProcessId = process.Id;
_lastStartedProcessPath = Path.GetDirectoryName(preset.Path);
}
else if (resumeThreadId != default)
{
_winApiAdminService.ResumeThread((uint)resumeThreadId);
}
await ExecuteSteps(preset.PostLaunchSteps);
@@ -77,16 +188,27 @@ namespace ColorControl.Services.GameLauncher
await ExecuteFinalizationStepsAsync(process, preset.FinalizeSteps);
}
_lastAppliedPreset = preset;
PresetApplied();
return result;
}
private async Task ExecuteFinalizationStepsAsync(Process process, List<string> finalizeSteps)
{
await process.WaitForExitAsync();
await Task.Delay(1000);
try
{
if (process.HasExited)
{
return;
}
await process.WaitForExitAsync();
}
catch (Exception ex)
{
Logger.Error(ex);
return;
}
await ExecuteSteps(finalizeSteps);
}
@@ -140,5 +262,27 @@ namespace ColorControl.Services.GameLauncher
}
}
private void LoadConfig()
{
_configFilename = Path.Combine(_dataPath, "GameConfig.json");
try
{
if (File.Exists(_configFilename))
{
Config = JsonConvert.DeserializeObject<GameServiceConfig>(File.ReadAllText(_configFilename));
}
}
catch (System.Exception ex)
{
Logger.Error($"LoadConfig: {ex.Message}");
}
Config ??= new GameServiceConfig();
}
private void SaveConfig()
{
Utils.WriteObject(_configFilename, Config);
}
}
}
@@ -0,0 +1,11 @@
namespace ColorControl.Services.GameLauncher
{
class GameServiceConfig
{
public bool ApplyExternallyLaunched { get; set; }
public GameServiceConfig()
{
}
}
}
+6 -1
View File
@@ -1,5 +1,6 @@
using ColorControl.Services.Common;
using ColorControl.Shared.Common;
using ColorControl.Shared.Services;
using LgTv;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
@@ -262,8 +263,10 @@ namespace ColorControl.Services.LG
AddSetDeviceConfigAction("HDMI_4_icon", typeof(HdmiIcon), "HDMI 4 icon");
AddGenericPictureAction("soundMode", typeof(SoundMode), category: "sound", title: "Sound Mode");
AddGenericPictureAction("smartSoundMode", typeof(OffToOn), category: "sound", title: "Adaptive Sound Control");
AddGenericPictureAction("soundOutput", typeof(SoundOutput), category: "sound", title: "Sound Output");
AddGenericPictureAction("autoVolume", typeof(OffToOn), category: "sound", title: "Auto Volume");
AddGenericPictureAction("virtualSurround", typeof(OffToOn), category: "sound", title: "Virtual Surround");
//AddGenericPictureAction("enableToastPopup", typeof(OffToOn), category: "option", title: "enableToastPopup");
AddSetConfigAction("tv.conti.supportUsedTime", typeof(BoolFalseToTrue), title: "Total Power On Time");
@@ -917,7 +920,9 @@ namespace ColorControl.Services.LG
if (MacAddress != null)
{
result = WOL.WakeFunctionCheckAdmin(MacAddress, IpAddress);
var wolService = Program.ServiceProvider.GetRequiredService<WolService>();
result = wolService.SendWol(MacAddress, IpAddress);
_justWokeUp = true;
}
else
+1 -1
View File
@@ -263,7 +263,7 @@ namespace ColorControl.Services.LG
private void UpdateInfo()
{
lblTvName.Text = $"Device: {_lgDevice?.Name ?? "No tv selected"}";
lblProcessName.Text = $"Current process: {_lgService.MonitorContext?.ForegroundProcess?.ProcessName ?? _lgService.MonitorContext?.LastFullScreenProcessName ?? "No full screen process"}";
lblProcessName.Text = $"Current process: {_lgService.CurrentProcessEvent?.ForegroundProcess?.ProcessName ?? _lgService.CurrentProcessEvent?.LastFullScreenProcessName ?? "No full screen process"}";
UpdateValues();
}
+2 -2
View File
@@ -43,7 +43,7 @@ namespace ColorControl.Services.LG
_trayIcon = trayIcon;
_mainHandle = handle;
_config = Shared.Common.AppContext.CurrentContext.Config;
_config = Shared.Common.GlobalContext.CurrentContext.Config;
InitializeComponent();
@@ -96,7 +96,7 @@ namespace ColorControl.Services.LG
{
FillLgDevices();
var startUpParams = Shared.Common.AppContext.CurrentContext.StartUpParams;
var startUpParams = Shared.Common.GlobalContext.CurrentContext.StartUpParams;
if (startUpParams.ExecuteLgPreset)
{
+10 -18
View File
@@ -22,19 +22,6 @@ namespace ColorControl.Services.LG
{
class LgService : ServiceBase<LgPreset>
{
internal class ProcessMonitorContext
{
public List<LgDevice> Devices { get; set; }
public bool WasFullScreen { get; set; }
public Process[] StartedProcesses { get; set; }
public Process[] StoppedProcesses { get; set; }
public Process[] RunningProcesses { get; set; }
public bool IsNotificationDisabled { get; set; }
public Process ForegroundProcess { get; set; }
public bool ForegroundProcessIsFullScreen { get; set; }
public string LastFullScreenProcessName = string.Empty;
}
protected static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
public static string LgListAppsJson = "listApps.json";
@@ -56,7 +43,6 @@ namespace ColorControl.Services.LG
public event EventHandler SelectedDeviceChangedEvent;
public LgServiceConfig Config { get; private set; }
public ProcessMonitorContext MonitorContext { get; private set; }
protected override string PresetsBaseFilename => "LgPresets.json";
@@ -75,9 +61,13 @@ namespace ColorControl.Services.LG
private int _poweredOffByScreenSaverProcessId;
private LgPreset _lastTriggeredPreset;
private RestartDetector _restartDetector;
private readonly WinApiService _winApiService;
private readonly WinApiAdminService _winApiAdminService;
private SynchronizationContext _syncContext;
public LgService(AppContextProvider appContextProvider, PowerEventDispatcher powerEventDispatcher, SessionSwitchDispatcher sessionSwitchDispatcher, ProcessEventDispatcher processEventDispatcher, ServiceManager serviceManager, RestartDetector restartDetector) : base(appContextProvider)
public ProcessChangedEventArgs CurrentProcessEvent => _processEventDispatcher?.MonitorContext;
public LgService(AppContextProvider appContextProvider, PowerEventDispatcher powerEventDispatcher, SessionSwitchDispatcher sessionSwitchDispatcher, ProcessEventDispatcher processEventDispatcher, ServiceManager serviceManager, RestartDetector restartDetector, WinApiService winApiService, WinApiAdminService winApiAdminService) : base(appContextProvider)
{
_allowPowerOn = appContextProvider.GetAppContext().StartUpParams.RunningFromScheduledTask;
_powerEventDispatcher = powerEventDispatcher;
@@ -87,6 +77,8 @@ namespace ColorControl.Services.LG
LgPreset.LgApps = _lgApps;
_restartDetector = restartDetector;
_winApiService = winApiService;
_winApiAdminService = winApiAdminService;
_syncContext = appContextProvider.GetAppContext().SynchronizationContext;
LgTvApiCore.SyncContext = _syncContext;
@@ -851,7 +843,7 @@ namespace ColorControl.Services.LG
var standByScript = Path.Combine(Program.DataDir, "StandByScript.bat");
if (File.Exists(standByScript))
{
Utils.StartProcess(standByScript, hidden: true, wait: true);
_winApiAdminService.StartProcess(standByScript, hidden: true, wait: true);
}
}
@@ -911,13 +903,13 @@ namespace ColorControl.Services.LG
if (File.Exists(resumeScript))
{
Utils.StartProcess(resumeScript, hidden: true);
_winApiAdminService.StartProcess(resumeScript, hidden: true);
}
}
private void SendConfigToService()
{
if (!Utils.IsServiceRunning())
if (!_winApiService.IsServiceRunning())
{
return;
}
+89
View File
@@ -0,0 +1,89 @@
namespace ColorControl.Services.NVIDIA
{
partial class NvInfoPanel
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
grpNVIDIAInfo = new System.Windows.Forms.GroupBox();
btnRefreshNVIDIAInfo = new System.Windows.Forms.Button();
tvNVIDIAInfo = new System.Windows.Forms.TreeView();
grpNVIDIAInfo.SuspendLayout();
SuspendLayout();
//
// grpNVIDIAInfo
//
grpNVIDIAInfo.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
grpNVIDIAInfo.Controls.Add(btnRefreshNVIDIAInfo);
grpNVIDIAInfo.Controls.Add(tvNVIDIAInfo);
grpNVIDIAInfo.Location = new System.Drawing.Point(4, 3);
grpNVIDIAInfo.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
grpNVIDIAInfo.Name = "grpNVIDIAInfo";
grpNVIDIAInfo.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3);
grpNVIDIAInfo.Size = new System.Drawing.Size(643, 547);
grpNVIDIAInfo.TabIndex = 5;
grpNVIDIAInfo.TabStop = false;
grpNVIDIAInfo.Text = "NVIDIA info";
//
// btnRefreshNVIDIAInfo
//
btnRefreshNVIDIAInfo.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left;
btnRefreshNVIDIAInfo.Location = new System.Drawing.Point(8, 514);
btnRefreshNVIDIAInfo.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
btnRefreshNVIDIAInfo.Name = "btnRefreshNVIDIAInfo";
btnRefreshNVIDIAInfo.Size = new System.Drawing.Size(88, 27);
btnRefreshNVIDIAInfo.TabIndex = 1;
btnRefreshNVIDIAInfo.Text = "Refresh";
btnRefreshNVIDIAInfo.UseVisualStyleBackColor = true;
btnRefreshNVIDIAInfo.Click += btnRefreshNVIDIAInfo_Click;
//
// tvNVIDIAInfo
//
tvNVIDIAInfo.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
tvNVIDIAInfo.Location = new System.Drawing.Point(8, 22);
tvNVIDIAInfo.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
tvNVIDIAInfo.Name = "tvNVIDIAInfo";
tvNVIDIAInfo.Size = new System.Drawing.Size(627, 486);
tvNVIDIAInfo.TabIndex = 0;
//
// NvInfoPanel
//
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
Controls.Add(grpNVIDIAInfo);
Name = "NvInfoPanel";
Size = new System.Drawing.Size(654, 556);
grpNVIDIAInfo.ResumeLayout(false);
ResumeLayout(false);
}
#endregion
private System.Windows.Forms.GroupBox grpNVIDIAInfo;
private System.Windows.Forms.Button btnRefreshNVIDIAInfo;
private System.Windows.Forms.TreeView tvNVIDIAInfo;
}
}
@@ -0,0 +1,46 @@
using ColorControl.Shared.Forms;
using NvAPIWrapper.Display;
using System.Windows.Forms;
namespace ColorControl.Services.NVIDIA
{
public partial class NvInfoPanel : UserControl, IModulePanel
{
private NvService _nvService;
internal NvInfoPanel(NvService nvService)
{
_nvService = nvService;
InitializeComponent();
if (DarkModeUtils.UseDarkMode)
{
grpNVIDIAInfo.ForeColor = FormUtils.CurrentForeColor;
}
RefreshInfo();
}
public void UpdateInfo()
{
RefreshInfo();
}
private void btnRefreshNVIDIAInfo_Click(object sender, System.EventArgs e)
{
}
private void RefreshInfo()
{
tvNVIDIAInfo.Nodes.Clear();
var displays = Display.GetDisplays();
for (var i = 0; i < displays.Length; i++)
{
var display = displays[i];
var node = TreeNodeBuilder.CreateTree(display, $"Display[{i}]");
tvNVIDIAInfo.Nodes.Add(node);
}
}
}
}
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing"">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
+36 -18
View File
@@ -82,6 +82,8 @@ namespace ColorControl.Services.NVIDIA
miNvDriverSettingsIncluded = new System.Windows.Forms.ToolStripMenuItem();
mnuNvOtherSettings = new System.Windows.Forms.ToolStripMenuItem();
miNvOtherIncluded = new System.Windows.Forms.ToolStripMenuItem();
mnuNvHdmiSettings = new System.Windows.Forms.ToolStripMenuItem();
miNvHdmiIncluded = new System.Windows.Forms.ToolStripMenuItem();
mnuNvOverclocking = new System.Windows.Forms.ToolStripMenuItem();
miNvOverclockingIncluded = new System.Windows.Forms.ToolStripMenuItem();
miNvCopyId = new System.Windows.Forms.ToolStripMenuItem();
@@ -91,9 +93,9 @@ namespace ColorControl.Services.NVIDIA
miNvProfileInspector = new System.Windows.Forms.ToolStripMenuItem();
miNvNovideo = new System.Windows.Forms.ToolStripMenuItem();
miNvSettings = new System.Windows.Forms.ToolStripMenuItem();
miNvTestDithering = new System.Windows.Forms.ToolStripMenuItem();
lvNvPresetsToolTip = new System.Windows.Forms.ToolTip(components);
mnuNvHdmiSettings = new System.Windows.Forms.ToolStripMenuItem();
miNvHdmiIncluded = new System.Windows.Forms.ToolStripMenuItem();
miNVIDIAInfo = new System.Windows.Forms.ToolStripMenuItem();
mnuNvPresets.SuspendLayout();
mnuNvSettings.SuspendLayout();
SuspendLayout();
@@ -326,7 +328,7 @@ namespace ColorControl.Services.NVIDIA
mnuNvPresets.ImageScalingSize = new System.Drawing.Size(20, 20);
mnuNvPresets.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { miNvApply, miNvPresetApplyOnStartup, tssNvPresetMenu, mnuNvDisplay, mnuNvPresetsColorSettings, mnuRefreshRate, mnuNvResolution, miNvPresetDithering, miNvHDR, mnuNvDriverSettings, mnuNvOtherSettings, mnuNvHdmiSettings, mnuNvOverclocking, miNvCopyId });
mnuNvPresets.Name = "mnuNvPresets";
mnuNvPresets.Size = new System.Drawing.Size(185, 318);
mnuNvPresets.Size = new System.Drawing.Size(185, 296);
mnuNvPresets.Opening += mnuNvPresets_Opening;
//
// miNvApply
@@ -543,7 +545,7 @@ namespace ColorControl.Services.NVIDIA
// miNvDriverSettingsIncluded
//
miNvDriverSettingsIncluded.Name = "miNvDriverSettingsIncluded";
miNvDriverSettingsIncluded.Size = new System.Drawing.Size(180, 22);
miNvDriverSettingsIncluded.Size = new System.Drawing.Size(120, 22);
miNvDriverSettingsIncluded.Text = "Included";
miNvDriverSettingsIncluded.Click += miNvDriverSettingsIncluded_Click;
//
@@ -557,10 +559,24 @@ namespace ColorControl.Services.NVIDIA
// miNvOtherIncluded
//
miNvOtherIncluded.Name = "miNvOtherIncluded";
miNvOtherIncluded.Size = new System.Drawing.Size(180, 22);
miNvOtherIncluded.Size = new System.Drawing.Size(120, 22);
miNvOtherIncluded.Text = "Included";
miNvOtherIncluded.Click += miNvOtherIncluded_Click;
//
// mnuNvHdmiSettings
//
mnuNvHdmiSettings.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { miNvHdmiIncluded });
mnuNvHdmiSettings.Name = "mnuNvHdmiSettings";
mnuNvHdmiSettings.Size = new System.Drawing.Size(184, 22);
mnuNvHdmiSettings.Text = "HDMI Settings";
//
// miNvHdmiIncluded
//
miNvHdmiIncluded.Name = "miNvHdmiIncluded";
miNvHdmiIncluded.Size = new System.Drawing.Size(120, 22);
miNvHdmiIncluded.Text = "Included";
miNvHdmiIncluded.Click += miNvHdmiIncluded_Click;
//
// mnuNvOverclocking
//
mnuNvOverclocking.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { miNvOverclockingIncluded });
@@ -571,7 +587,7 @@ namespace ColorControl.Services.NVIDIA
// miNvOverclockingIncluded
//
miNvOverclockingIncluded.Name = "miNvOverclockingIncluded";
miNvOverclockingIncluded.Size = new System.Drawing.Size(180, 22);
miNvOverclockingIncluded.Size = new System.Drawing.Size(120, 22);
miNvOverclockingIncluded.Text = "Included";
miNvOverclockingIncluded.Click += miNvOverclockingIncluded_Click;
//
@@ -620,9 +636,9 @@ namespace ColorControl.Services.NVIDIA
// mnuNvSettings
//
mnuNvSettings.ImageScalingSize = new System.Drawing.Size(20, 20);
mnuNvSettings.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { miNvProfileInspector, miNvNovideo, miNvSettings });
mnuNvSettings.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { miNvProfileInspector, miNvNovideo, miNvSettings, miNvTestDithering, miNVIDIAInfo });
mnuNvSettings.Name = "mnuLgButtons";
mnuNvSettings.Size = new System.Drawing.Size(202, 70);
mnuNvSettings.Size = new System.Drawing.Size(202, 136);
//
// miNvProfileInspector
//
@@ -645,19 +661,19 @@ namespace ColorControl.Services.NVIDIA
miNvSettings.Text = "Settings";
miNvSettings.Click += miNvSettings_Click;
//
// mnuNvHdmiSettings
// miNvTestDithering
//
mnuNvHdmiSettings.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { miNvHdmiIncluded });
mnuNvHdmiSettings.Name = "mnuNvHdmiSettings";
mnuNvHdmiSettings.Size = new System.Drawing.Size(184, 22);
mnuNvHdmiSettings.Text = "HDMI Settings";
miNvTestDithering.Name = "miNvTestDithering";
miNvTestDithering.Size = new System.Drawing.Size(201, 22);
miNvTestDithering.Text = "Test dithering";
miNvTestDithering.Click += miNvTestDithering_Click;
//
// miNvHdmiIncluded
// miNVIDIAInfo
//
miNvHdmiIncluded.Name = "miNvHdmiIncluded";
miNvHdmiIncluded.Size = new System.Drawing.Size(180, 22);
miNvHdmiIncluded.Text = "Included";
miNvHdmiIncluded.Click += miNvHdmiIncluded_Click;
miNVIDIAInfo.Name = "miNVIDIAInfo";
miNVIDIAInfo.Size = new System.Drawing.Size(201, 22);
miNVIDIAInfo.Text = "NVIDIA Info";
miNVIDIAInfo.Click += miNVIDIAInfo_Click;
//
// NvPanel
//
@@ -760,5 +776,7 @@ namespace ColorControl.Services.NVIDIA
private System.Windows.Forms.ToolStripMenuItem miNvOtherIncluded;
private System.Windows.Forms.ToolStripMenuItem mnuNvHdmiSettings;
private System.Windows.Forms.ToolStripMenuItem miNvHdmiIncluded;
private System.Windows.Forms.ToolStripMenuItem miNvTestDithering;
private System.Windows.Forms.ToolStripMenuItem miNVIDIAInfo;
}
}
+27 -10
View File
@@ -37,9 +37,9 @@ namespace ColorControl.Services.NVIDIA
private readonly AppContextProvider _appContextProvider;
private string _lastDisplayRefreshRates = string.Empty;
private NotifyIcon _trayIcon;
private RpcService _rpcService;
private RpcClientService _rpcService;
public NvPanel(NvService nvService, NotifyIcon trayIcon, IntPtr handle, AppContextProvider appContextProvider, RpcService rpcService)
public NvPanel(NvService nvService, NotifyIcon trayIcon, IntPtr handle, AppContextProvider appContextProvider, RpcClientService rpcService)
{
_nvService = nvService;
_trayIcon = trayIcon;
@@ -287,17 +287,20 @@ namespace ColorControl.Services.NVIDIA
{
var preset = GetSelectedNvPreset(true);
var checkState = miNvPresetDitheringEnabled.CheckState;
var newCheckState = checkState == CheckState.Checked ? CheckState.Unchecked : checkState == CheckState.Unchecked ? CheckState.Indeterminate : CheckState.Checked;
if (preset.IsDisplayPreset)
{
miNvPresetDitheringEnabled.Checked = !miNvPresetDitheringEnabled.Checked;
miNvPresetDitheringEnabled.CheckState = newCheckState;
_nvService.SetDithering(miNvPresetDitheringEnabled.Checked ? NvDitherState.Enabled : NvDitherState.Disabled);
_nvService.SetDithering(newCheckState == CheckState.Indeterminate ? NvDitherState.Auto : newCheckState == CheckState.Checked ? NvDitherState.Enabled : NvDitherState.Disabled);
UpdateDisplayInfoItems();
return;
}
preset.ditheringEnabled = !preset.ditheringEnabled;
preset.ditheringEnabled = checkState == CheckState.Indeterminate ? null : checkState == CheckState.Checked;
AddOrUpdateItem();
}
@@ -395,7 +398,7 @@ namespace ColorControl.Services.NVIDIA
miNvPresetColorSettings.Checked = preset.applyColorData;
miNvPresetApplyDithering.Checked = preset.applyDithering;
miNvPresetDitheringEnabled.Checked = preset.ditheringEnabled;
miNvPresetDitheringEnabled.CheckState = preset.ditheringEnabled == null ? CheckState.Indeterminate : preset.ditheringEnabled == true ? CheckState.Checked : CheckState.Unchecked;
foreach (var item in mnuNvDitheringBitDepth.DropDownItems.OfType<ToolStripMenuItem>())
{
@@ -1466,7 +1469,7 @@ namespace ColorControl.Services.NVIDIA
return;
}
_nvService.ApplyOverclocking(newSettings);
_nvService.ApplyOverclocking(new List<NvGpuOcSettings> { newSettings });
UpdateNvGpuInfo();
}
@@ -1687,7 +1690,7 @@ namespace ColorControl.Services.NVIDIA
private async Task ApplyNvPresetOnStartup(int attempts = 5)
{
var startUpParams = Shared.Common.AppContext.CurrentContext.StartUpParams;
var startUpParams = Shared.Common.GlobalContext.CurrentContext.StartUpParams;
var presetIdOrName = !string.IsNullOrEmpty(startUpParams.NvidiaPresetIdOrName) ? startUpParams.NvidiaPresetIdOrName : _config.NvPresetId_ApplyOnStartup.ToString();
@@ -1728,7 +1731,7 @@ namespace ColorControl.Services.NVIDIA
if (preset.IsDisplayPreset)
{
_nvService.SetDithering(preset.ditheringEnabled ? NvDitherState.Enabled : NvDitherState.Disabled, ditheringBits, preset.ditheringMode);
_nvService.SetDithering(preset.DitherState, ditheringBits, preset.ditheringMode);
UpdateDisplayInfoItems();
return;
@@ -1749,7 +1752,7 @@ namespace ColorControl.Services.NVIDIA
if (preset.IsDisplayPreset)
{
_nvService.SetDithering(preset.ditheringEnabled ? NvDitherState.Enabled : NvDitherState.Disabled, preset.ditheringBits, ditheringMode);
_nvService.SetDithering(preset.DitherState, preset.ditheringBits, ditheringMode);
UpdateDisplayInfoItems();
return;
@@ -1797,5 +1800,19 @@ namespace ColorControl.Services.NVIDIA
AddOrUpdateItem();
}
private void miNvTestDithering_Click(object sender, EventArgs e)
{
var panel = new NvDitherPanel(_nvService);
MessageForms.ShowControl(panel, "Test dithering");
}
private void miNVIDIAInfo_Click(object sender, EventArgs e)
{
var panel = new NvInfoPanel(_nvService);
MessageForms.ShowControl(panel, "NVIDIA Info");
}
}
}
+11 -5
View File
@@ -23,7 +23,7 @@ namespace ColorControl.Services.NVIDIA
public bool HDREnabled { get; set; }
public bool toggleHDR { get; set; }
public bool applyDithering { get; set; }
public bool ditheringEnabled { get; set; }
public bool? ditheringEnabled { get; set; }
public bool applyRefreshRate { get; set; }
public uint refreshRate { get; set; }
public bool applyResolution { get; set; }
@@ -49,6 +49,7 @@ namespace ColorControl.Services.NVIDIA
public Display Display { get; set; }
[JsonIgnore]
public string InfoLine { get; set; }
public NvDitherState DitherState => ditheringEnabled.HasValue ? ditheringEnabled == true ? NvDitherState.Enabled : NvDitherState.Disabled : NvDitherState.Auto;
public NvPreset() : base()
{
@@ -224,14 +225,19 @@ namespace ColorControl.Services.NVIDIA
public string GetDitheringDescription(string disabledText = "Disabled")
{
var dithering = ditheringEnabled ? string.Empty : disabledText;
if (ditheringEnabled)
if (ditheringEnabled == null && ditheringBits == 0 && ditheringMode == 0)
{
return "Auto: Disabled";
}
if (ditheringEnabled is null or true)
{
var ditherBitsDescription = ((NvDitherBits)ditheringBits).GetDescription();
var ditherModeDescription = ((NvDitherMode)ditheringMode).GetDescription();
dithering = string.Format("{0} {1}", ditherBitsDescription, ditherModeDescription);
return string.Format("{0}{1} {2}", ditheringEnabled == null ? "Auto: " : "", ditherBitsDescription, ditherModeDescription);
}
return dithering;
return disabledText;
}
public string GetHdmiSettingsDescription()
+64 -45
View File
@@ -7,6 +7,7 @@ using ColorControl.Shared.Native;
using ColorControl.Shared.Services;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using novideo_srgb;
using nspector.Common;
using nspector.Common.Meta;
using NvAPIWrapper.Display;
@@ -143,11 +144,15 @@ namespace ColorControl.Services.NVIDIA
DRS_RBAR_OPTIONS,
DRS_RBAR_SIZE_LIMIT
};
private readonly WinApiService _winApiService;
private readonly RpcClientService _rpcClientService;
private static NvService ServiceInstance;
public NvService(AppContextProvider appContextProvider) : base(appContextProvider)
public NvService(AppContextProvider appContextProvider, WinApiService winApiService, RpcClientService rpcClientService) : base(appContextProvider)
{
_winApiService = winApiService;
_rpcClientService = rpcClientService;
_rpcClientService.Name = nameof(NvService);
NvPreset.NvService = this;
AddJsonConverter(new ColorDataConverter());
@@ -159,9 +164,7 @@ namespace ColorControl.Services.NVIDIA
{
try
{
var appContextProvider = Program.ServiceProvider.GetRequiredService<AppContextProvider>();
var nvService = new NvService(appContextProvider);
var nvService = Program.ServiceProvider.GetRequiredService<NvService>();
var result = await nvService.ApplyPreset(idOrName);
@@ -315,6 +318,11 @@ namespace ColorControl.Services.NVIDIA
if (applyHdr)
{
if (newHdrEnabled && !hdrEnabled)
{
MainWindow.BeforeDisplaySettingsChange();
}
SetHDRState(display, newHdrEnabled);
}
@@ -341,7 +349,7 @@ namespace ColorControl.Services.NVIDIA
if (preset.applyDithering)
{
if (!SetDithering(preset.ditheringEnabled ? NvDitherState.Enabled : NvDitherState.Disabled, preset: preset))
if (!SetDithering(preset.DitherState, preset: preset))
{
result = false;
}
@@ -364,19 +372,17 @@ namespace ColorControl.Services.NVIDIA
return Task.FromResult(result);
}
public bool ApplyOverclocking(NvGpuOcSettings setting)
{
return ApplyOverclocking(new List<NvGpuOcSettings> { setting });
}
public bool ApplyOverclocking(List<NvGpuOcSettings> settings)
{
if (!Utils.IsAdministrator())
if (!_winApiService.IsAdministrator())
{
var result = PipeUtils.SendMessage(new SvcNvOverclockingMessage
var message = new SvcRpcSetNvOverclockingMessage
{
MethodName = nameof(ApplyOverclocking),
OverclockingSettings = settings
});
};
var result = _rpcClientService.Call<object>(message);
if (result == null)
{
@@ -418,42 +424,26 @@ namespace ColorControl.Services.NVIDIA
}
}
public static void ApplyDriverSettings(string profileName, List<KeyValuePair<uint, string>> settings)
public void ApplyDriverSettings(string profileName, List<KeyValuePair<uint, string>> settings)
{
CheckServiceInstance();
RefreshProfileSettings();
ServiceInstance._drs.StoreSettingsToProfile(profileName, settings);
_drs.StoreSettingsToProfile(profileName, settings);
}
public static bool RestoreDriverSettings(string profileName, List<KeyValuePair<uint, string>> settings)
public bool RestoreDriverSettings(string profileName, List<KeyValuePair<uint, string>> settings)
{
CheckServiceInstance();
var result = false;
foreach (var keyValuePair in settings)
{
var settingId = keyValuePair.Key;
ServiceInstance._drs.ResetValue(profileName, settingId, out result);
_drs.ResetValue(profileName, settingId, out result);
}
return result;
}
public static NvService CheckServiceInstance()
{
if (ServiceInstance == null)
{
var appContextProvider = Program.ServiceProvider.GetRequiredService<AppContextProvider>();
ServiceInstance = new NvService(appContextProvider);
ServiceInstance.Initialize();
ServiceInstance.RefreshProfileSettings();
}
return ServiceInstance;
}
private void SetDriverSettings(Dictionary<uint, uint> settings)
{
var convertedSettings = new List<KeyValuePair<uint, string>>();
@@ -853,6 +843,22 @@ namespace ColorControl.Services.NVIDIA
//var display = GetCurrentDisplay();
//var displayDevice = display.DisplayDevice;
//var config = DisplayApi.GetDisplayConfig();
//var config1 = config[0];
//var pathInfo1 = config1.TargetsInfo.First();
//var details = pathInfo1.Details.Value;
//var newDetails = new PathAdvancedTargetInfo(details.Rotation, Scaling.GPUScanOutToNative);
//var newPathTargetInfo = new PathTargetInfoV2(pathInfo1.DisplayId, newDetails);
//var newPathInfo = new PathInfoV2(new[] { newPathTargetInfo }, config1.SourceModeInfo);
//DisplayApi.SetDisplayConfig(new IPathInfo[] { newPathInfo }, DisplayConfigFlags.SaveToPersistence);
//var info = DisplayApi.GetScanOutConfiguration(displayDevice.DisplayId);
//var vertices = new float[] {
@@ -1023,7 +1029,7 @@ namespace ColorControl.Services.NVIDIA
}
else
{
preset.ditheringEnabled = ditherInfo.state != (int)NvDitherState.Disabled;
preset.ditheringEnabled = ditherInfo.state == 0 ? null : ditherInfo.state != (int)NvDitherState.Disabled;
preset.ditheringBits = (uint)ditherInfo.bits;
preset.ditheringMode = (uint)ditherInfo.mode;
}
@@ -1123,11 +1129,11 @@ namespace ColorControl.Services.NVIDIA
_drs.GetProfileNames(ref _baseProfileName, false);
if (!Utils.IsAdministrator())
{
_drs.ApplySettings += HandleDrsApplySettings;
_drs.RestoreSetting += HandleDrsRestoreSetting;
}
//if (!WinApiService.IsAdministratorStatic())
//{
_drs.ApplySettings += HandleDrsApplySettings;
_drs.RestoreSetting += HandleDrsRestoreSetting;
//}
//SetGpuClocks();
@@ -1169,10 +1175,9 @@ namespace ColorControl.Services.NVIDIA
private bool HasPrivilegesForUnexposedApis()
{
return Utils.IsAdministrator() || _appContextProvider.GetAppContext()?.Config.ElevationMethod != ElevationMethod.UseService || _appContextProvider.GetAppContext()?.IsServiceRunning() != true;
return _winApiService.IsAdministrator() || !_winApiService.IsServiceRunning();
}
private void HandleDrsApplySettings(object sender, DrsEvent drsEvent)
{
if (HasPrivilegesForUnexposedApis())
@@ -1180,7 +1185,14 @@ namespace ColorControl.Services.NVIDIA
return;
}
PipeUtils.SendMessage(new SvcNvDriverSettingsMessage { ProfileName = drsEvent.ProfileName, DriverSettings = drsEvent.Settings });
var message = new SvcRpcSetNvDriverSettingsMessage
{
MethodName = nameof(ApplyDriverSettings),
ProfileName = drsEvent.ProfileName,
DriverSettings = drsEvent.Settings
};
_rpcClientService.Call<object>(message);
drsEvent.Handled = true;
}
@@ -1192,7 +1204,14 @@ namespace ColorControl.Services.NVIDIA
return;
}
PipeUtils.SendMessage(new SvcNvDriverSettingsMessage(SvcMessageType.RestoreNvidiaDriverSetting) { ProfileName = drsEvent.ProfileName, DriverSettings = drsEvent.Settings });
var message = new SvcRpcSetNvDriverSettingsMessage
{
MethodName = nameof(RestoreDriverSettings),
ProfileName = drsEvent.ProfileName,
DriverSettings = drsEvent.Settings
};
_rpcClientService.Call<object>(message);
drsEvent.Handled = true;
}
@@ -1,6 +1,7 @@
using ColorControl.Services.Common;
using ColorControl.Shared.Common;
using ColorControl.Shared.Forms;
using ColorControl.Shared.Services;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using NLog;
@@ -114,7 +115,7 @@ namespace ColorControl.Services.Samsung
AddInvokableAction("WOL", WakeAction);
AddInvokableAction("ServiceMenu", ServiceMenuAction, true);
AddInternalPresetAction(new SamsungPreset("PictureOff", null, new[] { "KEY_AD:1200", "KEY_DOWN:300", "KEY_DOWN:300", "KEY_ENTER" }));
AddInternalPresetAction(new SamsungPreset("PictureOff", null, new[] { "KEY_AD:1400", "KEY_DOWN:200", "KEY_DOWN:200", "KEY_ENTER" }));
AddInternalPresetAction(new SamsungPreset("PictureOn", null, new[] { "KEY_RETURN:1000", "KEY_RETURN", "KEY_RETURN" }));
_serviceManager = Program.ServiceProvider.GetRequiredService<ServiceManager>();
@@ -328,7 +329,9 @@ namespace ColorControl.Services.Samsung
if (MacAddress != null)
{
result = WOL.WakeFunctionCheckAdmin(MacAddress, IpAddress);
var wolService = Program.ServiceProvider.GetRequiredService<WolService>();
result = wolService.SendWol(MacAddress, IpAddress);
}
else
{
@@ -385,7 +388,7 @@ namespace ColorControl.Services.Samsung
return $"{(IsDummy ? string.Empty : (IsCustom ? "Custom: " : "Auto detect: "))}{Name}{(!string.IsNullOrEmpty(IpAddress) ? ", " + IpAddress : string.Empty)}";
}
internal async Task<bool> ExecutePresetAsync(SamsungPreset preset, Shared.Common.AppContext appContext = null, SamsungServiceConfig config = null)
internal async Task<bool> ExecutePresetAsync(SamsungPreset preset, Shared.Common.GlobalContext appContext = null, SamsungServiceConfig config = null)
{
if (config == null)
{
@@ -463,7 +466,7 @@ namespace ColorControl.Services.Samsung
return true;
}
private async Task ExecuteStepsAsync(SamsungPreset preset, Shared.Common.AppContext appContext, SamsungServiceConfig config)
private async Task ExecuteStepsAsync(SamsungPreset preset, Shared.Common.GlobalContext appContext, SamsungServiceConfig config)
{
foreach (var step in preset.Steps)
{
@@ -521,7 +524,7 @@ namespace ColorControl.Services.Samsung
}
}
public async Task ExecuteActionAsync(InvokableAction action, string[] parameters, Shared.Common.AppContext appContext, SamsungServiceConfig config)
public async Task ExecuteActionAsync(InvokableAction action, string[] parameters, Shared.Common.GlobalContext appContext, SamsungServiceConfig config)
{
if (action.Preset != null)
{
@@ -38,7 +38,7 @@ namespace ColorControl.Services.Samsung
_amdService = amdService;
_mainHandle = handle;
_config = Shared.Common.AppContext.CurrentContext.Config;
_config = Shared.Common.GlobalContext.CurrentContext.Config;
InitializeComponent();
@@ -94,7 +94,7 @@ namespace ColorControl.Services.Samsung
{
FillSamsungDevices();
var startUpParams = Shared.Common.AppContext.CurrentContext.StartUpParams;
var startUpParams = Shared.Common.GlobalContext.CurrentContext.StartUpParams;
if (startUpParams.ExecuteSamsungPreset)
{
@@ -1114,7 +1114,7 @@ Do you want to continue?";
return;
}
await device.ExecuteActionAsync(action, null, Shared.Common.AppContext.CurrentContext, _samsungService.Config);
await device.ExecuteActionAsync(action, null, Shared.Common.GlobalContext.CurrentContext, _samsungService.Config);
}
}
}
@@ -33,16 +33,17 @@ namespace ColorControl.Services.Samsung
private readonly SessionSwitchDispatcher _sessionSwitchDispatcher;
private readonly RestartDetector _restartDetector;
private readonly ProcessEventDispatcher _processEventDispatcher;
private readonly WinApiAdminService _winApiAdminService;
private string _configFilename;
private bool _poweredOffByScreenSaver;
private int _poweredOffByScreenSaverProcessId;
private object _lastTriggeredPreset;
private List<SamsungApp> _samsungApps = new List<SamsungApp>();
private Shared.Common.AppContext _appContext;
private Shared.Common.GlobalContext _appContext;
public List<SamsungDevice> Devices { get; private set; }
public SamsungService(AppContextProvider appContextProvider, ServiceManager serviceManager, PowerEventDispatcher powerEventDispatcher, SessionSwitchDispatcher sessionSwitchDispatcher, RestartDetector restartDetector, ProcessEventDispatcher processEventDispatcher) : base(appContextProvider)
public SamsungService(AppContextProvider appContextProvider, ServiceManager serviceManager, PowerEventDispatcher powerEventDispatcher, SessionSwitchDispatcher sessionSwitchDispatcher, RestartDetector restartDetector, ProcessEventDispatcher processEventDispatcher, WinApiAdminService winApiAdminService) : base(appContextProvider)
{
_appContext = appContextProvider.GetAppContext();
_allowPowerOn = _appContext.StartUpParams.RunningFromScheduledTask;
@@ -51,6 +52,7 @@ namespace ColorControl.Services.Samsung
_sessionSwitchDispatcher = sessionSwitchDispatcher;
_restartDetector = restartDetector;
_processEventDispatcher = processEventDispatcher;
_winApiAdminService = winApiAdminService;
SamTvConnection.SyncContext = _appContext.SynchronizationContext;
LoadConfig();
@@ -267,7 +269,7 @@ namespace ColorControl.Services.Samsung
return await ApplyPreset(preset, _appContext);
}
private async Task<bool> ApplyPreset(SamsungPreset preset, Shared.Common.AppContext appContext)
private async Task<bool> ApplyPreset(SamsungPreset preset, Shared.Common.GlobalContext appContext)
{
var result = true;
@@ -368,7 +370,7 @@ namespace ColorControl.Services.Samsung
var standByScript = Path.Combine(Program.DataDir, "StandByScript.bat");
if (File.Exists(standByScript))
{
Utils.StartProcess(standByScript, hidden: true, wait: true);
_winApiAdminService.StartProcess(standByScript, hidden: true, wait: true);
}
}
@@ -428,7 +430,7 @@ namespace ColorControl.Services.Samsung
if (File.Exists(resumeScript))
{
Utils.StartProcess(resumeScript, hidden: true);
_winApiAdminService.StartProcess(resumeScript, hidden: true);
}
}
@@ -1,8 +1,8 @@
using ColorControl.Services.EventDispatcher;
using ColorControl.Services.LG;
using ColorControl.Services.NVIDIA;
using ColorControl.Shared.Common;
using ColorControl.Shared.Contracts;
using ColorControl.Shared.Services;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using NLog;
@@ -21,11 +21,19 @@ namespace ColorControl.Svc
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly SessionSwitchDispatcher _sessionSwitchDispatcher;
private readonly RpcServerService _rpcServerService;
private readonly WinApiAdminService _winApiAdminService;
private readonly WolService _wolService;
private static string LgConfigFile = "LgConfig.json";
public ColorControlBackgroundService(SessionSwitchDispatcher sessionSwitchDispatcher)
public string PipeName { get; set; } = PipeUtils.ServicePipe;
public ColorControlBackgroundService(SessionSwitchDispatcher sessionSwitchDispatcher, RpcServerService rpcServerService, WinApiAdminService winApiAdminService, WolService wolService)
{
_sessionSwitchDispatcher = sessionSwitchDispatcher;
_rpcServerService = rpcServerService;
_winApiAdminService = winApiAdminService;
_wolService = wolService;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
@@ -37,7 +45,10 @@ namespace ColorControl.Svc
//var lgService = new LgService(Program.DataDir, true);
//lgService.InstallEventHandlers(true);
await WakeDevicesAsync();
if (PipeName == PipeUtils.ServicePipe)
{
await WakeDevicesAsync();
}
var securityIdentifier = new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null);
@@ -50,7 +61,7 @@ namespace ColorControl.Svc
{
Logger.Debug("WAITING FOR MESSAGE...");
var pipeServer = NamedPipeServerStreamAcl.Create("testpipe", PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, 1024, 1024, ps);
var pipeServer = NamedPipeServerStreamAcl.Create(PipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, 1024, 1024, ps);
await pipeServer.WaitForConnectionAsync(stoppingToken);
@@ -113,39 +124,31 @@ namespace ColorControl.Svc
SvcMessageType.SetLgConfig => HandleSetLgConfigMessage(message),
SvcMessageType.GetLog => HandleGetLogMessage(message),
SvcMessageType.ClearLog => HandleClearLogMessage(message),
SvcMessageType.ExecuteRpc => await HandleExecuteRpcCommand(message),
SvcMessageType.ExecuteRpcGeneric => await HandleExecuteRpcGenericCommand(JsonConvert.DeserializeObject<SvcRpcMessage>(json)),
SvcMessageType.ExecuteRpcGeneric => await _rpcServerService.ExecuteRpcAsync(JsonConvert.DeserializeObject<SvcRpcMessage>(json)),
SvcMessageType.ExecuteRpcGenericTyped => await HandleRpcTypedAsync(JsonConvert.DeserializeObject<SvcRpcMessageTyped>(json), json),
SvcMessageType.ExecuteUpdate => await HandleExecuteUpdateCommandAsync(JsonConvert.DeserializeObject<SvcInstallUpdateMessage>(json)),
SvcMessageType.RestartAfterUpdate => HandleRestartAfterUpdateMessage(),
SvcMessageType.ApplyNvidiaDriverSettings => HandleNvDriverSettingsMessage(JsonConvert.DeserializeObject<SvcNvDriverSettingsMessage>(json)),
SvcMessageType.RestoreNvidiaDriverSetting => HandleNvRestoreDriverSettingsMessage(JsonConvert.DeserializeObject<SvcNvDriverSettingsMessage>(json)),
SvcMessageType.ApplyNvidiaOverclocking => HandleNvOverclockingMessage(JsonConvert.DeserializeObject<SvcNvOverclockingMessage>(json)),
_ => SvcResultMessage.FromResult(false, "Unexpected message type")
};
return result;
}
private async Task<SvcResultMessage> HandleExecuteRpcCommand(SvcMessage message)
private async Task<SvcResultMessage> HandleRpcTypedAsync(SvcRpcMessageTyped message, string json)
{
var args = message.Data.Split(' ');
var typeName = message.TypeName;
var startUpParams = StartUpParams.Parse(args);
Logger.Debug($"TypeName: {typeName}");
return SvcResultMessage.FromResult(await CommandLineHandler.HandleStartupParams(startUpParams, null));
}
var type = Type.GetType($"ColorControl.Shared.Contracts.{typeName}, Shared");
private async Task<SvcResultMessage> HandleExecuteRpcGenericCommand(SvcRpcMessage message)
{
var service = NvService.CheckServiceInstance();
Logger.Debug($"Type: {type?.Name}");
var method = service.GetType().GetMethod(message.MethodName);
var typedMessage = JsonConvert.DeserializeObject(json, type) as SvcRpcMessageTyped;
var result = method.Invoke(service, message.Arguments);
Logger.Debug($"Msg: {typedMessage?.MethodName}");
var data = JsonConvert.SerializeObject(result);
return SvcResultMessage.FromResult(data);
return await _rpcServerService.ExecuteRpcTypedAsync(typedMessage);
}
private SvcResultMessage HandleSetLgConfigMessage(SvcMessage message)
@@ -201,28 +204,7 @@ namespace ColorControl.Svc
private SvcResultMessage HandleRestartAfterUpdateMessage()
{
Utils.StartProcess("cmd.exe", $@"/C net stop ""{Utils.SERVICE_NAME}"" && net start ""{Utils.SERVICE_NAME}""", true);
return SvcResultMessage.FromResult(true);
}
private SvcResultMessage HandleNvDriverSettingsMessage(SvcNvDriverSettingsMessage message)
{
NvService.ApplyDriverSettings(message.ProfileName, message.DriverSettings);
return SvcResultMessage.FromResult(true);
}
private SvcResultMessage HandleNvRestoreDriverSettingsMessage(SvcNvDriverSettingsMessage message)
{
var result = NvService.RestoreDriverSettings(message.ProfileName, message.DriverSettings);
return SvcResultMessage.FromResult(result);
}
private SvcResultMessage HandleNvOverclockingMessage(SvcNvOverclockingMessage message)
{
NvService.CheckServiceInstance().ApplyOverclocking(message.OverclockingSettings);
_winApiAdminService.StartProcess("cmd.exe", $@"/C net stop ""{Utils.SERVICE_NAME}"" && net start ""{Utils.SERVICE_NAME}""", true);
return SvcResultMessage.FromResult(true);
}
@@ -252,7 +234,7 @@ namespace ColorControl.Svc
{
for (var i = 0; i < config.PowerOnRetries; i++)
{
WOL.WakeFunction(wakeDevice.MacAddress, wakeDevice.IpAddress);
_wolService.SendWol(wakeDevice.MacAddress, wakeDevice.IpAddress);
await Task.Delay(1000);
+17 -9
View File
@@ -1,8 +1,10 @@
using ColorControl.Shared.Common;
using ColorControl.Shared.Contracts;
using ColorControl.Shared.Forms;
using ColorControl.Shared.Services;
using ColorControl.Shared.XForms;
using DJ;
using Microsoft.Extensions.DependencyInjection;
using NLog;
using System;
using System.Collections.Generic;
@@ -19,16 +21,18 @@ namespace ColorControl.XForms
private static LogWindow _window;
private int _logLevelIndex;
private readonly WinApiAdminService _winApiAdminService;
public int LogLevelIndex { get => _logLevelIndex; set => _logLevelIndex = value; }
public LogWindow()
public LogWindow(WinApiAdminService winApiAdminService)
{
InitializeComponent();
LogLevelIndex = LogLevel.FromString(Shared.Common.AppContext.CurrentContext.Config.LogLevel).Ordinal;
LogLevelIndex = LogLevel.FromString(GlobalContext.CurrentContext.Config.LogLevel).Ordinal;
DataContext = this;
_winApiAdminService = winApiAdminService;
}
private void OnRequestNavigate(object sender, RequestNavigateEventArgs e)
@@ -47,7 +51,7 @@ namespace ColorControl.XForms
new Application();
}
_window ??= new LogWindow();
_window ??= Program.ServiceProvider.GetRequiredService<LogWindow>();
if (show)
{
@@ -77,7 +81,7 @@ namespace ColorControl.XForms
private void RawLog_Click(object sender, RoutedEventArgs e)
{
var context = Shared.Common.AppContext.CurrentContext;
var context = Shared.Common.GlobalContext.CurrentContext;
string logFile;
if (tabControl.SelectedIndex == 0)
@@ -86,7 +90,9 @@ namespace ColorControl.XForms
}
else
{
if (!Utils.IsServiceRunning())
var winApiService = Program.ServiceProvider.GetRequiredService<WinApiService>();
if (!winApiService.IsServiceRunning())
{
MessageForms.WarningOk("Service is not running");
return;
@@ -109,7 +115,7 @@ namespace ColorControl.XForms
return;
}
Utils.StartProcess(logFile);
_winApiAdminService.StartProcess(logFile);
}
private void LoadOlder_Click(object sender, RoutedEventArgs e)
@@ -128,7 +134,7 @@ namespace ColorControl.XForms
private void LogLevel_Changed(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
var context = Shared.Common.AppContext.CurrentContext;
var context = Shared.Common.GlobalContext.CurrentContext;
var logLevel = LogLevel.FromOrdinal(_logLevelIndex);
@@ -144,7 +150,7 @@ namespace ColorControl.XForms
return;
}
var context = Shared.Common.AppContext.CurrentContext;
var context = Shared.Common.GlobalContext.CurrentContext;
var lines = LoadLog();
@@ -160,7 +166,9 @@ namespace ColorControl.XForms
return Utils.ReadLines(Program.LogFilename);
}
if (Utils.IsServiceRunning())
var winApiService = Program.ServiceProvider.GetRequiredService<WinApiService>();
if (winApiService.IsServiceRunning())
{
var message = new SvcMessage { MessageType = SvcMessageType.GetLog };
+2 -1
View File
@@ -1,5 +1,4 @@
using nspector.Native.NVAPI2;
using System;
using nvw = nspector.Native.NVAPI2.NvapiDrsWrapper;
namespace nspector.Common
@@ -38,6 +37,8 @@ namespace nspector.Common
if (nvRes != NvAPI_Status.NVAPI_OK)
throw new NvapiException("DRS_LoadSettings", nvRes);
}
var dRes = nvw.DRS_DecryptSession(GlobalSession);
}
}
+5 -3
View File
@@ -380,13 +380,15 @@ namespace nspector.Common
public SettingMeta GetSettingMeta(uint settingId, SettingViewMode viewMode = SettingViewMode.Normal)
{
if (settingMetaCache.ContainsKey(settingId))
var settingMeta = settingMetaCache.GetValueOrDefault(settingId);
if (settingMeta != null)
{
return PostProcessMeta(settingId, settingMetaCache[settingId], viewMode);
return PostProcessMeta(settingId, settingMeta, viewMode);
}
else
{
var settingMeta = CreateSettingMeta(settingId);
settingMeta = CreateSettingMeta(settingId);
settingMetaCache.Add(settingId, settingMeta);
return PostProcessMeta(settingId, settingMeta, viewMode);
}
+71 -1
View File
@@ -21,6 +21,29 @@ namespace nspector.Common
public event EventHandler<DrsEvent>? RestoreSetting;
public bool ExternalApplySettings => ApplySettings != null;
const uint DRS_NGX_FORCE_DLAA = 0x10E41DF4;
const uint DRS_NGX_SCALE_RATIO = 0x10E41DF5;
private NVDRS_SETTING[] HiddenSettings = new[]
{
new NVDRS_SETTING {
version = nvw.NVDRS_SETTING_VER,
settingId = DRS_NGX_FORCE_DLAA,
settingType = NVDRS_SETTING_TYPE.NVDRS_DWORD_TYPE,
currentValue = new NVDRS_SETTING_UNION {
dwordValue = 0u
}
},
new NVDRS_SETTING {
version = nvw.NVDRS_SETTING_VER,
settingId = DRS_NGX_SCALE_RATIO,
settingType = NVDRS_SETTING_TYPE.NVDRS_DWORD_TYPE,
currentValue = new NVDRS_SETTING_UNION {
dwordValue = 0u
}
}
};
public DrsSettingsService(DrsSettingsMetaService metaService, DrsDecrypterService decrpterService)
: base(metaService, decrpterService)
{
@@ -180,6 +203,30 @@ namespace nspector.Common
return lstResult;
}
public string? GetProfileNameByApps(string appName)
{
string? name = null;
DrsSession((hSession) =>
{
var profileHandles = EnumProfileHandles(hSession);
foreach (IntPtr hProfile in profileHandles)
{
var apps = GetProfileApplications(hSession, hProfile);
if (apps.Any(a => a.appName.Equals(appName, StringComparison.OrdinalIgnoreCase)))
{
var profile = GetProfileInfo(hSession, hProfile);
name = profile.profileName;
break;
}
}
});
return name;
}
public void CreateProfile(string profileName, string applicationName = null)
{
DrsSession((hSession) =>
@@ -541,7 +588,7 @@ namespace nspector.Common
foreach (var settingId in settingIds)
{
var setting = ReadSetting(hSession, hProfile, settingId);
var setting = ReadSetting(hSession, hProfile, settingId, profileName);
if (setting != null)
result.Add(CreateSettingItem(setting.Value));
else
@@ -551,6 +598,29 @@ namespace nspector.Common
}
}
var isBaseProfile = profileName.Contains("Base Profile", StringComparison.OrdinalIgnoreCase);
if (isBaseProfile)
{
var hiddenSettings = HiddenSettings.Where(hs => !result.Any(s => s.SettingId == hs.settingId)).ToList();
foreach (var hiddenSetting in hiddenSettings)
{
var setting = ReadSetting(hSession, hProfile, hiddenSetting.settingId);
if (setting != null)
{
continue;
}
result.Add(CreateSettingItem(hiddenSetting));
}
}
else
{
result.RemoveAll(s => HiddenSettings.Any(hs => hs.settingId == s.SettingId));
}
if (skipApplications)
{
return null;
+28 -10
View File
@@ -63,6 +63,13 @@ namespace nspector.Common
}
else
{
if (profileName.Contains("Base Profile", StringComparison.OrdinalIgnoreCase))
{
var res = nvw.DRS_GetBaseProfile(hSession, ref hProfile);
return hProfile;
}
var nvRes = nvw.DRS_FindProfileByName(hSession, new StringBuilder(profileName), ref hProfile);
if (nvRes == NvAPI_Status.NVAPI_PROFILE_NOT_FOUND)
@@ -174,7 +181,7 @@ namespace nspector.Common
}
protected NVDRS_SETTING? ReadSetting(IntPtr hSession, IntPtr hProfile, uint settingId)
protected NVDRS_SETTING? ReadSetting(IntPtr hSession, IntPtr hProfile, uint settingId, string? profileName = null)
{
var newSetting = new NVDRS_SETTING()
{
@@ -190,8 +197,13 @@ namespace nspector.Common
if (decrypter != null)
{
var profile = GetProfileInfo(hSession, hProfile);
decrypter.DecryptSettingIfNeeded(profile.profileName, ref newSetting);
if (profileName == null)
{
var profile = GetProfileInfo(hSession, hProfile);
profileName = profile.profileName;
}
decrypter.DecryptSettingIfNeeded(profileName, ref newSetting);
}
return newSetting;
@@ -254,10 +266,13 @@ namespace nspector.Common
protected List<NVDRS_SETTING> GetProfileSettings(IntPtr hSession, IntPtr hProfile, NVDRS_PROFILE profile = default(NVDRS_PROFILE))
{
uint settingCount = 40;
var settings = new NVDRS_SETTING[settingCount];
settings[0].version = NvapiDrsWrapper.NVDRS_SETTING_VER;
var esRes = NvapiDrsWrapper.DRS_EnumSettings(hSession, hProfile, 0, ref settingCount, ref settings);
NVDRS_SETTING[] settings;
//var settings = new NVDRS_SETTING[settingCount];
//settings[0].version = NvapiDrsWrapper.NVDRS_SETTING_VER;
var esRes = NvapiDrsWrapper.DRS_EnumSettings(hSession, hProfile, 0, ref settingCount, out settings);
if (esRes == NvAPI_Status.NVAPI_END_ENUMERATION)
return new List<NVDRS_SETTING>();
@@ -282,11 +297,14 @@ namespace nspector.Common
protected List<NVDRS_APPLICATION_V3> GetProfileApplications(IntPtr hSession, IntPtr hProfile)
{
uint appCount = 512;
var apps = new NVDRS_APPLICATION_V3[512];
apps[0].version = NvapiDrsWrapper.NVDRS_APPLICATION_VER_V3;
uint appCount = 8;
var esRes = NvapiDrsWrapper.DRS_EnumApplications(hSession, hProfile, 0, ref appCount, ref apps);
NVDRS_APPLICATION_V3[] apps;
//var apps = new NVDRS_APPLICATION_V3[8];
//apps[0].version = NvapiDrsWrapper.NVDRS_APPLICATION_VER_V3;
var esRes = NvapiDrsWrapper.DRS_EnumApplications(hSession, hProfile, 0, ref appCount, out apps);
if (esRes == NvAPI_Status.NVAPI_END_ENUMERATION)
return new List<NVDRS_APPLICATION_V3>();
+33 -9
View File
@@ -489,6 +489,10 @@ namespace nspector.Native.NVAPI2
public delegate NvAPI_Status DRS_DestroySessionDelegate(IntPtr hSession);
public static readonly DRS_DestroySessionDelegate DRS_DestroySession;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate NvAPI_Status DRS_DecryptSessionDelegate(IntPtr hSession);
public static readonly DRS_DecryptSessionDelegate DRS_DecryptSession;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate NvAPI_Status DRS_LoadSettingsDelegate(IntPtr hSession);
public static readonly DRS_LoadSettingsDelegate DRS_LoadSettings;
@@ -568,25 +572,39 @@ namespace nspector.Native.NVAPI2
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate NvAPI_Status DRS_EnumApplicationsDelegate(IntPtr hSession, IntPtr hProfile, uint startIndex, ref uint appCount, IntPtr pApplication);
private static readonly DRS_EnumApplicationsDelegate DRS_EnumApplicationsInternal;
public static NvAPI_Status DRS_EnumApplications<TDrsAppVersion>(IntPtr hSession, IntPtr hProfile, uint startIndex, ref uint appCount, ref TDrsAppVersion[] apps)
[ThreadStatic]
private static IntPtr pSettingsApps;
[ThreadStatic]
private static NVDRS_APPLICATION_V3[] drsApps;
public static NvAPI_Status DRS_EnumApplications(IntPtr hSession, IntPtr hProfile, uint startIndex, ref uint appCount, out NVDRS_APPLICATION_V3[] apps)
{
NvAPI_Status res;
IntPtr pSettings;
NativeArrayHelper.SetArrayData(apps, out pSettings);
//IntPtr pSettings;
if (pSettingsApps == IntPtr.Zero)
{
drsApps = new NVDRS_APPLICATION_V3[8];
drsApps[0].version = NvapiDrsWrapper.NVDRS_APPLICATION_VER_V3;
NativeArrayHelper.SetArrayData(drsApps, out pSettingsApps);
}
//NativeArrayHelper.SetArrayData(apps, out pSettingsApps);
try
{
res = DRS_EnumApplicationsInternal(hSession, hProfile, startIndex, ref appCount, pSettings);
apps = NativeArrayHelper.GetArrayData<TDrsAppVersion>(pSettings, (int)appCount);
res = DRS_EnumApplicationsInternal(hSession, hProfile, startIndex, ref appCount, pSettingsApps);
apps = NativeArrayHelper.GetArrayData<NVDRS_APPLICATION_V3>(pSettingsApps, (int)appCount);
}
finally
{
Marshal.FreeHGlobal(pSettings);
//Marshal.FreeHGlobal(pSettings);
}
return res;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate NvAPI_Status DRS_FindApplicationByNameDelegate(IntPtr hSession, [MarshalAs(UnmanagedType.LPWStr, SizeConst = (int)NvapiDrsWrapper.NVAPI_UNICODE_STRING_MAX)] StringBuilder appName, ref IntPtr phProfile, ref NVDRS_APPLICATION_V3 pApplication);
public static readonly DRS_FindApplicationByNameDelegate DRS_FindApplicationByName;
@@ -616,14 +634,18 @@ namespace nspector.Native.NVAPI2
private static readonly DRS_EnumSettingsDelegate DRS_EnumSettingsInternal;
[ThreadStatic]
private static IntPtr pSettings;
[ThreadStatic]
private static NVDRS_SETTING[] drsSettings;
public static NvAPI_Status DRS_EnumSettings(IntPtr hSession, IntPtr hProfile, uint startIndex, ref uint settingsCount, ref NVDRS_SETTING[] settings)
public static NvAPI_Status DRS_EnumSettings(IntPtr hSession, IntPtr hProfile, uint startIndex, ref uint settingsCount, out NVDRS_SETTING[] settings)
{
NvAPI_Status res;
if (pSettings == IntPtr.Zero)
{
NativeArrayHelper.SetArrayData(settings, out pSettings);
drsSettings = new NVDRS_SETTING[settingsCount];
drsSettings[0].version = NvapiDrsWrapper.NVDRS_SETTING_VER;
NativeArrayHelper.SetArrayData(drsSettings, out pSettings);
}
try
{
@@ -769,6 +791,8 @@ namespace nspector.Native.NVAPI2
GetDelegate(0xFA5F6134, out DRS_RestoreProfileDefault);
GetDelegate(0x7DD5B261, out DRS_RestoreProfileDefaultSetting, 0x53F0381E);
GetDelegate(0xDA8466A0, out DRS_GetBaseProfile);
GetDelegate(0x8FC247B7, out DRS_DecryptSession);
#endregion
}
}
+3 -11
View File
@@ -11,16 +11,16 @@ namespace nspector.Native
public static T[] GetArrayData<T>(IntPtr sourcePointer, int itemCount)
{
var lstResult = new List<T>(itemCount);
var lstResult = new T[itemCount];
if (sourcePointer != IntPtr.Zero && itemCount > 0)
{
var sizeOfItem = Marshal.SizeOf(typeof(T));
for (int i = 0; i < itemCount; i++)
{
lstResult.Add(GetArrayItemData<T>(sourcePointer + (sizeOfItem * i)));
lstResult[i] = GetArrayItemData<T>(sourcePointer + (sizeOfItem * i));
}
}
return lstResult.ToArray();
return lstResult;
}
public static void SetArrayData<T>(T[] items, out IntPtr targetPointer)
@@ -54,13 +54,5 @@ namespace nspector.Native
targetPointer = IntPtr.Zero;
}
}
public static void SetArrayItemData<T>(T item, out IntPtr targetPointer)
{
var sizeOfItem = Marshal.SizeOf(typeof(T));
targetPointer = Marshal.AllocHGlobal(sizeOfItem);
Marshal.StructureToPtr(item, targetPointer, true);
}
}
}
+428 -461
View File
File diff suppressed because it is too large. Load diff
+29 -6
View File
@@ -19,6 +19,7 @@ namespace nspector
private List<SettingItem> _currentProfileSettingItems = new List<SettingItem>();
private static bool _alreadyScannedForPredefinedSettings = false;
private static object[] _baseProfileNames;
private IntPtr _taskbarParent = IntPtr.Zero;
private bool _activated = false;
private bool _isStartup = true;
@@ -173,15 +174,16 @@ namespace nspector
GC.Collect();
for (int i = 0; i < lvSettings.Items.Count; i++)
{
if (lvSettings.Items[i].Text == lvSelection)
var item = lvSettings.Items[i];
if (item.Text == lvSelection)
{
lvSettings.Items[i].Selected = true;
lvSettings.Items[i].EnsureVisible();
item.Selected = true;
item.EnsureVisible();
if (!cbProfiles.Focused)
{
lvSettings.Select();
cbValues.Text = lvSettings.Items[i].SubItems[1].Text;
cbValues.Text = item.SubItems[1].Text;
}
break;
}
@@ -193,12 +195,33 @@ namespace nspector
{
cbProfiles.Items.Clear();
var profileNames = _drs.GetProfileNames(ref _baseProfileName);
cbProfiles.Items.AddRange(profileNames.Cast<object>().ToArray());
if (_baseProfileNames != null)
{
cbProfiles.Items.AddRange(_baseProfileNames);
}
else
{
var profileNames = _drs.GetProfileNames(ref _baseProfileName);
_baseProfileNames = profileNames.Cast<object>().ToArray();
cbProfiles.Items.AddRange(_baseProfileNames);
}
cbProfiles.Sorted = true;
}
public void SetProfileByExecutable(string executable)
{
var profileName = _drs.GetProfileNameByApps(executable);
if (profileName != null)
{
cbProfiles.SelectedIndex = cbProfiles.Items.IndexOf(profileName);
return;
}
ShowCreateProfileDialog(Path.GetFileNameWithoutExtension(executable), executable);
}
private void MoveComboToItemAndFill()
{
if (lvSettings.SelectedItems.Count > 0)
+421 -248
View File
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
@@ -26,260 +26,433 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="ilListView.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>115, 17</value>
</metadata>
<data name="ilListView.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADI
DAAAAk1TRnQBSQFMAgEBBAEAAcABBwHAAQcBEAEAARABAAT/ARkBAAj/AUIBTQE2BwABNgMAASgDAAFA
AwABIAMAAQEBAAEYBgABGP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/ADMAAcgBvQGvAacBkQF5BgAD/iEA
A+QD2gYAA/4hAAGXAcMBqwFMAZwBcAYAA/4hAAOmA2gGAAP+FQAB8gHxAfABqQGPAXQBzwHHAbwD/wG6
AaUBjAGuAZQBeAHxAe8B7QHvAe0B6wGhAYgBbQHkAeAB2xIAA/UD3QPmA/8D4APeA/QD8wPaA+4SAAHt
AfIB7wE3AaEBZgGlAcwBtwP/AVgBsQGAATUBpgFoAekB8AHsAecB7wHqATwBlQFkAdQB4gHaEgAD7gNi
A7UD/wN6A2QD7APqA1oD2BIAAfMB8QHvAbwBoQGGAb4BogGHAb4BpQGIAbsBogGFAbwBogGEAagBlQGB
Aa0BlgF/Aa4BkgF3AegB5QHhEgAD9QnjBuIJ3gPwEgAB6wHyAe4BOgG1AXEBPAG2AXQBPgG3AXMBOgG1
AXEBOgG1AXEBNwGmAWoBOAGoAWsBNAGkAWcB2QHnAd8SAAPuA3MDdgN0A3EDbwNxA20DZAPeDAAB9AHz
AfIB7wHsAekB6AHiAdwByQGyAZcB0wHCAa4BzgG8AaYBzAG6AaUBzAG5AaMBywG3AaIBygG3AaIBvgGn
AY8BxgG1AaMB5AHgAdsB4wHeAdoD/wMAA/YD8wPvA+cD7AbqCekG5AbuA/8DAAHvAfQB8QHiAe4B5wHM
AeYB1wFCAcMBfAFUAckBiQFOAccBhQFLAcYBggFLAcYBggFJAcUBgQFJAcUBgQE8AbsBdQF7Ab8BmgHT
AeIB2gHTAeAB2QP/AwAD8QPnA9cDhAOgA5cDlgmTA34DlgPYA9cD/wMAAcYBswGdAb4BqAGPAcwBtQGa
AdMBvwGrAdUBxQGyAccBsAGXAcMBrAGNAb8BpgGMAb8BpwGMAcUBrwGXAcYBswGdAbsBowGJAaIBiwFx
AY0BcwFXAeEB3QHYAwAD5QPkA+gD7APtA+cD5APiA+QG5wPjA9sD1APtAwABXQHCAYoBPAG7AXUBSAHE
AYEBVAHJAYkBWAHKAYsBQgHDAXwBQAG+AXgBQAG5AXYBOwG5AXQBQAHCAXsBQwHDAX0BOgG2AXIBMQGb
AWEBLAGAAVEB0QHeAdcDAAOOA30DhwOdA6UDhQN3A3gDeQOGA40DdwNfA0MD1QMAAekB5AHeAcYBrgGU
AdUBxAGtAc0BuQGlAcoBsAGYAeUB3gHXAfgB9wH2A/oB6AHiAdwBwQGpAY4BwAGoAY4BxAGuAZUBsQGZ
AYABzwHGAb0D+wMAA+8D5gPsA+oD5gPtA/kD+wPvBuQD5gPgA+cD/AMAAc4B5wHaAUABwgF8AVUByQGJ
AUwBxgGDAUcBxAF/AcMB4wHRAfQB9wH2AfkC+gHOAeYB2QFFAbkBeQE8AbwBdgE9AcEBeQE3AawBbAGt
AcsBuwH6AvsDAAPZA4IDnQOXA4YD0QP2A/oD2AN6A3wDgwNuA7YD+wMAAfcB9gH1AcgBsAGVAd4BzAG2
AcsBtQGcAdQByQG6DAAB4gHdAdoBtwGgAY4BwwGwAaEBpQGSAYAB8AHuAewGAAP4A+cD7wboDAAD7gPj
A+gD3gPzBgAB8gH2AfQBQgHCAX0BYAHNAZEBRgHEAX8BmgHRAbMMAAHIAeMB1AE6AbYBcgFFAcQBfgE2
AaMBaAHnAe8B6gYAA/QDggOnA4oDsQwAA9gDgQOWA3ID6gMAAc0BuQGiAcsBtAGZAeMBzQG3AecB1gHD
AbsBoQGFA/oMAAP6Ab8BpgGMAcwBuQGjAbwBogGEAa4BlAF4AacBkQF5A+cD6APwA/ID4QP7DAAD+wPi
A+kD4gPeA9oBXgHJAY4BRQHEAX4BYwHOAZMBbAHQAZkBPAG0AXMB+QL6DAAB+QL6AUABuQF2AUsBxgGC
AToBtQFxATUBpgFoAUwBnAFwA5IDhgOnA7YDcwP5DAAD+gN4A5MDbwNkA2gB1wHJAbgBzwG4AaIB5gHR
Ab0B7AHbAcoBugGhAYUC+QH4DAAB+AH3AfYBwwGsAY0BzAG6AaUBuwGiAYUBugGlAYwByAG9Aa8D6QPn
A/ED9APhA/oMAAP5A+QD6gPiA+AD5AGKAdMBqwFXAccBigFoAc8BlgFyAdIBnQE8AbIBcAH4AfkB+AwA
AfQB9wH2AUABvgF4AUsBxgGCAToBtQFxAVgBsQGAAZcBwwGrA6wDkgOvA74DcQP4DAAD9gN3A5YDcQN6
A6YDAAP7AdwByQGzAewB3AHLAccBswGaAc4BxAG5DAAB5QHeAdcBxwGwAZcBzgG8AaYBvgGlAYgD/wYA
A/sD7QP0A+cD5QwAA+0D5wPqA+MD/wYAAfoC+wFeAcwBjwFyAdIBnQFCAcMBfAGoAckBtgwAAcMB4wHR
AUIBwwF8AU4BxwGFAT4BtwFzA/8GAAP7A6MDvwOIA7IMAAPRA4UDlwN0A/8GAAHxAe8B7AHZAcQBrQHv
Ad8BzgHfAc0BuwG2AaEBhQHOAcQBuQL5AfgD+gHUAckBugHKAbABmAHVAcUBsgHTAcIBrgG+AaIBhwHP
AccBvAYAA/QD7QP1A/AD4QPlA/oD+wPoA+YD7QPsA+MD5gYAAeUB8QHqAVkBygGNAXcB1AGhAWMBzgGT
ATwBsQFwAagByQG2AfgB+QH4AfkC+gGaAdEBswFHAcQBfwFYAcoBiwFUAckBiQE8AbYBdAGlAcwBtwYA
A+oDmwPCA64DcQOyA/gD+QOxA4YDpQOgA3YDtQYAAdYBxgGyAdABuAGdAdsBxQGwAfIB4gHSAeABzwG8
AccBswGaAboBoQGFAbsBoQGFAcsBtQGcAc0BuQGlAdMBvwGrAckBsgGXAbwBoQGGAakBjwF0BgAD6APp
A+wD9gPwA+cG4QPoA+oD7APnA+MD3QYAAXsB0QGhAUkBxQGBAV0BywGOAXsB1QGkAWQBzgGUAUIBwwF8
ATwBsgFwATwBtAFzAUYBxAF/AUwBxgGDAVQByQGJAUIBwwF8AToBtQFxATcBoQFmBgADowOKA6ADxwOv
A4gDcQNzA4oDlwOdA4QDcwNiBgAB8wHxAe8B8AHtAeoB8QHuAesB4gHOAboB7gHfAc0B7AHcAcsB7AHb
AcoB5wHWAcMB3gHMAbYB1QHEAa0BzAG1AZoB6AHiAdwB8wHxAe8B8gHxAfAGAAP1A/ID8wPwA/UG9APy
A+8D7APoA+8G9QYAAeoB8wHuAeEB7wHnAeMB8AHoAWQBzgGUAXUB0wGfAXIB0gGdAXIB0gGdAWwB0AGZ
AWABzQGRAVUByQGJAUgBxAGBAcwB5gHXAesB8gHuAe0B8gHvBgAD7gPoA+kDrAPAA78DvgO2A6cDnQOH
A9cG7gwAAfQB8wHxAdUBwAGnAdkBwwGqAdwByQGzAeYB0QG9AeMBzQG3AcgBsAGVAcYBrgGUAb4BqAGP
Ae8B7AHpEgAD9gPrA+wD7QPxA/AD5wPmA+QD8xIAAe0B9AHwAVIByAGHAVcByQGJAV4BzAGPAWgBzwGW
AWMBzgGTAUIBwgF9AUABwgF8ATwBuwF1AeIB7gHnEgAD8AOVA5gDowOvA6cGggN9A+cSAAH1AfQB8gHQ
Ab0BpAHgAdYBzAP7Ac8BuAGiAcsBtAGZAfcB9gH1AekB5AHeAcYBswGdAfQB8wHyEgAD9gPpA+sD+wPn
A+gD+APvA+UD9hIAAe4B9QHxAVsByQGNAasB3QHCAfoC+wFXAccBigFFAcQBfgHyAfYB9AHOAecB2gFd
AcIBigHvAfQB8RIAA/EDkgPEA/sDkgOGA/QD2QOOA/EVAAH9AvwD/gMAAdcByQG4Ac0BuQGiIQAD/QP+
AwAD6QPnIQAD/AP+AwABigHTAasBXgHJAY4hAAP8A/4DAAOsA5IVAAFCAU0BPgcAAT4DAAEoAwABQAMA
ASADAAEBAQABAQYAAQEWAAP/gQAB/gFvAf4BbwH+AW8B/gFvAeABBwHgAQcB4AEHAeABBwHgAQcB4AEH
AeABBwHgAQcBgAEAAYABAAGAAQABgAEAAYABAAGAAQABgAEAAYABAAGAAQABgAEAAYABAAGAAQABgwHB
AYMBwQGDAcEBgwHBAQMBwAEDAcABAwHAAQMBwAEDAcABAwHAAQMBwAEDAcABgwHBAYMBwQGDAcEBgwHB
AYABAQGAAQEBgAEBAYABAQGAAQEBgAEBAYABAQGAAQEBgAEBAYABAQGAAQEBgAEBAeABBwHgAQcB4AEH
AeABBwHgAQcB4AEHAeABBwHgAQcB8gF/AfIBfwHyAX8B8gF/Cw==
</value>
</data>
<metadata name="pbMain.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="tsMain.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>217, 17</value>
</metadata>
<metadata name="tsMain.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="tsbRefreshProfile.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGgSURBVDhPrZPLSsNAFIb7BoKP4Upw5UoQBHfmMrG1olCa
pFoExY2KiHcRERFEwYUKglSQesFeQK2rFkFr0Y26MRAKpa2+QS+/MzGpaS114wdhQv7/nDknZ8bx7xDi
a+FFeYvnFU2QFHCcRxdEOcQTmTctjWHB4UgM2Wwe5XIZ+fwnko/PWF3bhiAqJzRRp2mtD0/U7oWlTbAK
Bj1jYO/vmo5SqYR44gG9fcPgiNpu2uvDkrCVEG+zIMkqcfqQuEuiWCwidhsHJ8qHhtEOLX2H9cxW81MF
nni7XP1+5PIfKBQKmJlbR1UrVnAul0O9JJa+fxAwPJehqx+fPdh6apPU6nZfY9Gk4SaWGDwN09FlsUfL
rIg2LB/z/NI5SW4bHZ9FJpPBy+sbnG4//Unfk7BjJalNbsBGEzwLIZ1OIxK9AXGqdCdZlSS1iel/HiB2
OCTXEM4vItB1nc79HpPTK3APjBiHamJquXp09eCI0sGJyvH84gat4hqp1BM0TUMymcJRIEhLV3ZNa2ME
4nXSCxQ1LhLrmVbAgnskudW0/BcOxxdQeE7WHAMG/AAAAABJRU5ErkJggg==
</value>
</data>
<data name="tsbRestoreProfile.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFcSURBVDhP3VFNK0RhFL4/wNbM3PdcCgsfsbHDgkJKWPgD
ilJGNN73XEs/gbKUmvITuPc9d5iwYKfZyULZ26BkhTjnnXs1TWTNqafOx/M895z3ev84FsrwigQfvyGl
1yNM1IyO4cQNrUKdqGFj1awmuGgWZnDC9Wouz8U1xnATkj+oE78HLVyWKPeAlH9EUkOa1FyzWOAxeVIS
JuxtRoVeERhS51zviLlsIHNjYRltW1ejWOChDdbqhEIfRoVbE0PZbXXoP3G/ygZFNyeYZ4xlwgzC9fAI
7rmomUrQL01TyXekPUfSVo3zSSVXW3Ug75PNnEEpau+Uglff5XsnOH9D8reZuBJamOa6JvPQqkXhF89a
W9jw+MtAIiTVjRE88+AKY3/E5fKVGO74jC3hbMTBAPf2XT+FEzcGb7BqrH/KWNIUTLk34LX5V740Cn80
yGKU4P07QTNS+t8Nz/sEkToIpLSWKNoAAAAASUVORK5CYII=
</value>
</data>
<data name="tsbCreateProfile.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEgSURBVDhP3Y/PKwRhHIf3f5g/wMWUlIuDUk5y5MCB3Dk4
7EUbBwdXJ3EXsksjidlk2x27NrXt5kdjlTQXbSFK2iaGaX7s491Zjppx5FNP7/et9/n0fmP/PFwu8JGd
5OsaLdxpNIyVQPL1GcyDwWDmVsEx1sLLGvdHeLtduKVh/GIPTlbGPRvF3mmjXm0Vh8a9SEBGAl1gCMoS
j2p/uOyX5/AK4/i5bqgI8UrQPFUJO9mOr43gHk/9XOToy9QLCd4O+yAvxCb7gg0JK9WJqcWxTubDf+Kd
x0ERYkqwLliVeE8PRNufWhpnUxY7j2Fu92IlO3jOT+AqMk+lxfAS+6HI6/VW8NA5neVlb6g11zLcVNRo
v/gO1SXM3PTvpL+WWOwT04jC5H73kgIAAAAASUVORK5CYII=
</value>
</data>
<metadata name="btnResetValue.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="lblApplications.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<data name="toolStripButton5.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
TgDQASA1MVpwzwAAAABJRU5ErkJggg==
</value>
</data>
<data name="toolStripButton6.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
TgDQASA1MVpwzwAAAABJRU5ErkJggg==
</value>
</data>
<metadata name="ilCombo.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="cbValues.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="lblWidth96.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="lblWidth330.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="lblWidth16.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="lblWidth30.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="ilListView.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>115, 17</value>
</metadata>
<data name="ilListView.ImageStream" mimetype="application/x-microsoft.net.object.binary.base64">
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAyAwAAAJNU0Z0AUkBTAIBAQQB
AAHIAQcByAEHARABAAEQAQAE/wEZAQAI/wFCAU0BNgcAATYDAAEoAwABQAMAASADAAEBAQABGAYAARj/
AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wAzAAHIAb0BrwGnAZEBeQYAA/4hAAPkA9oGAAP+IQABlwHDAasB
TAGcAXAGAAP+IQADpgNoBgAD/hUAAfIB8QHwAakBjwF0Ac8BxwG8A/8BugGlAYwBrgGUAXgB8QHvAe0B
7wHtAesBoQGIAW0B5AHgAdsSAAP1A90D5gP/A+AD3gP0A/MD2gPuEgAB7QHyAe8BNwGhAWYBpQHMAbcD
/wFYAbEBgAE1AaYBaAHpAfAB7AHnAe8B6gE8AZUBZAHUAeIB2hIAA+4DYgO1A/8DegNkA+wD6gNaA9gS
AAHzAfEB7wG8AaEBhgG+AaIBhwG+AaUBiAG7AaIBhQG8AaIBhAGoAZUBgQGtAZYBfwGuAZIBdwHoAeUB
4RIAA/UJ4wbiCd4D8BIAAesB8gHuAToBtQFxATwBtgF0AT4BtwFzAToBtQFxAToBtQFxATcBpgFqATgB
qAFrATQBpAFnAdkB5wHfEgAD7gNzA3YDdANxA28DcQNtA2QD3gwAAfQB8wHyAe8B7AHpAegB4gHcAckB
sgGXAdMBwgGuAc4BvAGmAcwBugGlAcwBuQGjAcsBtwGiAcoBtwGiAb4BpwGPAcYBtQGjAeQB4AHbAeMB
3gHaA/8DAAP2A/MD7wPnA+wG6gnpBuQG7gP/AwAB7wH0AfEB4gHuAecBzAHmAdcBQgHDAXwBVAHJAYkB
TgHHAYUBSwHGAYIBSwHGAYIBSQHFAYEBSQHFAYEBPAG7AXUBewG/AZoB0wHiAdoB0wHgAdkD/wMAA/ED
5wPXA4QDoAOXA5YJkwN+A5YD2APXA/8DAAHGAbMBnQG+AagBjwHMAbUBmgHTAb8BqwHVAcUBsgHHAbAB
lwHDAawBjQG/AaYBjAG/AacBjAHFAa8BlwHGAbMBnQG7AaMBiQGiAYsBcQGNAXMBVwHhAd0B2AMAA+UD
5APoA+wD7QPnA+QD4gPkBucD4wPbA9QD7QMAAV0BwgGKATwBuwF1AUgBxAGBAVQByQGJAVgBygGLAUIB
wwF8AUABvgF4AUABuQF2ATsBuQF0AUABwgF7AUMBwwF9AToBtgFyATEBmwFhASwBgAFRAdEB3gHXAwAD
jgN9A4cDnQOlA4UDdwN4A3kDhgONA3cDXwNDA9UDAAHpAeQB3gHGAa4BlAHVAcQBrQHNAbkBpQHKAbAB
mAHlAd4B1wH4AfcB9gP6AegB4gHcAcEBqQGOAcABqAGOAcQBrgGVAbEBmQGAAc8BxgG9A/sDAAPvA+YD
7APqA+YD7QP5A/sD7wbkA+YD4APnA/wDAAHOAecB2gFAAcIBfAFVAckBiQFMAcYBgwFHAcQBfwHDAeMB
0QH0AfcB9gH5AvoBzgHmAdkBRQG5AXkBPAG8AXYBPQHBAXkBNwGsAWwBrQHLAbsB+gL7AwAD2QOCA50D
lwOGA9ED9gP6A9gDegN8A4MDbgO2A/sDAAH3AfYB9QHIAbABlQHeAcwBtgHLAbUBnAHUAckBugwAAeIB
3QHaAbcBoAGOAcMBsAGhAaUBkgGAAfAB7gHsBgAD+APnA+8G6AwAA+4D4wPoA94D8wYAAfIB9gH0AUIB
wgF9AWABzQGRAUYBxAF/AZoB0QGzDAAByAHjAdQBOgG2AXIBRQHEAX4BNgGjAWgB5wHvAeoGAAP0A4ID
pwOKA7EMAAPYA4EDlgNyA+oDAAHNAbkBogHLAbQBmQHjAc0BtwHnAdYBwwG7AaEBhQP6DAAD+gG/AaYB
jAHMAbkBowG8AaIBhAGuAZQBeAGnAZEBeQPnA+gD8APyA+ED+wwAA/sD4gPpA+ID3gPaAV4ByQGOAUUB
xAF+AWMBzgGTAWwB0AGZATwBtAFzAfkC+gwAAfkC+gFAAbkBdgFLAcYBggE6AbUBcQE1AaYBaAFMAZwB
cAOSA4YDpwO2A3MD+QwAA/oDeAOTA28DZANoAdcByQG4Ac8BuAGiAeYB0QG9AewB2wHKAboBoQGFAvkB
+AwAAfgB9wH2AcMBrAGNAcwBugGlAbsBogGFAboBpQGMAcgBvQGvA+kD5wPxA/QD4QP6DAAD+QPkA+oD
4gPgA+QBigHTAasBVwHHAYoBaAHPAZYBcgHSAZ0BPAGyAXAB+AH5AfgMAAH0AfcB9gFAAb4BeAFLAcYB
ggE6AbUBcQFYAbEBgAGXAcMBqwOsA5IDrwO+A3ED+AwAA/YDdwOWA3EDegOmAwAD+wHcAckBswHsAdwB
ywHHAbMBmgHOAcQBuQwAAeUB3gHXAccBsAGXAc4BvAGmAb4BpQGIA/8GAAP7A+0D9APnA+UMAAPtA+cD
6gPjA/8GAAH6AvsBXgHMAY8BcgHSAZ0BQgHDAXwBqAHJAbYMAAHDAeMB0QFCAcMBfAFOAccBhQE+AbcB
cwP/BgAD+wOjA78DiAOyDAAD0QOFA5cDdAP/BgAB8QHvAewB2QHEAa0B7wHfAc4B3wHNAbsBtgGhAYUB
zgHEAbkC+QH4A/oB1AHJAboBygGwAZgB1QHFAbIB0wHCAa4BvgGiAYcBzwHHAbwGAAP0A+0D9QPwA+ED
5QP6A/sD6APmA+0D7APjA+YGAAHlAfEB6gFZAcoBjQF3AdQBoQFjAc4BkwE8AbEBcAGoAckBtgH4AfkB
+AH5AvoBmgHRAbMBRwHEAX8BWAHKAYsBVAHJAYkBPAG2AXQBpQHMAbcGAAPqA5sDwgOuA3EDsgP4A/kD
sQOGA6UDoAN2A7UGAAHWAcYBsgHQAbgBnQHbAcUBsAHyAeIB0gHgAc8BvAHHAbMBmgG6AaEBhQG7AaEB
hQHLAbUBnAHNAbkBpQHTAb8BqwHJAbIBlwG8AaEBhgGpAY8BdAYAA+gD6QPsA/YD8APnBuED6APqA+wD
5wPjA90GAAF7AdEBoQFJAcUBgQFdAcsBjgF7AdUBpAFkAc4BlAFCAcMBfAE8AbIBcAE8AbQBcwFGAcQB
fwFMAcYBgwFUAckBiQFCAcMBfAE6AbUBcQE3AaEBZgYAA6MDigOgA8cDrwOIA3EDcwOKA5cDnQOEA3MD
YgYAAfMB8QHvAfAB7QHqAfEB7gHrAeIBzgG6Ae4B3wHNAewB3AHLAewB2wHKAecB1gHDAd4BzAG2AdUB
xAGtAcwBtQGaAegB4gHcAfMB8QHvAfIB8QHwBgAD9QPyA/MD8AP1BvQD8gPvA+wD6APvBvUGAAHqAfMB
7gHhAe8B5wHjAfAB6AFkAc4BlAF1AdMBnwFyAdIBnQFyAdIBnQFsAdABmQFgAc0BkQFVAckBiQFIAcQB
gQHMAeYB1wHrAfIB7gHtAfIB7wYAA+4D6APpA6wDwAO/A74DtgOnA50DhwPXBu4MAAH0AfMB8QHVAcAB
pwHZAcMBqgHcAckBswHmAdEBvQHjAc0BtwHIAbABlQHGAa4BlAG+AagBjwHvAewB6RIAA/YD6wPsA+0D
8QPwA+cD5gPkA/MSAAHtAfQB8AFSAcgBhwFXAckBiQFeAcwBjwFoAc8BlgFjAc4BkwFCAcIBfQFAAcIB
fAE8AbsBdQHiAe4B5xIAA/ADlQOYA6MDrwOnBoIDfQPnEgAB9QH0AfIB0AG9AaQB4AHWAcwD+wHPAbgB
ogHLAbQBmQH3AfYB9QHpAeQB3gHGAbMBnQH0AfMB8hIAA/YD6QPrA/sD5wPoA/gD7wPlA/YSAAHuAfUB
8QFbAckBjQGrAd0BwgH6AvsBVwHHAYoBRQHEAX4B8gH2AfQBzgHnAdoBXQHCAYoB7wH0AfESAAPxA5ID
xAP7A5IDhgP0A9kDjgPxFQAB/QL8A/4DAAHXAckBuAHNAbkBoiEAA/0D/gMAA+kD5yEAA/wD/gMAAYoB
0wGrAV4ByQGOIQAD/AP+AwADrAOSFQABQgFNAT4HAAE+AwABKAMAAUADAAEgAwABAQEAAQEGAAEBFgAD
/4EAAf4BbwH+AW8B/gFvAf4BbwHgAQcB4AEHAeABBwHgAQcB4AEHAeABBwHgAQcB4AEHAYABAAGAAQAB
gAEAAYABAAGAAQABgAEAAYABAAGAAQABgAEAAYABAAGAAQABgAEAAYMBwQGDAcEBgwHBAYMBwQEDAcAB
AwHAAQMBwAEDAcABAwHAAQMBwAEDAcABAwHAAYMBwQGDAcEBgwHBAYMBwQGAAQEBgAEBAYABAQGAAQEB
gAEBAYABAQGAAQEBgAEBAYABAQGAAQEBgAEBAYABAQHgAQcB4AEHAeABBwHgAQcB4AEHAeABBwHgAQcB
4AEHAfIBfwHyAX8B8gF/AfIBfws=
</value>
</data>
<metadata name="pbMain.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="tsMain.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>217, 17</value>
</metadata>
<metadata name="tsMain.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="tsMain.BackgroundImage" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAAANklEQVQ4T6XIsREAIAADIfdf
Oi5A4Z8FDWfbF2bBLJgFs2AWzIJZMAtmwSyYBbNgFsyC+W7nAsWt/R/ojsvuAAAAAElFTkSuQmCC
</value>
</data>
<data name="tsbModifiedProfiles.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAKzSURBVDhPrZJJTBNhGIbnoCHehHgwJsREOGiILYsxBBE1
YPCIshVjAInRYliCW0BpFcUom1BRWhYRkB0UgxGNZWdmqgW0hZIuyAgUhTCF0FJEBXltYTwJXvRNvtv3
PHm/Pz/x32KId3Vgzrt/UYW4sMqw3SnKcDdnMspvkIoJYGkB/zi3tnFWcry3WNP80RPqjDp/x6dUuGe5
vvoejF0NIE/56CkBz4NbXT8tx1wdFCd2zubv24wsn+0r43V5oCvvol16FcMvikFH+mopwZ6/SzQCl5Le
EB4MVdmgqjKglVeAUTShp/Qm9M9lUMQcGqKCN5CQAo8dVJBbv7YyC3RNJjSvH8MyOQTzhBofu2pBVqRD
1yQFHXNY0xPmxuewtdjv6wrhyXXVOau17fDCtB6LM8NYmBrEHEPDIC9bk9ia0KcPasmTfHcOtwmi/HSG
2lxQFbehb32CpTkGPy2jq/D8eC8Wx0hYDXKMyIvRXZoGQ3MRyGg/LYcThErIC+7MjZseVzZDp9Ui+kwC
jgSGQtneBPNYHzyDkrHr6AVkZmTBRBahsygVqnO8SA4niIHYvY7dkmhm5eskhrQGxF2+gwMBEehoLoPF
JvCKKMDWABlE6YVYVpWAKk2EJsnbicMJoqPw7LYOqZD5YR7D1OcJSPJlSLwkxoDtD3wz0sgrLgCx/wGu
iB9iqa8AdGkC7AyH/xbEMlbbq3+fGQGso8ACA4vhDUy6Nggu3gLBlyAhJQ/LvfdBP1pPIBMy88b3MH+i
MatrhUndDFN/PYzqdhBeeSB42YhPzsaSXbBeg06ZcNQy+hbm4S7MDr2C6cMzsO8qMaFuw6bAMhC+5Ui8
LsWyUvKngK5LciKrk/vpxhss3Shm6QbR2tSnslSDmG0pF7Evy0RsW2Uqq6i/xpI1Kayd4fB/CUH8AppD
2GmutIMCAAAAAElFTkSuQmCC
</value>
</data>
<data name="tsbRefreshProfile.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGgSURBVDhPrZPLSsNAFIb7BoKP4Upw5UoQBHfmMrG1olCa
pFoExY2KiHcRERFEwYUKglSQesFeQK2rFkFr0Y26MRAKpa2+QS+/MzGpaS114wdhQv7/nDknZ8bx7xDi
a+FFeYvnFU2QFHCcRxdEOcQTmTctjWHB4UgM2Wwe5XIZ+fwnko/PWF3bhiAqJzRRp2mtD0/U7oWlTbAK
Bj1jYO/vmo5SqYR44gG9fcPgiNpu2uvDkrCVEG+zIMkqcfqQuEuiWCwidhsHJ8qHhtEOLX2H9cxW81MF
nni7XP1+5PIfKBQKmJlbR1UrVnAul0O9JJa+fxAwPJehqx+fPdh6apPU6nZfY9Gk4SaWGDwN09FlsUfL
rIg2LB/z/NI5SW4bHZ9FJpPBy+sbnG4//Unfk7BjJalNbsBGEzwLIZ1OIxK9AXGqdCdZlSS1iel/HiB2
OCTXEM4vItB1nc79HpPTK3APjBiHamJquXp09eCI0sGJyvH84gat4hqp1BM0TUMymcJRIEhLV3ZNa2ME
4nXSCxQ1LhLrmVbAgnskudW0/BcOxxdQeE7WHAMG/AAAAABJRU5ErkJggg==
</value>
</data>
<data name="tsbRestoreProfile.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFcSURBVDhP3VFNK0RhFL4/wNbM3PdcCgsfsbHDgkJKWPgD
ilJGNN73XEs/gbKUmvITuPc9d5iwYKfZyULZ26BkhTjnnXs1TWTNqafOx/M895z3ev84FsrwigQfvyGl
1yNM1IyO4cQNrUKdqGFj1awmuGgWZnDC9Wouz8U1xnATkj+oE78HLVyWKPeAlH9EUkOa1FyzWOAxeVIS
JuxtRoVeERhS51zviLlsIHNjYRltW1ejWOChDdbqhEIfRoVbE0PZbXXoP3G/ygZFNyeYZ4xlwgzC9fAI
7rmomUrQL01TyXekPUfSVo3zSSVXW3Ug75PNnEEpau+Uglff5XsnOH9D8reZuBJamOa6JvPQqkXhF89a
W9jw+MtAIiTVjRE88+AKY3/E5fKVGO74jC3hbMTBAPf2XT+FEzcGb7BqrH/KWNIUTLk34LX5V740Cn80
yGKU4P07QTNS+t8Nz/sEkToIpLSWKNoAAAAASUVORK5CYII=
</value>
</data>
<data name="tsbCreateProfile.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAEgSURBVDhP3Y/PKwRhHIf3f5g/wMWUlIuDUk5y5MCB3Dk4
7EUbBwdXJ3EXsksjidlk2x27NrXt5kdjlTQXbSFK2iaGaX7s491Zjppx5FNP7/et9/n0fmP/PFwu8JGd
5OsaLdxpNIyVQPL1GcyDwWDmVsEx1sLLGvdHeLtduKVh/GIPTlbGPRvF3mmjXm0Vh8a9SEBGAl1gCMoS
j2p/uOyX5/AK4/i5bqgI8UrQPFUJO9mOr43gHk/9XOToy9QLCd4O+yAvxCb7gg0JK9WJqcWxTubDf+Kd
x0ERYkqwLliVeE8PRNufWhpnUxY7j2Fu92IlO3jOT+AqMk+lxfAS+6HI6/VW8NA5neVlb6g11zLcVNRo
v/gO1SXM3PTvpL+WWOwT04jC5H73kgIAAAAASUVORK5CYII=
</value>
</data>
<data name="tsbDeleteProfile.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAFtSURBVDhP3ZJPSwJBGIfd2ZnddcWLiKC76sKgIHryQ/QZ
+h5FlhJGB79HBF09RIga5Z901xVTSKxYzEw2EIICDx6nKYYg1uxcD7yX5/3NvDPMuP4ZY4yXs1jMHicS
h0x98ZRIFKYYzx8jkSVTTugG9nM8TnqqagxTqfyHI/k8mCSTB1Y02p1gTMaKYn+GVzGjk/uK0u6EQsTU
tKtxOp29CYc3hsFg26LOUpTmNBp1nO4btxhnTZ+v8aBpbyO/v0vLvA+FFnc+X32iKLssth5LVbevvd5u
SxCIiRAZeDx9KxDYYu3fGcjyniFJvZYoEp2WIYr9oSxnWHs9uiTtVwAwmhAumqLYaQhC+5LnX8oANHqS
lGOx1egIFejiToXjSJnjLnQIM20Id4ocVz0CgJwAoPfc7gKLO6kiNK/wPCkBUK9BmGXaVROEXJHnR8e0
16AZpp2UIFyeQWifI+R4qlMANul1XusI/fyR/iIu1ztb44EJFA1Z/gAAAABJRU5ErkJggg==
</value>
</data>
<data name="tsbAddApplication.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVDhPrZPNSwJRFMXvP9auqH27Fv0HQQRhFC00LCIk
RRRMWiguhJCiheAHagqpJOIXD4wyRgUNdYwCBY1O7zk65Bhk0YEfc2d499zDHR79j84+lskB/ArRo4p/
cGTmZ8E3NlE1cTW25sPSnzVgjE1RLDJkswx3dwzJJEMiwRCNMgSDDH4/mzXQqlqV4Xbfwum8QanUQbMJ
1GpApQKUy+PEqjQG/f4ALleST39BLNaE2RyAJA3mN7i+ziKdlhEIVHn9gHi8hlyujtdXoNtVkswYDIcK
3W4P5+cphEJ1XF09wOtlKBSeQVbiy+OYCO32Nwa9noLPl0I4XMXlZZk/n5DPN5DJ1ECnBEt/HXRMaLUA
Y1ZjIOIJrNYgb76Hx1PgsRvqVDohmN7WQAe81nP2Oaq4QaejYDD4eOwibLY4IpHSqFlMFs2H7VXsSSvY
qSyBdjQG4jcJ9PoL6HQe2O0hyPI76IgfNCpTRTPt8nqbs6kxEJv9iiQphrKsJBORdY+LoC1Co6HdwQ+X
aXR4MnWDlPepy/RnEX0CXRRDb0PokG0AAAAASUVORK5CYII=
</value>
</data>
<data name="tssbRemoveApplication.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHsSURBVDhPrZPfS1NhGMd33020ftyIpGAZbXVRLQtC6ia6
8R+oCd20uohgd104ZRiGMDMQzF/F7MfVjjBLs7PsWLPNk0PLHV7ZnNY2gtEohIqFQZ/OWWuwI8GKvvCF
l5f3+3me9+F9Lf9Hgz9OWwbgr2xkytI3BmLV+4RUgpT1m3otX51vFjYDhBAVjscFCwuC+XlBNCoIhwWK
IpBlweSk2AwwK5P5xOhohKGh52jaR3I5yGZhbQ0SiVLHZZkAhcKGHp7Tq68zM5Ojt/cJ6fRG9QBZjuuB
r8RiHxgfTyFJCUZGIn8G1D2A9afThE+eKlaPSgrywUO8C4b0e6fx+1/T0RHU5/KZVAqWl02Aqyq8qN0J
l48RafPy0HFUX+8n1NiIqmbp63uJz6fQ36+wsmIM3AS4FIYxmx3amlltroHz+wjXb0OdeMXwsEpXV4jO
zse43f5i+5pmArRMwdupZyj1W+GCnS9napi+eIVAYE4P3cXrncDjCeJ09hSrLy2ZAIPtd4g0WMFlA2cD
nN2NXGvl/ZtVkslvdHc/orX1Bi7XrWJ4cdEEuL/nALhtaId3MHukDlp2wTl93eQgn/81dWNwRutGOKY/
5wrAbNPxjLR9Cz7PbdrV79yzOwjstXF9LInVXzpsdsVn+mdZLD8BfTZF0/R8bMwAAAAASUVORK5CYII=
</value>
</data>
<data name="tsbExportProfiles.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIbSURBVDhPtdBfaFJRHAdwXzMW1EuswRa1go2psBg97WFv
4WQ6VnmZ7mEb6KhIyUww/2wKUTCFa21sqxWOkJYSERh7qOGF6aU1cdBLM2okXMk5piR48w9+03FAorX2
UB84L+d8v7/DOYL/RrnSenpkpXtdyYjS/UxzI9k+GM1ao3DgbfsXP2yYSA/jwptTi+ToYAaW2ziaH8IM
RvG4dBv9EUml53WTlBzv7/Jye9KRVqA2wJUbxEx5FDe5QXQ9a9oULxw/TGJ/NhSTsBQjLlsSvbiXuVQd
QmG2eBU9TAdED4/Ok9j+xC8azsqX2uBM9WFyZwT2rT7Yv1PoXDxRPrMglJDY72iaPjI+7hyeomffSZda
MPGtF/TOFbTOHULXg5NoudNQqq69/yIQCDyPxWI8wzCYnnuEzifHoHrfgbvZi2ieF+Dzp81KkktWgsEg
b7fbX5Jand/vL/M8D5ZlYTAYcGPsFq45x9A9KUJ4dQ1b29vIZrMIhULQarUVUqvz+Xx8PB5HIpFAsVgE
G2ExdX8avqc+bHzcQCQSgcPhgMlkgkqlKpFancvlWo1Go0ilUuA4DplMBoVCAbWhHo9nt2i1WqHX66FU
Kj+Q2q90Op3e6/X+yOVyyOfzqDEajbDZbLBYLFCr1TxFUddJfG8ymUxYvS0YDocrtQFms3n3zdVbX2k0
GiGJ/Z1UKj3vdrs5uVz+VaFQnCPb/5pA8BMNdy5aS5fTsQAAAABJRU5ErkJggg==
</value>
</data>
<data name="tsbImportProfiles.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIkSURBVDhPtdJdaJJRGAfw142IWd1FrUW7aNFF1GoF1cU2
6iIqs2mL0KUE3Sh2kYaJbfmFg1aQBkZrtYikkppWFtnHRqCUChviRUSbEDWHLmdTwfCdluefjgMjtnIE
/W6f//M853AO818cG2Cqdw82pNoCTWzr64YPmx+veUpLi2RkqvZ6Nxat3zvwgHRiy6NVhFYq2/Bi5ZOd
Q/Ufm4fWF3um23Ezp0Dt3RrQcmXr3Ctcl1MS0vNVREzxw7gyfYJU32BQ1cdIl/QzO2jsrziNr1aP66MH
oIsehHnyCLk0JSbdk22kabAuWXOfc4Hm/ox7h3P96PCm4rnP+6Cf4OFiqp1sfVlbXHqLcTNgODS2MJOp
++Tou099h563FDon9sAY34965zLScrv5i1Vj3U5j87lcroFwOMz6fD70Xu1Fx9njaH1bh7UPlxPdm/Ng
v82QeCxOPB4PazQa3bRtjtPp/MmyLILBINRqNVSnzmCbrRGKfgVG/CNITiWRyWTg9Xohl8vnP6vD4WAj
kQii0SgKhQKCgSCulU7iuOfA2OgYAoEAzGYztFotJBLJD9o2x2KxDIdCISQSCcRiMaTTaeTzeZSH2my2
2Ua9Xg+VSgWRSPSetv1OqVSq7Hb7TDabRS6XQ5lGo4HBYIBOp4NUKmXFYvFpGl8Yn8/nlrZ5/H4/KQ/o
6uqavXNp6zOZTMalscp4PN4uq9UaEwgE40KhcFE/8B8wzC+qySa+SK8LKwAAAABJRU5ErkJggg==
</value>
</data>
<data name="tscbShowCustomSettingNamesOnly.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAJuSURBVDhPxY9NTNIBGIdta262TnXo2qpLh07ZlgfdtNVa
oumCFBlK+TXzE6Wc6fyHM2I6SKcYGpVkiqCZIhPTVAhCWyo5DaVIExIlnOlwoM38ZfTva6TXnvPzvPu9
fv8fjnxSlSc3Ibf5DdhN48h+NIashlFkSIeR/uAl0iSDSK3TI1msRaKoH5eqepFQoQZTqEJcebvaj1BM
+OfIxtWyQSt2wvxpDRML6zDav6BcOQZ6WVsHjVD4e1ew5YaATOlIT6N+Bs4VNxzLbtg/e2Bd8mDa6cGo
xYF6RScKinnILuKDVSp9+iv+yfcjW3P7Hmrf/Y4X12Cyu9DVO4Bb3ELkpKfhXDgF8fGssq1k14/yD9gC
Q0DSHY1G0jfpjb2zZ50wa+Ww9YmhEeci4nQwAk+GPKNQKHvI7G+oW0cSKrt1Nd0T3p9HpmbxoqUCZpUQ
WnEWChjBuBBFaSMIYjeZ+EKrVuxlCTvxcWUDPcYPkFXmryvLE6Hg0nHzcvAqIzqSSqrbE8NrgXV5A+3G
BXCKuHMCVuC6MCUUV84ctkQxmftJbXuoJU2wu76ixbgI6g3JJDuBZuWE7sN1etBG9u0ngyEXM0NJ9d9E
F0sx79rEXd0YiHbDan2rZrOxNAlVCg3uDblQKjd6jhwPo5G6L5GFErx1uMFTPge/Ywb619MwOQHJkBuP
XzlQO2ADi2iwkLov4dfEw2evVg/HEnVLJa0mqPQWSLVzqBmw477GCkHnFDi1WpD69hw8GhQSlyfQiZoN
EPXaUKtfgqh/Hnzle6TwZG5S25mwiNgDMan552MzuI0MTpkuuUhkZuTwDYeOnTj1DdeVozI6609oAAAA
AElFTkSuQmCC
</value>
</data>
<data name="tscbShowScannedUnknownSettings.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAANWSURBVDhPdZNbTNJRHMf/bT70mFuvvbTWbd2xrYeeaj1X
W1msNYoUu9DNmgKCqEiW/iMuEmX8ESkFQf54QQVFILzQX1A0DStJMv0HZpartMzi1x+lFVt9trOzc/b7
nv3O5+wgv5FbiFN38G6mDO9JV9YTgJq6d97Suy8Xaa20RMm/AYAV8VnbPqizeEehPTD5wTkUAU1r/4wC
7wJRVVvmUuH/kNb3Hlc19VW3+McH/GMzYCVCUOsaBnNnEAzOQZCavR6Osr7yXGnNtkQkGYm5Z5ep80Ws
d/Q9KEyPFxn5KtFhOpN3TYi+VVaZobyyFq4L0XnWJe7+RCQZKU4cdQTImWZiFBh8lSiDcTIzT/bopdU/
MRaamlsMkp/ARox8F4rR4JGDB7cmYn9QNhAQv7OBajtHKM7hopphgTMmf/055n07+20uGJ2D3jezgPdN
w0VOoeumzp6TJLbU2LUDs/V9MHuCcIUjHOPVjZsE7hhvZOrHE4t/esHon4X6wOef9tA8yGs9iyKFNlls
aY3rYtx2XBhPhEKxLRoW4OFBzEXOtzydhcDEAvjCX8D35hOona9BLLmbLLbogZUm1jnOyMzex4VlClA5
SUAbn0Hb0AyEp7+BY5CkXiQ02TAQcaOWYPQ6XwxG11PgqxrenSvB1ib6QBCO0qI/yeZ9lOPEpMk7Drgv
uuijXsbQPhAanopxG8aBJVDU2i/k3+7X2XyQj7XaWSJsbyKOIOwS3XZBEcpSyBVQ1T4EjqEomDwjcKfO
ndcRie273zFWTqPRyou1djlmfQKFGhtkFVe+SsQRJIORscfaZF8ok6pi67bQcjV1LV87fM+hookYKZBg
1Vs3b5SlZ/J2laqbByrMbuDKDZ3HstE1S2HmCeYGS11TJPwqDKmpqTKOSPLwLL8MsrL5kHVNAMycm/4b
NS7pLb2rX4l3g8zohvNi9cKhCyUshMFgrHpYpQ+QEySkpaV5qPM2/S3WRAnT2fygptrGGnvgnqULuHct
nfRcWe7hSzd2I1iF1hEhI0Cn0yep8AFqLH2uOHGxeapGUqhuthVoWoEnNzZflegjZwoxTqIEQap1euBx
uZCSksKmliuXd5eJi2WLKzeybxu2U8bD2Wj16tNCbPMxjmL9cgWC/AIp/hYHsS2RwgAAAABJRU5ErkJg
gg==
</value>
</data>
<data name="tsbBitValueEditor.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGcSURBVDhPrZPpSwJRFMXn/y2ktGy3KNM00xapHn0IogKF
hIo2Iykpoxr6EFi0QUGRUkZ7aObJM+Pw1IIW+sHDYZhz7rn3PpV/w7ecUgdjafijz+iP3KM3nIJ3PgnP
zCXcoXN0BU/hmDyEfSwOkzWoFmQ6A6sPajzxjp+ye3RbasLKZPEEWD0DNi/yH10B+9fAUQo4vQXO7+RJ
p9OwDW6hIFcUxiYWh8DOJWDzCLT1CE3o6hNIPAE3L4DXL7RDg5aBmDRgz6TOJbCXBDq8As5eXUjBYz7g
6xvgHxLayWQyaPJFpQEHRozYjEnx3asufCsbTzabRUN3RBpw2oSxO316ZYpZzUAI/Zm/uVwOdc6wNOCq
CKOzZ/bLyoaIFBuQWvuCNOCeCYfG6uy5PHY5lrZZaeAM5PeXh71zaEb14qrlCaqaQtLAPn6gvfyNgcka
kAbto3vaSxoY/X9HpXlCGrSO7Kq8nrwgPNwzV8Vpf8X65jEqqidK/w+tw9sqr2dz/wYavWuod6/A6lhC
TfsczLZpVDVOabFZ+ZP47yjKB3q7lEPomoQ8AAAAAElFTkSuQmCC
</value>
</data>
<data name="tsbApplyProfile.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAKqSURBVDhPY8AGVFQY2DUdxM1NQqQiQFjDRcxCRoaBEyqN
H6jZi9pET9LfVL7P9m3dEdf/VYfs/mevMX8f0KixVdtZ3AGqDDuwTZAraT8R9H/yueT/7ScC/zcc9fhf
e9gZbAgIZ60y+28eKVsNVY4KLCJlUkAau0+F/2886vm//ojb/+pDDv+BLvlfstP6f8Emy/85a83BhhgF
SWVCtUGAvKmoRMVBm899p6P/Nx3zBtuKrDlvg8X/nDXm/ws2W/5PWWD8H+jFH3Im/EpQ7QwMdinyTRPP
JoA1Vx60BWsGaYRpzlhm+v/Sq33/v//+DHZJ4mzD/1Yxcu0M9gwsDFpaojzRk/QO9J6O+l+x3/b/qeeb
/r/8+gDsiqyVZmAnX3l98D8I3Hl/5n/8DMP/YZ06/93yVY4oW4iqMCibCMomzTG8BAo0kI0HHi0BK371
9SE44C6/PgDm33p36n/MJP3/wS1aYAM8S1Wuq1oImYH9HzlB7yzI+SAXgGzcfGfS/6+/Pvx/8+3x/y+/
3v+/+uYw2O8h7dpgHNal89+7TPWSsq2IEQPIH865ystAcV68wxpsQPI8o/8rrjf+f/r51v8zz7f+z1hu
CrYVpBHkgqgJev/t0xRXShrziIADUd1O2A8URaAAAvk7daHx/6S5Rv/nXioEi4E0RvTogm0PbNQEG6Dp
KBIG1gwFTA6pitthIQ5yLiikQX6O6tf7H9EL1Nym/T+gAaLZPllhLzgGkIGCoYC8a77yVZALQAbETTOA
aAbaDHJ2ULMW2ED3QtU7cnr8ilBtqAAUI+bh0suA/v2ZMNMQHGVxUw3AGkPatH5bRsusAlkEVY4TMCqY
Ctjpeog3mYXLLAZhPU/xFnljflBGYoIoIQJISkpyyRoKS8noC0mL64lzQ4XRAAMDAPInffz2odmOAAAA
AElFTkSuQmCC
</value>
</data>
<metadata name="btnResetValue.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<data name="btnResetValue.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAAA8AAAAJCAYAAADtj3ZXAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAAA50lEQVQoU3XRvSuGURgHYBY2
mUxvlMl/oRT1TiaTTFZ5SmHgjSxCIYXB4GMRJXaSQcmuDAwYRFE+BhJx3TyPPG8Zrjqdc36n+75PRZIk
f9XRwhJnnPL5nyxUSSezbKX6GWCEPcrDTxGsZ4oTxuhmgmV2mKbICh/kwkPpZhvrbLDIIA3ExXi0Nl3n
wq280MM2vXQRFy6Yp4NdorpD4uw563mcB9pZ44A5hpnhkk0KNHHHb7iKSW4pscoVx8RjzTQSVR3xynfZ
mWqihRjUAjG4PuIH9jknQrmey9UwyjU3PJJN+Z23H8n9FxjlApHDfpvMAAAAAElFTkSuQmCC
</value>
</data>
<metadata name="lblApplications.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<data name="toolStripButton5.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
TgDQASA1MVpwzwAAAABJRU5ErkJggg==
</value>
</data>
<data name="toolStripButton6.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
TgDQASA1MVpwzwAAAABJRU5ErkJggg==
</value>
</data>
<metadata name="ilCombo.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="cbValues.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="lblWidth96.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="lblWidth330.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="lblWidth16.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="lblWidth30.Locked" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
</root>
+12
View File
@@ -4971,5 +4971,17 @@
</SettingValues>
<SettingMasks />
</CustomSetting>
<CustomSetting>
<UserfriendlyName>DLSS/DLAA: Force DLAA</UserfriendlyName>
<HexSettingID>0x10E41DF4</HexSettingID>
<Description />
<GroupName>8 - Extra</GroupName>
</CustomSetting>
<CustomSetting>
<UserfriendlyName>DLSS/DLAA: Override Scale Ratio</UserfriendlyName>
<HexSettingID>0x10E41DF5</HexSettingID>
<Description />
<GroupName>8 - Extra</GroupName>
</CustomSetting>
</Settings>
</CustomSettingNames>
+18 -5
View File
@@ -1,12 +1,12 @@
using System;
using System.Linq;
using NvAPIWrapper.GPU;
using NvAPIWrapper.GPU;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.Display;
using NvAPIWrapper.Native.Display.Structures;
using NvAPIWrapper.Native.Exceptions;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.Interfaces.Display;
using System;
using System.Linq;
namespace NvAPIWrapper.Display
{
@@ -41,12 +41,25 @@ namespace NvAPIWrapper.Display
get => new DVCInformation(Handle);
}
private DisplayDevice _displayDevice;
/// <summary>
/// Gets corresponding DisplayDevice based on display name
/// </summary>
public DisplayDevice DisplayDevice
{
get => new DisplayDevice(Name);
get
{
if (_displayDevice == null)
{
_displayDevice = new DisplayDevice(Name);
}
return _displayDevice;
}
}
/// <summary>
@@ -189,7 +202,7 @@ namespace NvAPIWrapper.Display
return false;
}
return Equals((Display) obj);
return Equals((Display)obj);
}
/// <inheritdoc />
@@ -6,9 +6,9 @@ using System.ComponentModel;
namespace ColorControl.Shared.Common
{
public class AppContext
public class GlobalContext
{
public static AppContext CurrentContext { get; private set; }
public static GlobalContext CurrentContext { get; private set; }
public Config Config { get; private set; }
@@ -19,7 +19,7 @@ namespace ColorControl.Shared.Common
public DateTime StartTime { get; private set; } = DateTime.Now;
public string MutexId { get; private set; }
public AppContext(Config config, StartUpParams startUpParams, string dataPath, LoggingRule loggingRule, string mutexId = null)
public GlobalContext(Config config, StartUpParams startUpParams, string dataPath, LoggingRule loggingRule, string mutexId = null)
{
Config = config;
StartUpParams = startUpParams;
@@ -30,11 +30,6 @@ namespace ColorControl.Shared.Common
CurrentContext = this;
}
public bool IsServiceRunning()
{
return Utils.IsServiceRunning();
}
public void SetLogLevel(LogLevel logLevel)
{
Config.LogLevel = logLevel.ToString();
+10 -20
View File
@@ -7,11 +7,14 @@ namespace ColorControl.Shared.Common
{
public static class PipeUtils
{
public const string ServicePipe = "servicepipe";
public const string ElevatedPipe = "elevatedpipe";
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
public static string SendMessage(string message, int timeout = 2000)
public static string SendMessage(string message, int timeout = 2000, string pipeName = ServicePipe)
{
var pipeClient = new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut, PipeOptions.None, TokenImpersonationLevel.None);
var pipeClient = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.None, TokenImpersonationLevel.None);
try
{
pipeClient.Connect(timeout);
@@ -61,37 +64,24 @@ namespace ColorControl.Shared.Common
return SendMessage(message);
}
public static bool? SendRpcMessage(string command)
public static T SendRpcMessage<T>(SvcRpcMessage message, int timeout = 2000, string pipeName = ServicePipe)
{
var message = new SvcMessage { MessageType = SvcMessageType.ExecuteRpc, Data = command };
var messageJson = JsonConvert.SerializeObject(message);
var resultJson = SendMessage(messageJson);
var resultJson = SendMessage(messageJson, timeout, pipeName);
if (resultJson == null)
{
return null;
return default;
}
var resultMessage = JsonConvert.DeserializeObject<SvcResultMessage>(resultJson);
return resultMessage.Result;
}
public static T SendRpcMessage<T>(SvcRpcMessage message, int timeout = 2000) where T : class
{
var messageJson = JsonConvert.SerializeObject(message);
var resultJson = SendMessage(messageJson, timeout);
if (resultJson == null)
if (resultMessage?.Data == null)
{
return null;
return default;
}
var resultMessage = JsonConvert.DeserializeObject<SvcResultMessage>(resultJson);
var result = JsonConvert.DeserializeObject<T>(resultMessage.Data);
return result;
+3 -2
View File
@@ -1,4 +1,5 @@
using System.ComponentModel;
using ColorControl.Shared.Services;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using static ColorControl.Shared.Native.WinApi;
@@ -46,7 +47,7 @@ namespace ColorControl.Shared.Common
public static Process Parent(this Process process, IEnumerable<Process> processes = null)
{
if (Utils.IsAdministrator())
if (WinApiService.IsAdministratorStatic())
{
try
{
+1 -391
View File
@@ -1,7 +1,4 @@
using ColorControl.Shared.Contracts;
using ColorControl.Shared.Native;
using Microsoft.Win32;
using Microsoft.Win32.TaskScheduler;
using ColorControl.Shared.Native;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NStandard;
@@ -14,10 +11,7 @@ using System.IO.Compression;
using System.Net.Http;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Principal;
using System.ServiceProcess;
using System.Text;
using Windows.Devices.Enumeration;
using Windows.Devices.Enumeration.Pnp;
@@ -36,7 +30,6 @@ namespace ColorControl.Shared.Common
public static Guid GUID_CONSOLE_DISPLAY_STATE = Guid.Parse("6FE69556-704A-47A0-8F24-C28D936FDA47");
public static bool ConsoleOpened { get; private set; }
public static bool UseDedicatedElevatedProcess = false;
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
@@ -111,168 +104,6 @@ The best and suggested method to provide this is via a Windows Service. Only whe
return path;
}
private static bool? _IsAdministrator;
public static bool IsAdministrator()
{
if (_IsAdministrator.HasValue)
{
return _IsAdministrator.Value;
}
var identity = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(identity);
_IsAdministrator = principal.IsInRole(WindowsBuiltInRole.Administrator);
return _IsAdministrator.Value;
}
public static int ExecuteElevated(string args, bool wait = true, bool skipDedicated = false, bool skipService = false)
{
if (!skipService && IsServiceRunning())
{
var result = PipeUtils.SendRpcMessage(args);
if (result.HasValue)
{
return 0;
}
}
if (UseDedicatedElevatedProcess && !skipDedicated)
{
CheckElevatedProcess();
WinApi.CopyData.Send(ElevatedProcessWindowHandle, 1, args);
return 0;
}
var fileName = Process.GetCurrentProcess().MainModule.FileName;
var info = new ProcessStartInfo(fileName, args)
{
Verb = "runas", // indicates to elevate privileges
UseShellExecute = true,
};
var process = new Process
{
EnableRaisingEvents = true, // enable WaitForExit()
StartInfo = info
};
try
{
process.Start();
if (wait)
{
process.WaitForExit(); // sleep calling process thread until evoked process exit
}
return process.Id;
}
catch (Exception e)
{
Logger.Error("ExecuteElevated: " + e.Message);
}
return 0;
}
private static nint ElevatedProcessWindowHandle = nint.Zero;
public static void CheckElevatedProcess()
{
ElevatedProcessWindowHandle = NativeMethods.FindWindowW(null, "ElevatedForm");
if (ElevatedProcessWindowHandle == nint.Zero)
{
ExecuteElevated(StartUpParams.StartElevatedParam, false, true, true);
var delay = 1000;
while (delay >= 0)
{
Thread.Sleep(100);
ElevatedProcessWindowHandle = NativeMethods.FindWindowW(null, "ElevatedForm");
if (ElevatedProcessWindowHandle != nint.Zero)
{
Thread.Sleep(500);
break;
}
delay -= 100;
}
}
}
public static bool IsChromeFixInstalled()
{
var key = Registry.ClassesRoot.OpenSubKey(@"ChromeHTML\shell\open\command");
return key != null && key.GetValue(null).ToString().Contains("--disable-lcd-text");
}
public static bool InstallChromeFix(bool install, string applicationDataFolder)
{
var argument = "--disable-lcd-text";
var key = Registry.ClassesRoot.OpenSubKey(@"ChromeHTML\shell\open\command", true);
if (key != null)
{
var value = key.GetValue(null).ToString();
value = value.Replace("chrome.exe\" " + argument + " --", "chrome.exe\" --");
if (install)
{
value = value.Replace("chrome.exe\" --", "chrome.exe\" " + argument + " --");
}
key.SetValue(null, value);
}
var roamingFolder = applicationDataFolder ?? Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
UpdateShortcut(Path.Combine(roamingFolder, @"Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\Google Chrome.lnk"), argument, !install);
UpdateShortcut(Path.Combine(roamingFolder, @"Microsoft\Internet Explorer\Quick Launch\Google Chrome.lnk"), argument, !install);
var allUsersStartMenuFolder = Environment.GetFolderPath(Environment.SpecialFolder.CommonStartMenu);
UpdateShortcut(Path.Combine(allUsersStartMenuFolder, @"Programs\Google Chrome.lnk"), argument, !install);
return true;
}
public static bool IsChromeInstalled()
{
var key = Registry.ClassesRoot.OpenSubKey(@"ChromeHTML\shell\open\command");
return key != null;
}
public static bool UpdateShortcut(string path, string arguments, bool removeArguments = false)
{
if (File.Exists(path))
{
IWshRuntimeLibrary.WshShell shell = new IWshRuntimeLibrary.WshShell();
IWshRuntimeLibrary.IWshShortcut shortcut = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(path);
shortcut.Arguments = shortcut.Arguments.Replace(arguments, "");
if (!removeArguments)
{
if (!string.IsNullOrEmpty(shortcut.Arguments))
{
shortcut.Arguments = shortcut.Arguments + " ";
}
shortcut.Arguments = shortcut.Arguments + arguments;
}
// save it / create
shortcut.Save();
return true;
}
return false;
}
public static string[] GetDeviceProperty(PnpObject device, string propertyName)
{
object objValue;
@@ -489,63 +320,6 @@ The best and suggested method to provide this is via a Windows Service. Only whe
return list;
}
public static void RegisterTask(string taskName, bool enabled, TaskRunLevel runLevel = TaskRunLevel.LUA)
{
if (!IsAdministrator())
{
ExecuteElevated(enabled ? $"{StartUpParams.EnableAutoStartParam} {(int)runLevel}" : StartUpParams.DisableAutoStartParam, skipService: true);
return;
}
var file = Process.GetCurrentProcess().MainModule.FileName;
var directory = Path.GetDirectoryName(file);
try
{
using (TaskService ts = new TaskService())
{
if (enabled)
{
var td = ts.NewTask();
td.RegistrationInfo.Description = "Start ColorControl";
td.Principal.RunLevel = runLevel;
td.Triggers.Add(new LogonTrigger { UserId = WindowsIdentity.GetCurrent().Name });
td.Actions.Add(new ExecAction(file, StartUpParams.RunningFromScheduledTaskParam, directory));
ts.RootFolder.RegisterTaskDefinition(taskName, td);
}
else
{
ts.RootFolder.DeleteTask(taskName, false);
}
}
}
catch (Exception e)
{
Logger.Error($"Could not create/delete task: {e.Message}");
}
}
public static bool TaskExists(string taskName)
{
using (TaskService ts = new TaskService())
{
var task = ts.RootFolder.Tasks.FirstOrDefault(x => x.Name.Equals(taskName));
return task != null;
}
}
public static void CheckWin32Error(string message)
{
var errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message;
throw new Exception($"{message}: {errorMessage}");
}
public static bool OpenConsole()
{
if (ConsoleOpened)
@@ -601,76 +375,6 @@ The best and suggested method to provide this is via a Windows Service. Only whe
return null;
}
public static Process StartProcess(string fileName, string arguments = null, bool hidden = false, bool wait = false, bool setWorkingDir = false, bool elevate = false, uint affinityMask = 0, uint priorityClass = 0)
{
var process = Process.Start(new ProcessStartInfo(fileName, arguments)
{
Verb = elevate ? "runas" : string.Empty, // indicates to elevate privileges
UseShellExecute = true,
WindowStyle = hidden ? ProcessWindowStyle.Hidden : ProcessWindowStyle.Normal,
WorkingDirectory = setWorkingDir ? Path.GetDirectoryName(fileName) : null
});
if (affinityMask > 0)
{
SetProcessAffinity(process.Id, affinityMask);
}
if (priorityClass > 0 && priorityClass != NativeConstants.NORMAL_PRIORITY_CLASS)
{
SetProcessPriority(process.Id, priorityClass);
}
if (wait)
{
process.WaitForExit();
}
return process;
}
public static void SetProcessAffinity(int processId, uint affinityMask)
{
if (!IsAdministrator())
{
ExecuteElevated($"{StartUpParams.SetProcessAffinityParam} {processId} {affinityMask}");
return;
}
var hProcess = NativeMethods.OpenProcess(NativeConstants.PROCESS_ALL_ACCESS, false, (uint)processId);
if (hProcess == nint.Zero)
{
CheckWin32Error($"Unable to set processor affinity on process {processId}");
}
NativeMethods.SetProcessAffinityMask(hProcess, affinityMask);
//var AffinityMask = (long)process.ProcessorAffinity;
//AffinityMask &= 0x000F; // use only any of the first 4 available processors
//process.ProcessorAffinity = (IntPtr)AffinityMask;
}
public static void SetProcessPriority(int processId, uint priorityClass)
{
if (!IsAdministrator())
{
ExecuteElevated($"{StartUpParams.SetProcessPriorityParam} {processId} {priorityClass}");
return;
}
var hProcess = NativeMethods.OpenProcess(NativeConstants.PROCESS_ALL_ACCESS, false, (uint)processId);
if (hProcess == nint.Zero)
{
CheckWin32Error($"Unable to set process priority on process {processId}");
}
NativeMethods.SetPriorityClass(hProcess, priorityClass);
}
public static string GetResourceFile(string resourceName)
{
resourceName = "ColorControl.Resources." + resourceName;
@@ -794,100 +498,6 @@ The best and suggested method to provide this is via a Windows Service. Only whe
return str1.Trim().Replace(" ", string.Empty).Equals(str2.Trim().Replace(" ", string.Empty), StringComparison.OrdinalIgnoreCase);
}
public static void StartService()
{
if (!IsAdministrator())
{
ExecuteElevated(StartUpParams.StartServiceParam);
return;
}
var controller = new ServiceController(SERVICE_NAME);
if (controller.Status == ServiceControllerStatus.Stopped)
{
controller.Start();
}
}
public static void StopService()
{
if (!IsAdministrator())
{
ExecuteElevated(StartUpParams.StopServiceParam);
return;
}
var controller = new ServiceController(SERVICE_NAME);
if (controller.Status == ServiceControllerStatus.Running)
{
controller.Stop();
}
}
public static bool IsServiceInstalled()
{
return GetServiceStatus() != 0;
}
public static bool IsServiceRunning()
{
return GetServiceStatus() == ServiceControllerStatus.Running;
}
public static ServiceControllerStatus GetServiceStatus()
{
var controller = new ServiceController(SERVICE_NAME);
try
{
return controller.Status;
}
catch (Exception)
{
return 0;
}
}
public static void InstallService()
{
if (!IsAdministrator())
{
ExecuteElevated(StartUpParams.InstallServiceParam, skipService: true);
return;
}
if (!IsServiceInstalled())
{
StartProcess("sc.exe", @$"create ""{SERVICE_NAME}"" binpath=""{Process.GetCurrentProcess().MainModule.FileName}"" start=auto", wait: true);
StartProcess("sc.exe", @$"description ""{SERVICE_NAME}"" ""Executes tasks for Color Control that require elevation. If this service is stopped, functions like WOL might be impacted.""", wait: true);
}
StartService();
}
public static void UninstallService()
{
if (!IsAdministrator())
{
ExecuteElevated(StartUpParams.UninstallServiceParam, skipService: true);
return;
}
if (!IsServiceInstalled())
{
return;
}
StopService();
StartProcess("sc.exe", @$"delete ""{SERVICE_NAME}""", wait: true);
}
public static async Task<bool> PingHost(string nameOrAddress)
{
try
-255
View File
@@ -1,255 +0,0 @@
using ColorControl.Shared.Contracts;
using NLog;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using Vanara.PInvoke;
using static Vanara.PInvoke.IpHlpApi;
namespace ColorControl.Shared.Common
{
public class WOL
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private const string ArgumentExceptionInvalidMacAddressLength = "Invalid MAC address length.";
private const string ArgumentExceptionInvalidPasswordLength = "Invalid password length.";
private const int DefaultWolPort = 9;
public static bool WakeFunction(string macAddress, string ipAddress = null)
{
return WakeFunctionToAllNics(macAddress, ipAddress);
}
public static bool WakeFunctionCheckAdmin(string macAddress, string ipAddress = null)
{
if (Utils.IsAdministrator())
{
return WakeFunction(macAddress, ipAddress);
}
var result = PipeUtils.SendRpcMessage($"{StartUpParams.SendWakeOnLanParam} {macAddress} {ipAddress}");
// Execute local WOL anyway because pipe failed
if (!result.HasValue)
{
result = WakeFunction(macAddress, ipAddress);
}
return result.Value;
}
public static bool WakeFunctionToAllNics(string macAddress, string ipAddressString)
{
var result = false;
Logger.Debug($"Sending WOL packet to MAC-address {macAddress}");
try
{
var physicalAddress = PhysicalAddress.Parse(macAddress);
var addressBytes = physicalAddress.GetAddressBytes();
var data = GetWolPacket(addressBytes);
var ipAddress = ipAddressString != null ? IPAddress.Parse(ipAddressString) : null;
var interfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (var ni in interfaces)
{
if (ni.NetworkInterfaceType == NetworkInterfaceType.Loopback/* || ni.Name.Contains("VirtualBox") || ni.Name.Contains("vEthernet") || ni.Description.Contains("Virtual")*/)
{
continue;
}
Logger.Debug($"Found network: {ni.Name} ({ni.Description}), type: {ni.NetworkInterfaceType}");
try
{
if (ni.SupportsMulticast && ni.GetIPProperties().GetIPv4Properties() == null)
{
continue;
}
foreach (var uip in ni.GetIPProperties().UnicastAddresses)
{
if (uip.Address.ToString().StartsWith("169.254") || uip.Address.AddressFamily != AddressFamily.InterNetwork)
{
continue;
}
Logger.Debug($"Broadcast WOL in network: {ni.Name} ({ni.Description}), local address: {uip.Address}, destination IP-address: {ipAddressString ?? "broadcast"}");
if (ipAddress != null && Utils.IsAdministrator())
{
var localEP = new IPEndPoint(uip.Address, 0);
SendWolToIpAddress(uip.Address, ipAddress, data, physicalAddress);
}
BroadcastWol(uip.Address, IPAddress.Broadcast, data);
var parts = uip.Address.ToString().Split(".").ToList();
parts[3] = "0";
var broadcastAddress = IPAddress.Parse(string.Join(".", parts));
BroadcastWol(uip.Address, broadcastAddress, data);
result = true;
}
}
catch (Exception ex)
{
Logger.Error($"WakeFunctionToAllNics: while sending to specific network: {ni.Name} ({ni.Description}): {ex.ToLogString()}");
}
}
}
catch (Exception ex)
{
Logger.Error($"WakeFunctionToAllNics: {ex.ToLogString()}");
}
return result;
}
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="macAddress"/> is not 6.</exception>
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="password"/> is not 0 or 6.</exception>
private static byte[] GetWolPacket(byte[] macAddress, byte[] password = null)
{
if (macAddress == null)
throw new ArgumentNullException(nameof(macAddress));
if (macAddress.Length != 6)
throw new ArgumentException(ArgumentExceptionInvalidMacAddressLength);
password = password ?? new byte[0];
if (password.Length != 0 && password.Length != 6)
throw new ArgumentException(ArgumentExceptionInvalidPasswordLength);
var packet = new byte[17 * 6 + password.Length];
int offset, i;
for (offset = 0; offset < 6; ++offset)
packet[offset] = 0xFF;
for (offset = 6; offset < 17 * 6; offset += 6)
for (i = 0; i < 6; ++i)
packet[i + offset] = macAddress[i];
if (password.Length > 0)
{
for (offset = 16 * 6 + 6; offset < 17 * 6 + password.Length; offset += 6)
for (i = 0; i < 6; ++i)
packet[i + offset] = password[i];
}
return packet;
}
private static void BroadcastWol(IPAddress localAddress, IPAddress broadCastAddress, byte[] data)
{
//var localEP = new IPEndPoint(localAddress, 0);
var udpc = new UdpClient();
udpc.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
//udpc.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1);
var target = new IPEndPoint(broadCastAddress, DefaultWolPort);
udpc.Send(data, data.Length, target);
}
private static void SendWolToIpAddress(IPAddress localAddress, IPAddress remoteAddress, byte[] data, PhysicalAddress physicalAddress)
{
//var localEP = new IPEndPoint(localAddress, 0);
var netLuid = CreateTransientLocalNetEntry(remoteAddress, physicalAddress);
try
{
var udpc = new UdpClient();
udpc.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
var target = new IPEndPoint(remoteAddress, DefaultWolPort);
udpc.Send(data, data.Length, target);
}
finally
{
DeleteNetEntry(netLuid, remoteAddress);
}
}
private static NET_LUID CreateTransientLocalNetEntry(IPAddress ipAddress, PhysicalAddress macAddress)
{
var ipBytes = ipAddress.GetAddressBytes();
var address = new Ws2_32.SOCKADDR_INET
{
si_family = Ws2_32.ADDRESS_FAMILY.AF_INET,
Ipv4 = new Ws2_32.SOCKADDR_IN(new Ws2_32.IN_ADDR(ipBytes), DefaultWolPort),
};
var net = new NET_LUID();
var addr = new Ws2_32.SOCKADDR_INET();
MIB_IPFORWARD_ROW2 forwardRow;
var result = GetBestRoute2(net, 0, addr, address, 0, out forwardRow, out _);
if (result != Win32Error.ERROR_SUCCESS)
{
Logger.Debug($"Cannot find best route: {result}");
var luidDummy = new NET_LUID();
return luidDummy;
}
var luid = forwardRow.InterfaceLuid;
var macAddressBytes = macAddress.GetAddressBytes();
var bytes = new byte[32];
macAddressBytes.CopyTo(bytes, 0);
var row = new MIB_IPNET_ROW2
{
Address = address,
InterfaceLuid = luid,
PhysicalAddress = bytes,
PhysicalAddressLength = 6
};
result = CreateIpNetEntry2(ref row);
if (result != Win32Error.ERROR_SUCCESS)
{
Logger.Debug($"Cannot create ip net entry: {result}");
}
return luid;
}
private static void DeleteNetEntry(NET_LUID luid, IPAddress ipAddress)
{
if (luid.Value == 0)
{
return;
}
var ipBytes = ipAddress.GetAddressBytes();
var address = new Ws2_32.SOCKADDR_INET
{
si_family = Ws2_32.ADDRESS_FAMILY.AF_INET,
Ipv4 = new Ws2_32.SOCKADDR_IN(new Ws2_32.IN_ADDR(ipBytes), DefaultWolPort)
};
var row = new MIB_IPNET_ROW2
{
Address = address,
InterfaceLuid = luid,
};
var result = DeleteIpNetEntry2(ref row);
if (result != Win32Error.ERROR_SUCCESS)
{
Logger.Debug($"Cannot delete ip net entry: {result}");
}
}
}
}
+1 -138
View File
@@ -1,13 +1,8 @@
using ColorControl.Shared.Common;
using Microsoft.Win32.TaskScheduler;
namespace ColorControl.Shared.Contracts
namespace ColorControl.Shared.Contracts
{
public class StartUpParams
{
public const string RunningFromScheduledTaskParam = "--scheduled";
public const string ActivateChromeFontFixParam = "--activate-chrome-font-fix";
public const string DeactivateChromeFontFixParam = "--deactivate-chrome-font-fix";
public const string ExecuteHelpParam = "--help";
public const string ExecuteNvidiaPresetParam = "--nvpreset";
public const string ExecuteAmdPresetParam = "--amdpreset";
@@ -15,21 +10,9 @@ namespace ColorControl.Shared.Contracts
public const string ExecuteSamsungPresetParam = "--sampreset";
public const string NoDeviceRefreshParam = "--no-refresh";
public const string NoGuiParam = "--nogui";
public const string EnableAutoStartParam = "--enable-auto-start";
public const string DisableAutoStartParam = "--disable-auto-start";
public const string SetProcessAffinityParam = "--set-process-affinity";
public const string SetProcessPriorityParam = "--set-process-priority";
public const string StartElevatedParam = "--elevated";
public const string SendWakeOnLanParam = "--send-wol";
public const string InstallServiceParam = "--install-service";
public const string UninstallServiceParam = "--uninstall-service";
public const string StartServiceParam = "--start-service";
public const string StopServiceParam = "--stop-service";
public bool RunningFromScheduledTask { get; private set; }
public bool ActivateChromeFontFix { get; private set; }
public bool DeactivateChromeFontFix { get; private set; }
public string ChromeFontFixApplicationDataFolder { get; private set; }
public bool ExecuteHelp { get; private set; }
public bool ExecuteNvidiaPreset { get; private set; }
public string NvidiaPresetIdOrName { get; private set; }
@@ -41,22 +24,7 @@ namespace ColorControl.Shared.Contracts
public string SamsungPresetName { get; private set; }
public bool NoDeviceRefresh { get; private set; }
public bool NoGui { get; set; }
public bool EnableAutoStart { get; private set; }
public TaskRunLevel AutoStartRunLevel { get; private set; } = TaskRunLevel.LUA;
public bool DisableAutoStart { get; private set; }
public bool SetProcessAffinity { get; private set; }
public int ProcessId { get; private set; }
public uint AffinityMask { get; private set; }
public bool SetProcessPriority { get; private set; }
public uint PriorityClass { get; private set; }
public bool StartElevated { get; private set; }
public bool SendWol { get; private set; }
public string WolMacAddress { get; private set; }
public string WolIpAddress { get; private set; }
public bool InstallService { get; private set; }
public bool UninstallService { get; private set; }
public bool StartService { get; private set; }
public bool StopService { get; private set; }
public static StartUpParams Parse(IEnumerable<string> args)
{
@@ -68,12 +36,6 @@ namespace ColorControl.Shared.Contracts
{
switch (parseNameParam)
{
case ActivateChromeFontFixParam:
case DeactivateChromeFontFixParam:
{
settings.ChromeFontFixApplicationDataFolder = arg;
break;
}
case ExecuteNvidiaPresetParam:
{
settings.NvidiaPresetIdOrName = arg;
@@ -94,44 +56,6 @@ namespace ColorControl.Shared.Contracts
settings.SamsungPresetName = arg;
break;
}
case SetProcessAffinityParam:
{
if (settings.ProcessId == 0)
{
settings.ProcessId = int.Parse(arg);
continue;
}
settings.AffinityMask = uint.Parse(arg);
break;
}
case SetProcessPriorityParam:
{
if (settings.ProcessId == 0)
{
settings.ProcessId = int.Parse(arg);
continue;
}
settings.PriorityClass = uint.Parse(arg);
break;
}
case SendWakeOnLanParam:
{
if (settings.WolMacAddress == null)
{
settings.WolMacAddress = arg;
continue;
}
settings.WolIpAddress = arg;
break;
}
case EnableAutoStartParam:
{
settings.AutoStartRunLevel = (TaskRunLevel)Utils.ParseInt(arg, 0);
break;
}
}
parseNameParam = string.Empty;
@@ -145,18 +69,6 @@ namespace ColorControl.Shared.Contracts
settings.RunningFromScheduledTask = true;
break;
}
case ActivateChromeFontFixParam:
{
settings.ActivateChromeFontFix = true;
parseNameParam = ActivateChromeFontFixParam;
break;
}
case DeactivateChromeFontFixParam:
{
settings.DeactivateChromeFontFix = true;
parseNameParam = DeactivateChromeFontFixParam;
break;
}
case ExecuteHelpParam:
{
settings.ExecuteHelp = true;
@@ -192,60 +104,11 @@ namespace ColorControl.Shared.Contracts
settings.NoGui = true;
break;
}
case EnableAutoStartParam:
{
settings.EnableAutoStart = true;
parseNameParam = EnableAutoStartParam;
break;
}
case DisableAutoStartParam:
{
settings.DisableAutoStart = true;
break;
}
case SetProcessAffinityParam:
{
settings.SetProcessAffinity = true;
parseNameParam = SetProcessAffinityParam;
break;
}
case SetProcessPriorityParam:
{
settings.SetProcessPriority = true;
parseNameParam = SetProcessPriorityParam;
break;
}
case StartElevatedParam:
{
settings.StartElevated = true;
break;
}
case SendWakeOnLanParam:
{
settings.SendWol = true;
parseNameParam = SendWakeOnLanParam;
break;
}
case InstallServiceParam:
{
settings.InstallService = true;
break;
}
case UninstallServiceParam:
{
settings.UninstallService = true;
break;
}
case StartServiceParam:
{
settings.StartService = true;
break;
}
case StopServiceParam:
{
settings.StopService = true;
break;
}
case NoDeviceRefreshParam:
{
settings.NoDeviceRefresh = true;
+64 -53
View File
@@ -1,70 +1,81 @@
using ColorControl.Shared.Contracts.NVIDIA;
namespace ColorControl.Shared.Contracts
namespace ColorControl.Shared.Contracts;
public enum SvcMessageType
{
public enum SvcMessageType
SetLgConfig = 1,
GetLog = 2,
ClearLog = 3,
ExecuteRpc = 10,
ExecuteRpcGeneric = 11,
ExecuteRpcGenericTyped = 12,
ExecuteUpdate = 20,
RestartAfterUpdate = 21,
}
public class SvcMessage
{
public SvcMessageType MessageType { get; set; }
public string Data { get; set; }
}
public class SvcInstallUpdateMessage : SvcMessage
{
public SvcInstallUpdateMessage()
{
SetLgConfig = 1,
GetLog = 2,
ClearLog = 3,
ExecuteRpc = 10,
ExecuteRpcGeneric = 11,
ExecuteUpdate = 20,
RestartAfterUpdate = 21,
ApplyNvidiaDriverSettings = 101,
RestoreNvidiaDriverSetting = 102,
ApplyNvidiaOverclocking = 110,
MessageType = SvcMessageType.ExecuteUpdate;
}
public class SvcMessage
{
public SvcMessageType MessageType { get; set; }
public string DownloadUrl { get; set; }
public string ClientPath { get; set; }
}
public string Data { get; set; }
public class SvcRpcMessage : SvcMessage
{
public SvcRpcMessage()
{
MessageType = SvcMessageType.ExecuteRpcGeneric;
}
public class SvcInstallUpdateMessage : SvcMessage
private string _typeName;
public string TypeName
{
public SvcInstallUpdateMessage()
get
{
MessageType = SvcMessageType.ExecuteUpdate;
}
if (_typeName == null)
{
_typeName = GetType().Name;
}
public string DownloadUrl { get; set; }
public string ClientPath { get; set; }
return _typeName;
}
set { _typeName = value; }
}
public string ServiceName { get; set; }
public string MethodName { get; set; }
public object[] Arguments { get; set; }
}
public class SvcNvDriverSettingsMessage : SvcMessage
public class SvcRpcMessageTyped : SvcRpcMessage
{
public SvcRpcMessageTyped() : base()
{
public SvcNvDriverSettingsMessage(SvcMessageType messageType = SvcMessageType.ApplyNvidiaDriverSettings)
{
MessageType = messageType;
}
public string ProfileName { get; set; }
public List<KeyValuePair<uint, string>> DriverSettings { get; set; }
}
public class SvcNvOverclockingMessage : SvcMessage
{
public SvcNvOverclockingMessage(SvcMessageType messageType = SvcMessageType.ApplyNvidiaOverclocking)
{
MessageType = messageType;
}
public List<NvGpuOcSettings> OverclockingSettings { get; set; }
}
public class SvcRpcMessage : SvcMessage
{
public SvcRpcMessage()
{
MessageType = SvcMessageType.ExecuteRpcGeneric;
}
public string ServiceName { get; set; }
public string MethodName { get; set; }
public object[] Arguments { get; set; }
MessageType = SvcMessageType.ExecuteRpcGenericTyped;
}
}
public class SvcRpcSetNvDriverSettingsMessage : SvcRpcMessageTyped
{
public string ProfileName { get; set; }
public List<KeyValuePair<uint, string>> DriverSettings { get; set; }
}
public class SvcRpcSetNvOverclockingMessage : SvcRpcMessageTyped
{
public List<NvGpuOcSettings> OverclockingSettings { get; set; }
}
+26
View File
@@ -531,5 +531,31 @@ namespace ColorControl.Shared.Forms
return prompt;
}
public static Form ShowControl(Control control, string title)
{
var prompt = new Form()
{
Icon = MainForm.Icon,
Text = title,
Width = 800,
Height = 400,
StartPosition = FormStartPosition.CenterScreen,
BackColor = FormUtils.CurrentBackColor,
ForeColor = FormUtils.CurrentForeColor,
};
prompt.Controls.Add(control);
control.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
control.Width = prompt.ClientRectangle.Width;
control.Height = prompt.ClientRectangle.Height;
prompt.UpdateTheme(onlyIfDark: true);
prompt.Show(MainForm);
return prompt;
}
}
}
+77 -163
View File
@@ -1,170 +1,84 @@
using NWin32.NativeTypes;
using System.Runtime.InteropServices;
namespace ColorControl.Shared.Native
namespace ColorControl.Shared.Native;
public static class WinApi
{
public static class WinApi
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct POWERBROADCAST_SETTING
{
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct POWERBROADCAST_SETTING
{
public Guid PowerSetting;
public uint DataLength;
public byte Data;
}
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public IntPtr dwData; // in C/C++ this is an UINT_PTR, not an UINT
public int cbData;
public IntPtr lpData;
}
[StructLayout(LayoutKind.Sequential)]
public struct CopyData : IDisposable
{
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, IntPtr wParam, ref CopyData target,
SendMessageTimeoutFlags fuFlags, uint uTimeout, out UIntPtr lpdwResult);
[Flags]
enum SendMessageTimeoutFlags : uint
{
SMTO_NORMAL = 0x0,
SMTO_BLOCK = 0x1,
SMTO_ABORTIFHUNG = 0x2,
SMTO_NOTIMEOUTIFNOTHUNG = 0x8
}
const uint WM_COPYDATA = 0x4A;
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
public void Dispose()
{
if (lpData != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(lpData);
lpData = IntPtr.Zero;
cbData = 0;
}
}
public string AsAnsiString
{
get { return Marshal.PtrToStringAnsi(lpData, cbData); }
}
public string AsUnicodeString
{
get { return Marshal.PtrToStringUni(lpData); }
}
public static CopyData CreateForString(int dwData, string value, bool Unicode = false)
{
var result = new CopyData();
result.dwData = (IntPtr)dwData;
result.lpData = Unicode ? Marshal.StringToCoTaskMemUni(value) : Marshal.StringToCoTaskMemAnsi(value);
result.cbData = value.Length + 2;
return result;
}
public static UIntPtr Send(IntPtr targetHandle, int dwData, string value, uint timeoutMs = 1000, bool Unicode = false)
{
var cds = CreateForString(dwData, value, Unicode);
UIntPtr result;
SendMessageTimeout(targetHandle, WM_COPYDATA, IntPtr.Zero, ref cds, SendMessageTimeoutFlags.SMTO_NORMAL, timeoutMs, out result);
cds.Dispose();
return result;
}
}
public enum MessageFilterInfo : uint
{
None = 0, AlreadyAllowed = 1, AlreadyDisAllowed = 2, AllowedHigher = 3
};
public enum ChangeWindowMessageFilterExAction : uint
{
Reset = 0, Allow = 1, DisAllow = 2
};
[StructLayout(LayoutKind.Sequential)]
public struct CHANGEFILTERSTRUCT
{
public uint size;
public MessageFilterInfo info;
}
[StructLayout(LayoutKind.Sequential)]
public struct ParentProcessUtilities
{
// These members must match PROCESS_BASIC_INFORMATION
internal IntPtr Reserved1;
internal IntPtr PebBaseAddress;
internal IntPtr Reserved2_0;
internal IntPtr Reserved2_1;
internal IntPtr UniqueProcessId;
internal IntPtr InheritedFromUniqueProcessId;
}
public const int ENUM_CURRENT_SETTINGS = -1;
public const int ENUM_REGISTRY_SETTINGS = -2;
public static int PBT_POWERSETTINGCHANGE = 32787;
public delegate void PCREATE_PROCESS_NOTIFY_ROUTINE(IntPtr ParentId, IntPtr ProcessId, bool Create);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
[DllImport("user32.dll")]
public static extern bool EnumDisplaySettingsA(string deviceName, int modeNum, out DEVMODEA devMode);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AllocConsole();
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
public static extern bool AttachConsole(int processId);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FreeConsole();
[DllImport(@"User32", SetLastError = true)]
public static extern IntPtr RegisterPowerSettingNotification(IntPtr hRecipient, ref Guid PowerSettingGuid, Int32 Flags);
[DllImport("User32.dll", SetLastError = true)]
public static extern bool UnregisterPowerSettingNotification(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool ChangeWindowMessageFilterEx(IntPtr hWnd, uint msg, ChangeWindowMessageFilterExAction action, ref CHANGEFILTERSTRUCT changeInfo);
[DllImport("uxtheme.dll", CharSet = CharSet.Unicode)]
public static extern int SetWindowTheme(IntPtr hWnd, string pszSubAppName, string pszSubIdList);
[DllImport("uxtheme.dll", CharSet = CharSet.Unicode, EntryPoint = "#104")]
public static extern int RefreshImmersiveColorPolicyState();
[DllImport("uxtheme.dll", CharSet = CharSet.Unicode, EntryPoint = "#133")]
public static extern int AllowDarkModeForWindow(IntPtr hWnd, bool allow);
[DllImport("uxtheme.dll", CharSet = CharSet.Unicode, EntryPoint = "#135")]
public static extern int SetPreferredAppMode(int appMode);
[DllImport("uxtheme.dll", EntryPoint = "#136")]
public static extern void FlushMenuThemes();
[DllImport("dwmapi.dll", PreserveSig = true)]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);
[DllImport("ntdll.dll")]
public static extern int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, ref ParentProcessUtilities processInformation, int processInformationLength, out int returnLength);
[DllImport("dwmapi.dll", EntryPoint = "#171")]
public static extern void DwmpSDRToHDRBoostPtr(IntPtr monitor, double brightness);
public Guid PowerSetting;
public uint DataLength;
public byte Data;
}
[StructLayout(LayoutKind.Sequential)]
public struct ParentProcessUtilities
{
// These members must match PROCESS_BASIC_INFORMATION
internal IntPtr Reserved1;
internal IntPtr PebBaseAddress;
internal IntPtr Reserved2_0;
internal IntPtr Reserved2_1;
internal IntPtr UniqueProcessId;
internal IntPtr InheritedFromUniqueProcessId;
}
public const int ENUM_CURRENT_SETTINGS = -1;
public const int ENUM_REGISTRY_SETTINGS = -2;
public static int PBT_POWERSETTINGCHANGE = 32787;
public delegate void PCREATE_PROCESS_NOTIFY_ROUTINE(IntPtr ParentId, IntPtr ProcessId, bool Create);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
[DllImport("user32.dll")]
public static extern bool EnumDisplaySettingsA(string deviceName, int modeNum, out DEVMODEA devMode);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AllocConsole();
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
public static extern bool AttachConsole(int processId);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FreeConsole();
[DllImport(@"User32", SetLastError = true)]
public static extern IntPtr RegisterPowerSettingNotification(IntPtr hRecipient, ref Guid PowerSettingGuid, Int32 Flags);
[DllImport("User32.dll", SetLastError = true)]
public static extern bool UnregisterPowerSettingNotification(IntPtr hWnd);
[DllImport("uxtheme.dll", CharSet = CharSet.Unicode)]
public static extern int SetWindowTheme(IntPtr hWnd, string pszSubAppName, string pszSubIdList);
[DllImport("uxtheme.dll", CharSet = CharSet.Unicode, EntryPoint = "#104")]
public static extern int RefreshImmersiveColorPolicyState();
[DllImport("uxtheme.dll", CharSet = CharSet.Unicode, EntryPoint = "#133")]
public static extern int AllowDarkModeForWindow(IntPtr hWnd, bool allow);
[DllImport("uxtheme.dll", CharSet = CharSet.Unicode, EntryPoint = "#135")]
public static extern int SetPreferredAppMode(int appMode);
[DllImport("uxtheme.dll", EntryPoint = "#136")]
public static extern void FlushMenuThemes();
[DllImport("dwmapi.dll", PreserveSig = true)]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);
[DllImport("ntdll.dll")]
public static extern int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, ref ParentProcessUtilities processInformation, int processInformationLength, out int returnLength);
[DllImport("dwmapi.dll", EntryPoint = "#171")]
public static extern void DwmpSDRToHDRBoostPtr(IntPtr monitor, double brightness);
}
+3 -3
View File
@@ -2,14 +2,14 @@
{
public class AppContextProvider
{
private Common.AppContext _appContext;
private Common.GlobalContext _appContext;
public void SetAppContext(Common.AppContext appContext)
public void SetAppContext(Common.GlobalContext appContext)
{
_appContext = appContext;
}
public Common.AppContext GetAppContext()
public Common.GlobalContext GetAppContext()
{
return _appContext;
}
+72
View File
@@ -0,0 +1,72 @@
using ColorControl.Shared.Common;
using ColorControl.Shared.Contracts;
using System.Diagnostics;
namespace ColorControl.Shared.Services;
public class RpcClientService
{
private readonly WinElevatedProcessManager _elevatedProcessManager;
private readonly WinApiService _winApiService;
private readonly RpcServerService _rpcServerService;
public string Name { get; set; }
public RpcClientService(WinElevatedProcessManager elevatedProcessManager, WinApiService winApiService, RpcServerService rpcServerService)
{
_elevatedProcessManager = elevatedProcessManager;
_winApiService = winApiService;
_rpcServerService = rpcServerService;
}
public T Call<T>(string method, params object[] arguments)
{
if (!_winApiService.IsServiceRunning())
{
// Last resort: try via elevated process
return ExecuteViaElevatedProcess<T>(method, arguments);
}
var rpcMessage = new SvcRpcMessage
{
ServiceName = Name,
MethodName = method,
Arguments = arguments
};
//var json = JsonConvert.SerializeObject(rpcMessage);
//var msg = JsonConvert.DeserializeObject<SvcRpcMessage>(json);
//var _ = _rpcServerService.ExecuteRpcAsync(msg);
//return default;
return PipeUtils.SendRpcMessage<T>(rpcMessage);
}
public T Call<T>(SvcRpcMessage message)
{
message.ServiceName = Name;
if (Debugger.IsAttached)
{
return PipeUtils.SendRpcMessage<T>(message, pipeName: PipeUtils.ElevatedPipe);
}
if (!_winApiService.IsServiceRunning())
{
// Last resort: try via elevated process
return ExecuteViaElevatedProcess<T>(message);
}
return PipeUtils.SendRpcMessage<T>(message);
}
private T ExecuteViaElevatedProcess<T>(string method, params object[] arguments)
{
return _elevatedProcessManager.ExecuteElevated<T>(method, arguments);
}
private T ExecuteViaElevatedProcess<T>(SvcRpcMessage message)
{
return _elevatedProcessManager.ExecuteElevated<T>(message);
}
}
+134
View File
@@ -0,0 +1,134 @@
using ColorControl.Shared.Contracts;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using System.Reflection;
namespace ColorControl.Shared.Services;
public class RpcServerService
{
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
private readonly IServiceProvider _serviceProvider;
public static List<Type> ServiceTypes = new List<Type>();
public RpcServerService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public async Task<SvcResultMessage> ExecuteRpcAsync(SvcRpcMessage message)
{
try
{
var service = GetServiceInstance(message.ServiceName);
var method = service.GetType().GetMethod(message.MethodName);
var convertedArgs = new List<object>();
var methodParams = method.GetParameters();
for (var i = 0; i < message.Arguments.Length; i++)
{
var arg = message.Arguments[i];
var methodParam = methodParams[i];
var convertedArg = ConvertArgument(arg, methodParam.ParameterType);
convertedArgs.Add(arg);
}
Logger.Debug($"Executing RPC: {message.ServiceName}.{message.MethodName}({string.Join(", ", convertedArgs)})");
var result = method.Invoke(service, convertedArgs.ToArray());
var data = JsonConvert.SerializeObject(result);
return SvcResultMessage.FromResult(data);
}
catch (Exception ex)
{
Logger.Error(ex, $"ExecuteRpcAsync: {ex.Message}");
return new SvcResultMessage { ErrorMessage = ex.Message, Result = false };
}
}
private object ConvertArgument(object arg, Type type)
{
if (arg.GetType() != type)
{
if (type.IsEnum)
{
return Enum.ToObject(type, arg);
}
var convertedArg = Convert.ChangeType(arg, type);
return convertedArg;
}
return arg;
}
public async Task<SvcResultMessage> ExecuteRpcTypedAsync(SvcRpcMessageTyped message)
{
try
{
var service = GetServiceInstance(message.ServiceName);
var method = service.GetType().GetMethod(message.MethodName);
var props = message.GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
var methodParams = method.GetParameters();
var convertedArgs = new List<object>();
var paramIndex = 0;
foreach (var prop in props)
{
Logger.Debug($"Prop: {prop.Name}");
var arg = prop.GetValue(message);
var methodParam = methodParams[paramIndex];
var convertedArg = ConvertArgument(arg, methodParam.ParameterType);
convertedArgs.Add(arg);
paramIndex++;
}
Logger.Debug($"Executing RPC-typed: {message.ServiceName}.{message.MethodName}({string.Join(", ", convertedArgs)})");
var result = method.Invoke(service, convertedArgs.ToArray());
var data = JsonConvert.SerializeObject(result);
return SvcResultMessage.FromResult(data);
}
catch (Exception ex)
{
Logger.Error(ex, $"ExecuteRpcTypedAsync: {ex.Message}");
return new SvcResultMessage { ErrorMessage = ex.Message, Result = false };
}
}
private object GetServiceInstance(string name)
{
var type = Type.GetType($"ColorControl.Shared.Services.{name}");
type ??= Type.GetType($"ColorControl.Services.NVIDIA.{name}");
type ??= ServiceTypes.FirstOrDefault(t => t.Name == name);
if (type == null)
{
throw new InvalidOperationException($"Type not found: {name}");
}
var service = _serviceProvider.GetRequiredService(type);
return service;
}
}
-23
View File
@@ -1,23 +0,0 @@
using ColorControl.Shared.Common;
using ColorControl.Shared.Contracts;
namespace ColorControl.Shared.Services
{
public class RpcService
{
public string Name { get; set; }
public T Call<T>(string method, params object[] arguments) where T : class
{
var rpcMessage = new SvcRpcMessage
{
ServiceName = Name,
MethodName = method,
Arguments = arguments
};
return PipeUtils.SendRpcMessage<T>(rpcMessage);
}
}
}
+383
View File
@@ -0,0 +1,383 @@
using ColorControl.Shared.Contracts;
using Microsoft.Win32;
using Microsoft.Win32.TaskScheduler;
using NWin32;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.ServiceProcess;
namespace ColorControl.Shared.Services
{
public class WinApiAdminService
{
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
public static string SERVICE_NAME = "Color Control Service";
private readonly WinApiService _winApiService;
private RpcClientService _rpcService;
private readonly WinElevatedProcessManager _elevatedProcessManager;
private bool? _IsAdministrator;
public WinApiAdminService(WinApiService winApiService, RpcClientService rpcService, WinElevatedProcessManager elevatedProcessManager)
{
_winApiService = winApiService;
_rpcService = rpcService;
_elevatedProcessManager = elevatedProcessManager;
_rpcService.Name = nameof(WinApiAdminService);
}
public bool SuspendThread(uint threadId)
{
if (!_winApiService.IsAdministrator())
{
return _rpcService.Call<bool>(nameof(SuspendThread), threadId);
}
var handle = NativeMethods.OpenThread(NativeConstants.THREAD_ALL_ACCESS, false, threadId);
try
{
var result = NativeMethods.SuspendThread(handle);
return ProcessResult(result);
}
finally
{
NativeMethods.CloseHandle(handle);
}
}
private int GetProcessMainThread(Process process)
{
var minStartTime = DateTime.MaxValue;
var mainThread = default(ProcessThread);
for (var i = 0; i < process.Threads.Count; i++)
{
var thread = process.Threads[i];
try
{
if (thread.StartTime < minStartTime)
{
mainThread = thread;
minStartTime = thread.StartTime;
}
}
catch { }
}
return mainThread.Id;
}
public int SuspendMainThread(int processId)
{
if (!_winApiService.IsAdministrator())
{
return _rpcService.Call<int>(nameof(SuspendMainThread), processId);
}
var process = Process.GetProcessById(processId);
var threadId = GetProcessMainThread(process);
if (SuspendThread((uint)threadId))
{
return threadId;
}
return 0;
}
public bool ResumeThread(uint threadId)
{
if (!_winApiService.IsAdministrator())
{
return _rpcService.Call<bool>(nameof(ResumeThread), threadId);
}
var handle = NativeMethods.OpenThread(NativeConstants.THREAD_ALL_ACCESS, false, threadId);
try
{
var result = NativeMethods.ResumeThread(handle);
return ProcessResult(result);
}
finally
{
NativeMethods.CloseHandle(handle);
}
}
public Process StartProcess(string fileName, string arguments = null, bool hidden = false, bool wait = false, bool setWorkingDir = false, bool elevate = false, uint affinityMask = 0, uint priorityClass = 0)
{
var process = Process.Start(new ProcessStartInfo(fileName, arguments)
{
Verb = elevate ? "runas" : string.Empty, // indicates to elevate privileges
UseShellExecute = true,
WindowStyle = hidden ? ProcessWindowStyle.Hidden : ProcessWindowStyle.Normal,
WorkingDirectory = setWorkingDir ? Path.GetDirectoryName(fileName) : null
});
if (affinityMask > 0)
{
SetProcessAffinity(process.Id, affinityMask);
}
if (priorityClass > 0 && priorityClass != NativeConstants.NORMAL_PRIORITY_CLASS)
{
SetProcessPriority(process.Id, priorityClass);
}
if (wait)
{
process.WaitForExit();
}
return process;
}
public bool StopProcess(int processId)
{
if (!_winApiService.IsAdministrator())
{
return _rpcService.Call<bool>(nameof(StopProcess), processId);
}
var process = Process.GetProcessById(processId);
if (process == null)
{
return false;
}
process.Kill();
return true;
}
public bool SetProcessAffinity(int processId, uint affinityMask)
{
if (!_winApiService.IsAdministrator())
{
return _rpcService.Call<bool>(nameof(SetProcessAffinity), processId, affinityMask);
}
var hProcess = NativeMethods.OpenProcess(NativeConstants.PROCESS_ALL_ACCESS, false, (uint)processId);
if (hProcess == nint.Zero)
{
CheckWin32Error($"Unable to set processor affinity on process {processId}");
return false;
}
return NativeMethods.SetProcessAffinityMask(hProcess, affinityMask);
}
public bool SetProcessPriority(int processId, uint priorityClass)
{
if (!_winApiService.IsAdministrator())
{
return _rpcService.Call<bool>(nameof(SetProcessPriority), processId, priorityClass);
}
var hProcess = NativeMethods.OpenProcess(NativeConstants.PROCESS_ALL_ACCESS, false, (uint)processId);
if (hProcess == nint.Zero)
{
CheckWin32Error($"Unable to set process priority on process {processId}");
return false;
}
return NativeMethods.SetPriorityClass(hProcess, priorityClass);
}
public void InstallService()
{
if (!_winApiService.IsAdministrator())
{
_elevatedProcessManager.ExecuteElevated(nameof(InstallService));
return;
}
if (!_winApiService.IsServiceInstalled())
{
StartProcess("sc.exe", @$"create ""{SERVICE_NAME}"" binpath=""{Process.GetCurrentProcess().MainModule.FileName}"" start=auto", wait: true);
StartProcess("sc.exe", @$"description ""{SERVICE_NAME}"" ""Executes tasks for Color Control that require elevation. If this service is stopped, functions like WOL might be impacted.""", wait: true);
}
StartService();
}
public void UninstallService()
{
if (!_winApiService.IsAdministrator())
{
_elevatedProcessManager.ExecuteElevated(nameof(UninstallService));
return;
}
if (!_winApiService.IsServiceInstalled())
{
return;
}
StopService();
StartProcess("sc.exe", @$"delete ""{SERVICE_NAME}""", wait: true);
}
public void StartService()
{
if (!_winApiService.IsAdministrator())
{
_elevatedProcessManager.ExecuteElevated(nameof(StartService));
return;
}
var controller = new ServiceController(SERVICE_NAME);
if (controller.Status == ServiceControllerStatus.Stopped)
{
controller.Start();
}
}
public void StopService()
{
if (!_winApiService.IsAdministrator())
{
_elevatedProcessManager.ExecuteElevated(nameof(StopService));
return;
}
var controller = new ServiceController(SERVICE_NAME);
if (controller.Status == ServiceControllerStatus.Running)
{
controller.Stop();
}
}
public bool InstallChromeFix(bool install, string applicationDataFolder)
{
if (!_winApiService.IsAdministrator())
{
return _rpcService.Call<bool>(nameof(InstallChromeFix), new object[] { install, applicationDataFolder });
}
var argument = "--disable-lcd-text";
var key = Registry.ClassesRoot.OpenSubKey(@"ChromeHTML\shell\open\command", true);
if (key != null)
{
var value = key.GetValue(null).ToString();
value = value.Replace("chrome.exe\" " + argument + " --", "chrome.exe\" --");
if (install)
{
value = value.Replace("chrome.exe\" --", "chrome.exe\" " + argument + " --");
}
key.SetValue(null, value);
}
var roamingFolder = applicationDataFolder ?? Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
UpdateShortcut(Path.Combine(roamingFolder, @"Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\Google Chrome.lnk"), argument, !install);
UpdateShortcut(Path.Combine(roamingFolder, @"Microsoft\Internet Explorer\Quick Launch\Google Chrome.lnk"), argument, !install);
var allUsersStartMenuFolder = Environment.GetFolderPath(Environment.SpecialFolder.CommonStartMenu);
UpdateShortcut(Path.Combine(allUsersStartMenuFolder, @"Programs\Google Chrome.lnk"), argument, !install);
return true;
}
public void RegisterTask(string taskName, bool enabled, TaskRunLevel runLevel = TaskRunLevel.LUA)
{
if (!_winApiService.IsAdministrator())
{
_elevatedProcessManager.ExecuteElevated(nameof(RegisterTask), new object[] { taskName, enabled, runLevel });
return;
}
var file = Process.GetCurrentProcess().MainModule.FileName;
var directory = Path.GetDirectoryName(file);
try
{
using (TaskService ts = new TaskService())
{
if (enabled)
{
var td = ts.NewTask();
td.RegistrationInfo.Description = "Start ColorControl";
td.Principal.RunLevel = runLevel;
td.Triggers.Add(new LogonTrigger { UserId = WindowsIdentity.GetCurrent().Name });
td.Actions.Add(new ExecAction(file, StartUpParams.RunningFromScheduledTaskParam, directory));
ts.RootFolder.RegisterTaskDefinition(taskName, td);
}
else
{
ts.RootFolder.DeleteTask(taskName, false);
}
}
}
catch (Exception e)
{
Logger.Error($"Could not create/delete task: {e.Message}");
}
}
private static bool UpdateShortcut(string path, string arguments, bool removeArguments = false)
{
if (File.Exists(path))
{
IWshRuntimeLibrary.WshShell shell = new IWshRuntimeLibrary.WshShell();
IWshRuntimeLibrary.IWshShortcut shortcut = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(path);
shortcut.Arguments = shortcut.Arguments.Replace(arguments, "");
if (!removeArguments)
{
if (!string.IsNullOrEmpty(shortcut.Arguments))
{
shortcut.Arguments = shortcut.Arguments + " ";
}
shortcut.Arguments = shortcut.Arguments + arguments;
}
// save it / create
shortcut.Save();
return true;
}
return false;
}
private static bool ProcessResult(uint result, [CallerMemberName] string callerName = "")
{
if (result != NativeConstants.ERROR_SUCCESS)
{
// Logging
Logger.Error("Error executing {CallerName}: error code {Result}", callerName, result);
}
return result == NativeConstants.ERROR_SUCCESS;
}
private static void CheckWin32Error(string message)
{
var errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message;
throw new Exception($"{message}: {errorMessage}");
}
}
}
+83
View File
@@ -0,0 +1,83 @@
using Microsoft.Win32;
using Microsoft.Win32.TaskScheduler;
using System.Security.Principal;
using System.ServiceProcess;
namespace ColorControl.Shared.Services;
public class WinApiService
{
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
public static string SERVICE_NAME = "Color Control Service";
private static bool? _IsAdministrator;
public WinApiService()
{
}
public static bool IsAdministratorStatic()
{
if (_IsAdministrator.HasValue)
{
return _IsAdministrator.Value;
}
var identity = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(identity);
_IsAdministrator = principal.IsInRole(WindowsBuiltInRole.Administrator);
return _IsAdministrator.Value;
}
public bool IsAdministrator()
{
return IsAdministratorStatic();
}
public bool IsServiceInstalled()
{
return GetServiceStatus() != 0;
}
public bool IsServiceRunning()
{
return GetServiceStatus() == ServiceControllerStatus.Running;
}
public bool IsChromeInstalled()
{
var key = Registry.ClassesRoot.OpenSubKey(@"ChromeHTML\shell\open\command");
return key != null;
}
public bool IsChromeFixInstalled()
{
var key = Registry.ClassesRoot.OpenSubKey(@"ChromeHTML\shell\open\command");
return key != null && key.GetValue(null).ToString().Contains("--disable-lcd-text");
}
public bool TaskExists(string taskName)
{
using (TaskService ts = new TaskService())
{
var task = ts.RootFolder.Tasks.FirstOrDefault(x => x.Name.Equals(taskName));
return task != null;
}
}
private ServiceControllerStatus GetServiceStatus()
{
var controller = new ServiceController(SERVICE_NAME);
try
{
return controller.Status;
}
catch (Exception)
{
return 0;
}
}
}
@@ -0,0 +1,108 @@
using ColorControl.Shared.Common;
using ColorControl.Shared.Contracts;
using NWin32;
using System.Diagnostics;
namespace ColorControl.Shared.Services;
public class WinElevatedProcessManager
{
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
private bool UseDedicatedElevatedProcess = true;
public WinElevatedProcessManager()
{
}
public void ExecuteElevated(string method, params object[] arguments)
{
ExecuteElevated<object>(method, arguments);
}
public T ExecuteElevated<T>(string method, params object[] arguments)
{
CheckElevatedProcess();
var rpcMessage = new SvcRpcMessage
{
ServiceName = nameof(WinApiAdminService),
MethodName = method,
Arguments = arguments
};
return PipeUtils.SendRpcMessage<T>(rpcMessage, pipeName: PipeUtils.ElevatedPipe);
}
public T ExecuteElevated<T>(SvcRpcMessage message)
{
CheckElevatedProcess();
return PipeUtils.SendRpcMessage<T>(message, pipeName: PipeUtils.ElevatedPipe);
}
private int ExecuteDirect(string args, bool wait = true)
{
var fileName = Process.GetCurrentProcess().MainModule.FileName;
var info = new ProcessStartInfo(fileName, args)
{
Verb = "runas", // indicates to elevate privileges
UseShellExecute = true,
};
var process = new Process
{
EnableRaisingEvents = true, // enable WaitForExit()
StartInfo = info
};
try
{
process.Start();
if (wait)
{
process.WaitForExit(); // sleep calling process thread until evoked process exit
}
return process.Id;
}
catch (Exception e)
{
Logger.Error("ExecuteElevated: " + e.Message);
}
return 0;
}
private static nint ElevatedProcessWindowHandle = nint.Zero;
public void CheckElevatedProcess()
{
ElevatedProcessWindowHandle = NativeMethods.FindWindowW(null, "ElevatedForm");
if (ElevatedProcessWindowHandle != nint.Zero)
{
return;
}
ExecuteDirect(StartUpParams.StartElevatedParam, false);
var delay = 1000;
while (delay >= 0)
{
Thread.Sleep(100);
ElevatedProcessWindowHandle = NativeMethods.FindWindowW(null, "ElevatedForm");
if (ElevatedProcessWindowHandle != nint.Zero)
{
Thread.Sleep(500);
break;
}
delay -= 100;
}
}
}
+256
View File
@@ -0,0 +1,256 @@
using ColorControl.Shared.Common;
using NLog;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using Vanara.PInvoke;
using static Vanara.PInvoke.IpHlpApi;
namespace ColorControl.Shared.Services;
public class WolService
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private const string ArgumentExceptionInvalidMacAddressLength = "Invalid MAC address length.";
private const string ArgumentExceptionInvalidPasswordLength = "Invalid password length.";
private const int DefaultWolPort = 9;
private readonly WinApiService _winApiService;
private readonly RpcClientService _rpcService;
public WolService(WinApiService winApiService, RpcClientService rpcService)
{
_winApiService = winApiService;
_rpcService = rpcService;
_rpcService.Name = nameof(WolService);
}
public bool SendWol(string macAddress, string ipAddress = null)
{
if (!_winApiService.IsAdministrator())
{
if (_rpcService.Call<bool>("SendWol", macAddress, ipAddress))
{
return true;
}
// If RPC faield, execute local WOL anyway
}
return WakeFunctionToAllNics(macAddress, ipAddress);
}
private bool WakeFunctionToAllNics(string macAddress, string ipAddressString)
{
var result = false;
Logger.Debug($"Sending WOL packet to MAC-address {macAddress}");
try
{
var physicalAddress = PhysicalAddress.Parse(macAddress);
var addressBytes = physicalAddress.GetAddressBytes();
var data = GetWolPacket(addressBytes);
var ipAddress = ipAddressString != null ? IPAddress.Parse(ipAddressString) : null;
var interfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (var ni in interfaces)
{
if (ni.NetworkInterfaceType == NetworkInterfaceType.Loopback/* || ni.Name.Contains("VirtualBox") || ni.Name.Contains("vEthernet") || ni.Description.Contains("Virtual")*/)
{
continue;
}
Logger.Debug($"Found network: {ni.Name} ({ni.Description}), type: {ni.NetworkInterfaceType}");
try
{
if (ni.SupportsMulticast && ni.GetIPProperties().GetIPv4Properties() == null)
{
continue;
}
foreach (var uip in ni.GetIPProperties().UnicastAddresses)
{
if (uip.Address.ToString().StartsWith("169.254") || uip.Address.AddressFamily != AddressFamily.InterNetwork)
{
continue;
}
Logger.Debug($"Broadcast WOL in network: {ni.Name} ({ni.Description}), local address: {uip.Address}, destination IP-address: {ipAddressString ?? "broadcast"}");
if (ipAddress != null && _winApiService.IsAdministrator())
{
var localEP = new IPEndPoint(uip.Address, 0);
SendWolToIpAddress(uip.Address, ipAddress, data, physicalAddress);
}
BroadcastWol(uip.Address, IPAddress.Broadcast, data);
var parts = uip.Address.ToString().Split(".").ToList();
parts[3] = "0";
var broadcastAddress = IPAddress.Parse(string.Join(".", parts));
BroadcastWol(uip.Address, broadcastAddress, data);
result = true;
}
}
catch (Exception ex)
{
Logger.Error($"WakeFunctionToAllNics: while sending to specific network: {ni.Name} ({ni.Description}): {ex.ToLogString()}");
}
}
}
catch (Exception ex)
{
Logger.Error($"WakeFunctionToAllNics: {ex.ToLogString()}");
}
return result;
}
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="macAddress"/> is not 6.</exception>
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="password"/> is not 0 or 6.</exception>
private static byte[] GetWolPacket(byte[] macAddress, byte[] password = null)
{
if (macAddress == null)
throw new ArgumentNullException(nameof(macAddress));
if (macAddress.Length != 6)
throw new ArgumentException(ArgumentExceptionInvalidMacAddressLength);
password = password ?? new byte[0];
if (password.Length != 0 && password.Length != 6)
throw new ArgumentException(ArgumentExceptionInvalidPasswordLength);
var packet = new byte[17 * 6 + password.Length];
int offset, i;
for (offset = 0; offset < 6; ++offset)
packet[offset] = 0xFF;
for (offset = 6; offset < 17 * 6; offset += 6)
for (i = 0; i < 6; ++i)
packet[i + offset] = macAddress[i];
if (password.Length > 0)
{
for (offset = 16 * 6 + 6; offset < 17 * 6 + password.Length; offset += 6)
for (i = 0; i < 6; ++i)
packet[i + offset] = password[i];
}
return packet;
}
private static void BroadcastWol(IPAddress localAddress, IPAddress broadCastAddress, byte[] data)
{
//var localEP = new IPEndPoint(localAddress, 0);
var udpc = new UdpClient();
udpc.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
//udpc.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1);
var target = new IPEndPoint(broadCastAddress, DefaultWolPort);
udpc.Send(data, data.Length, target);
}
private static void SendWolToIpAddress(IPAddress localAddress, IPAddress remoteAddress, byte[] data, PhysicalAddress physicalAddress)
{
//var localEP = new IPEndPoint(localAddress, 0);
var netLuid = CreateTransientLocalNetEntry(remoteAddress, physicalAddress);
try
{
var udpc = new UdpClient();
udpc.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
var target = new IPEndPoint(remoteAddress, DefaultWolPort);
udpc.Send(data, data.Length, target);
}
finally
{
DeleteNetEntry(netLuid, remoteAddress);
}
}
private static NET_LUID CreateTransientLocalNetEntry(IPAddress ipAddress, PhysicalAddress macAddress)
{
var ipBytes = ipAddress.GetAddressBytes();
var address = new Ws2_32.SOCKADDR_INET
{
si_family = Ws2_32.ADDRESS_FAMILY.AF_INET,
Ipv4 = new Ws2_32.SOCKADDR_IN(new Ws2_32.IN_ADDR(ipBytes), DefaultWolPort),
};
var net = new NET_LUID();
var addr = new Ws2_32.SOCKADDR_INET();
MIB_IPFORWARD_ROW2 forwardRow;
var result = GetBestRoute2(net, 0, addr, address, 0, out forwardRow, out _);
if (result != Win32Error.ERROR_SUCCESS)
{
Logger.Debug($"Cannot find best route: {result}");
var luidDummy = new NET_LUID();
return luidDummy;
}
var luid = forwardRow.InterfaceLuid;
var macAddressBytes = macAddress.GetAddressBytes();
var bytes = new byte[32];
macAddressBytes.CopyTo(bytes, 0);
var row = new MIB_IPNET_ROW2
{
Address = address,
InterfaceLuid = luid,
PhysicalAddress = bytes,
PhysicalAddressLength = 6
};
result = CreateIpNetEntry2(ref row);
if (result != Win32Error.ERROR_SUCCESS)
{
Logger.Debug($"Cannot create ip net entry: {result}");
}
return luid;
}
private static void DeleteNetEntry(NET_LUID luid, IPAddress ipAddress)
{
if (luid.Value == 0)
{
return;
}
var ipBytes = ipAddress.GetAddressBytes();
var address = new Ws2_32.SOCKADDR_INET
{
si_family = Ws2_32.ADDRESS_FAMILY.AF_INET,
Ipv4 = new Ws2_32.SOCKADDR_IN(new Ws2_32.IN_ADDR(ipBytes), DefaultWolPort)
};
var row = new MIB_IPNET_ROW2
{
Address = address,
InterfaceLuid = luid,
};
var result = DeleteIpNetEntry2(ref row);
if (result != Win32Error.ERROR_SUCCESS)
{
Logger.Debug($"Cannot delete ip net entry: {result}");
}
}
}
+4 -3
View File
@@ -22,7 +22,7 @@ namespace novideo_srgb
UpdateMonitors();
}
private void UpdateMonitors()
public void UpdateMonitors(bool? forceClamp = null)
{
Monitors.Clear();
List<XElement> config = null;
@@ -66,12 +66,13 @@ namespace novideo_srgb
foreach (var monitor in Monitors)
{
monitor.ReapplyClamp();
monitor.ReapplyClamp(forceClamp);
}
}
public void OnDisplaySettingsChanged(object sender, EventArgs e)
public async void OnDisplaySettingsChanged(object sender, EventArgs e)
{
await Task.Delay(1000);
UpdateMonitors();
}
+15
View File
@@ -42,6 +42,21 @@ namespace novideo_srgb
return _novideoWindow != null;
}
public static void BeforeDisplaySettingsChange()
{
if (!IsInitialized())
{
return;
}
_novideoWindow.UpdateMonitors();
}
private void UpdateMonitors()
{
_viewModel.UpdateMonitors(false);
}
public static void UpdateContextMenu(ToolStripMenuItem parent)
{
if (_novideoWindow == null)
+9 -2
View File
@@ -75,9 +75,16 @@ namespace novideo_srgb
private void UpdateClamp(bool doClamp)
{
if (HdrActive)
{
_clamped = false;
return;
}
if (_clamped)
{
Novideo.DisableColorSpaceConversion(_output);
_clamped = Novideo.IsColorSpaceConversionActive(_output);
}
if (!doClamp) return;
@@ -159,11 +166,11 @@ namespace novideo_srgb
get => _clamped;
}
public void ReapplyClamp()
public void ReapplyClamp(bool? forceClamp = null)
{
try
{
var clamped = CanClamp && ClampSdr;
var clamped = CanClamp && ClampSdr && (!forceClamp.HasValue || forceClamp.Value);
UpdateClamp(clamped);
_clamped = clamped;
OnPropertyChanged(nameof(CanClamp));