diff --git a/.editorconfig b/.editorconfig
index 0c4b20f..705667e 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -103,7 +103,7 @@ end_of_line = crlf
csharp_using_directive_placement = outside_namespace:suggestion
csharp_prefer_simple_using_statement = false:suggestion
csharp_prefer_braces = true:suggestion
-csharp_style_namespace_declarations = block_scoped:silent
+csharp_style_namespace_declarations = file_scoped:suggestion
csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = false:silent
csharp_style_expression_bodied_methods = true:silent
@@ -150,3 +150,6 @@ csharp_indent_case_contents_when_block = false
csharp_preserve_single_line_statements = true
csharp_style_prefer_primary_constructors = false:suggestion
csharp_style_prefer_readonly_struct_member = true:suggestion
+csharp_prefer_system_threading_lock = true:suggestion
+csharp_prefer_static_anonymous_function = true:suggestion
+csharp_space_around_declaration_statements = ignore
diff --git a/YAMDCC.Common/CommonConfig.cs b/YAMDCC.Common/CommonConfig.cs
index 402adcc..aff3bed 100644
--- a/YAMDCC.Common/CommonConfig.cs
+++ b/YAMDCC.Common/CommonConfig.cs
@@ -20,85 +20,83 @@
using System.Xml.Serialization;
using YAMDCC.Logs;
-namespace YAMDCC.Common
+namespace YAMDCC.Common;
+
+public class CommonConfig
{
- public class CommonConfig
- {
- ///
- /// The config version expected when loading a config.
- ///
- [XmlIgnore]
- public const int ExpectedVer = 1;
+ ///
+ /// The config version expected when loading a config.
+ ///
+ [XmlIgnore]
+ public const int ExpectedVer = 1;
- ///
- /// The config version. Should be the same as
- /// unless the config is newer or invalid.
- ///
- [XmlAttribute]
- public int Ver { get; set; }
+ ///
+ /// The config version. Should be the same as
+ /// unless the config is newer or invalid.
+ ///
+ [XmlAttribute]
+ public int Ver { get; set; }
- ///
- /// The product this was made for.
- ///
- [XmlAttribute]
- public string App { get; set; }
+ ///
+ /// The product this was made for.
+ ///
+ [XmlAttribute]
+ public string App { get; set; }
- ///
- /// How verbose logs should be.
- ///
- [XmlElement]
- public LogLevel LogLevel { get; set; } = LogLevel.Debug;
+ ///
+ /// How verbose logs should be.
+ ///
+ [XmlElement]
+ public LogLevel LogLevel { get; set; } = LogLevel.Debug;
- ///
- /// Loads the global app config XML and returns a
- /// object.
- ///
- public static CommonConfig Load()
+ ///
+ /// Loads the global app config XML and returns a
+ /// object.
+ ///
+ public static CommonConfig Load()
+ {
+ XmlSerializer serialiser = new(typeof(CommonConfig));
+ try
{
- XmlSerializer serialiser = new(typeof(CommonConfig));
- try
+ using (XmlReader reader = XmlReader.Create(Paths.GlobalConf))
{
- using (XmlReader reader = XmlReader.Create(Paths.GlobalConf))
- {
- CommonConfig cfg = (CommonConfig)serialiser.Deserialize(reader);
- return cfg.Ver == ExpectedVer
- ? cfg
- : throw new InvalidConfigException();
- }
- }
- catch (Exception ex)
- {
- if (ex is FileNotFoundException
- or InvalidOperationException
- or InvalidConfigException)
- {
- return new CommonConfig();
- }
- else
- {
- throw;
- }
+ CommonConfig cfg = (CommonConfig)serialiser.Deserialize(reader);
+ return cfg.Ver == ExpectedVer
+ ? cfg
+ : throw new InvalidConfigException();
}
}
-
- ///
- /// Saves the global app config XML.
- ///
- ///
- public void Save()
+ catch (Exception ex)
{
- XmlSerializer serializer = new(typeof(CommonConfig));
- XmlWriterSettings settings = new()
+ if (ex is FileNotFoundException
+ or InvalidOperationException
+ or InvalidConfigException)
{
- Indent = true,
- IndentChars = "\t",
- };
-
- using (XmlWriter writer = XmlWriter.Create(Paths.GlobalConf, settings))
+ return new CommonConfig();
+ }
+ else
{
- serializer.Serialize(writer, this);
+ throw;
}
}
+ }
+ ///
+ /// Saves the global app config XML.
+ ///
+ ///
+ public void Save()
+ {
+ XmlSerializer serializer = new(typeof(CommonConfig));
+ XmlWriterSettings settings = new()
+ {
+ Indent = true,
+ IndentChars = "\t",
+ };
+
+ using (XmlWriter writer = XmlWriter.Create(Paths.GlobalConf, settings))
+ {
+ serializer.Serialize(writer, this);
+ }
}
}
diff --git a/YAMDCC.Common/Dialogs/CrashDialog.cs b/YAMDCC.Common/Dialogs/CrashDialog.cs
index 7f3acee..a685f5e 100644
--- a/YAMDCC.Common/Dialogs/CrashDialog.cs
+++ b/YAMDCC.Common/Dialogs/CrashDialog.cs
@@ -18,38 +18,37 @@
using System.Diagnostics;
using System.Windows.Forms;
-namespace YAMDCC.Common.Dialogs
+namespace YAMDCC.Common.Dialogs;
+
+public sealed partial class CrashDialog : Form
{
- public sealed partial class CrashDialog : Form
+ public CrashDialog(Exception ex)
{
- public CrashDialog(Exception ex)
- {
- InitializeComponent();
- lblError.Text = Strings.GetString("Crash");
- txtReport.Text = $"{ex.GetType()}: {ex.Message}\r\n{ex.StackTrace}";
- }
-
- private void btnReportIssue_Click(object sender, EventArgs e)
- {
- Process.Start($"{Paths.GitHubPage}/issues");
- }
+ InitializeComponent();
+ lblError.Text = Strings.GetString("Crash");
+ txtReport.Text = $"{ex.GetType()}: {ex.Message}\r\n{ex.StackTrace}";
+ }
- private void btnCopy_Click(object sender, EventArgs e)
- {
- Clipboard.SetText(txtReport.Text);
+ private void btnReportIssue_Click(object sender, EventArgs e)
+ {
+ Process.Start($"{Paths.GitHubPage}/issues");
+ }
- // should never fail, but better safe than sorry
- // (this is the crash handling dialog after all)
- if (sender is Button b)
- {
- // give confirmation that the crash report has been copied
- b.Text = "Copied!";
- }
- }
+ private void btnCopy_Click(object sender, EventArgs e)
+ {
+ Clipboard.SetText(txtReport.Text);
- private void btnExit_Click(object sender, EventArgs e)
+ // should never fail, but better safe than sorry
+ // (this is the crash handling dialog after all)
+ if (sender is Button b)
{
- Environment.Exit(0);
+ // give confirmation that the crash report has been copied
+ b.Text = "Copied!";
}
}
+
+ private void btnExit_Click(object sender, EventArgs e)
+ {
+ Environment.Exit(0);
+ }
}
diff --git a/YAMDCC.Common/Dialogs/ProgressDialog.cs b/YAMDCC.Common/Dialogs/ProgressDialog.cs
index b43d2ea..ff5acef 100644
--- a/YAMDCC.Common/Dialogs/ProgressDialog.cs
+++ b/YAMDCC.Common/Dialogs/ProgressDialog.cs
@@ -19,174 +19,173 @@
using System.Globalization;
using System.Windows.Forms;
-namespace YAMDCC.Common.Dialogs
+namespace YAMDCC.Common.Dialogs;
+
+public sealed partial class ProgressDialog : Form
{
- public sealed partial class ProgressDialog : Form
- {
- #region Disable close button
- private const int CP_NOCLOSE_BUTTON = 0x200;
+ #region Disable close button
+ private const int CP_NOCLOSE_BUTTON = 0x200;
- protected override CreateParams CreateParams
+ protected override CreateParams CreateParams
+ {
+ get
{
- get
- {
- CreateParams myCp = base.CreateParams;
- myCp.ClassStyle |= CP_NOCLOSE_BUTTON;
- return myCp;
- }
+ CreateParams myCp = base.CreateParams;
+ myCp.ClassStyle |= CP_NOCLOSE_BUTTON;
+ return myCp;
}
- #endregion
-
- public bool Cancelled { get; set; }
- public object Result { get; set; }
-
- private readonly object Argument;
- private readonly string Caption;
- private readonly Action DoWork;
-
- private readonly BackgroundWorker Worker = new();
- private readonly Timer DisplayTimer = new();
-
- ///
- public ProgressDialog(
- string caption,
- Action doWork,
- bool reportsProgress = false,
- bool canCancel = false)
- : this(caption, doWork, null, reportsProgress, canCancel)
- { }
-
- ///
- /// Initialises a new instance of the class.
- ///
- ///
- /// The window caption to use.
- ///
- ///
- /// The to run when showing this window.
- ///
- ///
- /// The argument to pass to .
- ///
- ///
- /// Set to if
- /// reports progress, otherwise .
- ///
- ///
- /// Set to if
- /// supports cancellation, otherwise .
- ///
- ///
- public ProgressDialog(
- string caption,
- Action doWork,
- object argument,
- bool reportsProgress = false,
- bool canCancel = false)
+ }
+ #endregion
+
+ public bool Cancelled { get; set; }
+ public object Result { get; set; }
+
+ private readonly object Argument;
+ private readonly string Caption;
+ private readonly Action DoWork;
+
+ private readonly BackgroundWorker Worker = new();
+ private readonly Timer DisplayTimer = new();
+
+ ///
+ public ProgressDialog(
+ string caption,
+ Action doWork,
+ bool reportsProgress = false,
+ bool canCancel = false)
+ : this(caption, doWork, null, reportsProgress, canCancel)
+ { }
+
+ ///
+ /// Initialises a new instance of the class.
+ ///
+ ///
+ /// The window caption to use.
+ ///
+ ///
+ /// The to run when showing this window.
+ ///
+ ///
+ /// The argument to pass to .
+ ///
+ ///
+ /// Set to if
+ /// reports progress, otherwise .
+ ///
+ ///
+ /// Set to if
+ /// supports cancellation, otherwise .
+ ///
+ ///
+ public ProgressDialog(
+ string caption,
+ Action doWork,
+ object argument,
+ bool reportsProgress = false,
+ bool canCancel = false)
+ {
+ Opacity = 0;
+ Argument = argument;
+ InitializeComponent();
+
+ // sanity check
+ if (doWork is null)
{
- Opacity = 0;
- Argument = argument;
- InitializeComponent();
-
- // sanity check
- if (doWork is null)
- {
- throw new ArgumentNullException(nameof(doWork), "The doWork parameter was null.");
- }
- DoWork = doWork;
-
- // set title text
- Caption = caption ?? "Please wait...";
- if (reportsProgress && caption is null)
- {
- Caption += " ({0}% complete)";
- }
- SetTitle(Caption);
-
- // event setup
- Worker.DoWork += Worker_DoWork;
- Worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
- if (reportsProgress)
- {
- Worker.ProgressChanged += Worker_ProgressChanged;
- }
- else
- {
- pbProgress.Style = ProgressBarStyle.Marquee;
- }
-
- // cancel support stuff
- if (canCancel)
- {
- Worker.WorkerSupportsCancellation = true;
- }
- else
- {
- btnCancel.Enabled = false;
- btnCancel.Visible = false;
- }
-
- DisplayTimer.Interval = 1000;
- DisplayTimer.Tick += DisplayTimer_Tick;
+ throw new ArgumentNullException(nameof(doWork), "The doWork parameter was null.");
}
+ DoWork = doWork;
- private void ProgressDialog_Load(object sender, EventArgs e)
+ // set title text
+ Caption = caption ?? "Please wait...";
+ if (reportsProgress && caption is null)
{
- DisplayTimer.Start();
- Worker.RunWorkerAsync(Argument);
+ Caption += " ({0}% complete)";
}
+ SetTitle(Caption);
- private void DisplayTimer_Tick(object sender, EventArgs e)
+ // event setup
+ Worker.DoWork += Worker_DoWork;
+ Worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
+ if (reportsProgress)
{
- Opacity = 1;
- DisplayTimer.Stop();
+ Worker.ProgressChanged += Worker_ProgressChanged;
}
-
- private void Worker_DoWork(object sender, DoWorkEventArgs e)
+ else
{
- DoWork?.Invoke(e);
+ pbProgress.Style = ProgressBarStyle.Marquee;
}
- private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
+ // cancel support stuff
+ if (canCancel)
{
- if (e.ProgressPercentage < 0)
- {
- pbProgress.Style = ProgressBarStyle.Marquee;
- }
- else
- {
- pbProgress.Style = ProgressBarStyle.Blocks;
- pbProgress.Value = e.ProgressPercentage;
- }
- SetTitle(Caption);
+ Worker.WorkerSupportsCancellation = true;
}
+ else
+ {
+ btnCancel.Enabled = false;
+ btnCancel.Visible = false;
+ }
+
+ DisplayTimer.Interval = 1000;
+ DisplayTimer.Tick += DisplayTimer_Tick;
+ }
+
+ private void ProgressDialog_Load(object sender, EventArgs e)
+ {
+ DisplayTimer.Start();
+ Worker.RunWorkerAsync(Argument);
+ }
+
+ private void DisplayTimer_Tick(object sender, EventArgs e)
+ {
+ Opacity = 1;
+ DisplayTimer.Stop();
+ }
+
+ private void Worker_DoWork(object sender, DoWorkEventArgs e)
+ {
+ DoWork?.Invoke(e);
+ }
- private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
+ private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
+ {
+ if (e.ProgressPercentage < 0)
+ {
+ pbProgress.Style = ProgressBarStyle.Marquee;
+ }
+ else
{
- if (e.Error is not null)
- {
- throw e.Error;
- }
- Cancelled = e.Cancelled;
- Result = e.Result;
- Worker.Dispose();
- Close();
+ pbProgress.Style = ProgressBarStyle.Blocks;
+ pbProgress.Value = e.ProgressPercentage;
}
+ SetTitle(Caption);
+ }
- private void btnCancel_Click(object sender, EventArgs e)
+ private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
+ {
+ if (e.Error is not null)
{
- if (Worker.WorkerSupportsCancellation && Worker.IsBusy && !Worker.CancellationPending)
- {
- btnCancel.Enabled = false;
- Worker.CancelAsync();
- Text = "Cancelling...";
- pbProgress.Style = ProgressBarStyle.Marquee;
- }
+ throw e.Error;
}
+ Cancelled = e.Cancelled;
+ Result = e.Result;
+ Worker.Dispose();
+ Close();
+ }
- private void SetTitle(string title)
+ private void btnCancel_Click(object sender, EventArgs e)
+ {
+ if (Worker.WorkerSupportsCancellation && Worker.IsBusy && !Worker.CancellationPending)
{
- lblCaption.Text = string.Format(CultureInfo.InvariantCulture, title, pbProgress.Value);
+ btnCancel.Enabled = false;
+ Worker.CancelAsync();
+ Text = "Cancelling...";
+ pbProgress.Style = ProgressBarStyle.Marquee;
}
}
+
+ private void SetTitle(string title)
+ {
+ lblCaption.Text = string.Format(CultureInfo.InvariantCulture, title, pbProgress.Value);
+ }
}
diff --git a/YAMDCC.Common/Dialogs/TextInputDialog.cs b/YAMDCC.Common/Dialogs/TextInputDialog.cs
index 668414c..631dc04 100644
--- a/YAMDCC.Common/Dialogs/TextInputDialog.cs
+++ b/YAMDCC.Common/Dialogs/TextInputDialog.cs
@@ -17,35 +17,34 @@
using System;
using System.Windows.Forms;
-namespace YAMDCC.Common.Dialogs
+namespace YAMDCC.Common.Dialogs;
+
+public sealed partial class TextInputDialog : Form
{
- public sealed partial class TextInputDialog : Form
- {
- ///
- /// The text that the user entered in this dialog.
- ///
- public string Result { get; set; }
+ ///
+ /// The text that the user entered in this dialog.
+ ///
+ public string Result { get; set; }
- public TextInputDialog(string caption, string title, string text, bool multiline = false)
- {
- InitializeComponent();
- lblCaption.Text = caption;
- txtInput.Text = text;
- txtInput.Multiline = multiline;
- txtInput.Height = (int)(AutoScaleDimensions.Height / 96 * 69);
- Text = title;
- }
+ public TextInputDialog(string caption, string title, string text, bool multiline = false)
+ {
+ InitializeComponent();
+ lblCaption.Text = caption;
+ txtInput.Text = text;
+ txtInput.Multiline = multiline;
+ txtInput.Height = (int)(AutoScaleDimensions.Height / 96 * 69);
+ Text = title;
+ }
- private void btnOK_Click(object sender, EventArgs e)
- {
- Result = txtInput.Text;
- }
+ private void btnOK_Click(object sender, EventArgs e)
+ {
+ Result = txtInput.Text;
+ }
- private void txtInput_TextChanged(object sender, EventArgs e)
- {
- // make sure text input isn't empty
- // before allowing user to click "OK":
- btnOK.Enabled = !string.IsNullOrEmpty(txtInput.Text);
- }
+ private void txtInput_TextChanged(object sender, EventArgs e)
+ {
+ // make sure text input isn't empty
+ // before allowing user to click "OK":
+ btnOK.Enabled = !string.IsNullOrEmpty(txtInput.Text);
}
}
diff --git a/YAMDCC.Common/Dialogs/VersionDialog.cs b/YAMDCC.Common/Dialogs/VersionDialog.cs
index ba49b0e..295688e 100644
--- a/YAMDCC.Common/Dialogs/VersionDialog.cs
+++ b/YAMDCC.Common/Dialogs/VersionDialog.cs
@@ -18,47 +18,46 @@
using System.Diagnostics;
using System.Windows.Forms;
-namespace YAMDCC.Common.Dialogs
+namespace YAMDCC.Common.Dialogs;
+
+public sealed partial class VersionDialog : Form
{
- public sealed partial class VersionDialog : Form
+ public VersionDialog()
{
- public VersionDialog()
- {
- InitializeComponent();
- lblDesc.Text = Strings.GetString("abtDesc");
- lblCopyright.Text = Strings.GetString("abtCopyright");
- lblVersion.Text += Utils.GetVerString();
+ InitializeComponent();
+ lblDesc.Text = Strings.GetString("abtDesc");
+ lblCopyright.Text = Strings.GetString("abtCopyright");
+ lblVersion.Text += Utils.GetVerString();
- string revision = Utils.GetRevision();
+ string revision = Utils.GetRevision();
- if (string.IsNullOrEmpty(revision))
- {
- lblRevision.Hide();
- }
- else
- {
- lblRevision.Text += revision;
- }
- }
-
- private void btnLicense_Click(object sender, EventArgs e)
+ if (string.IsNullOrEmpty(revision))
{
- Process.Start("https://www.gnu.org/licenses/gpl-3.0.html#license-text");
+ lblRevision.Hide();
}
-
- private void btnSource_Click(object sender, EventArgs e)
+ else
{
- Process.Start(Paths.GitHubPage);
+ lblRevision.Text += revision;
}
+ }
- private void btnFAQ_Click(object sender, EventArgs e)
- {
- Process.Start($"{Paths.GitHubPage}#faq");
- }
+ private void btnLicense_Click(object sender, EventArgs e)
+ {
+ Process.Start("https://www.gnu.org/licenses/gpl-3.0.html#license-text");
+ }
- private void btnIssues_Click(object sender, EventArgs e)
- {
- Process.Start($"{Paths.GitHubPage}/issues");
- }
+ private void btnSource_Click(object sender, EventArgs e)
+ {
+ Process.Start(Paths.GitHubPage);
+ }
+
+ private void btnFAQ_Click(object sender, EventArgs e)
+ {
+ Process.Start($"{Paths.GitHubPage}#faq");
+ }
+
+ private void btnIssues_Click(object sender, EventArgs e)
+ {
+ Process.Start($"{Paths.GitHubPage}/issues");
}
}
diff --git a/YAMDCC.Common/InvalidConfigException.cs b/YAMDCC.Common/InvalidConfigException.cs
index a26b1b8..54d2b4d 100644
--- a/YAMDCC.Common/InvalidConfigException.cs
+++ b/YAMDCC.Common/InvalidConfigException.cs
@@ -16,17 +16,16 @@
using System;
-namespace YAMDCC.Common
+namespace YAMDCC.Common;
+
+///
+/// The exception thrown when an invalid is loaded.
+///
+public sealed class InvalidConfigException : Exception
{
///
- /// The exception thrown when an invalid is loaded.
+ /// Initializes a new instance of the class.
///
- public sealed class InvalidConfigException : Exception
- {
- ///
- /// Initializes a new instance of the class.
- ///
- public InvalidConfigException()
- : base("The config was not in the expected format.") { }
- }
+ public InvalidConfigException()
+ : base("The config was not in the expected format.") { }
}
diff --git a/YAMDCC.Common/Paths.cs b/YAMDCC.Common/Paths.cs
index cff06df..a9c997e 100644
--- a/YAMDCC.Common/Paths.cs
+++ b/YAMDCC.Common/Paths.cs
@@ -17,64 +17,63 @@
using System;
using System.IO;
-namespace YAMDCC.Common
+namespace YAMDCC.Common;
+
+public static class Paths
{
- public static class Paths
- {
- ///
- /// The GitHub home page.
- ///
- public const string GitHubHome = "https://github.com";
+ ///
+ /// The GitHub home page.
+ ///
+ public const string GitHubHome = "https://github.com";
- ///
- /// The project repository.
- ///
- public const string ProjectRepo = "Sparronator9999/YAMDCC";
+ ///
+ /// The project repository.
+ ///
+ public const string ProjectRepo = "Sparronator9999/YAMDCC";
- ///
- /// The URL to this project's GitHub page.
- ///
- public static readonly string GitHubPage = $"{GitHubHome}/{ProjectRepo}";
+ ///
+ /// The URL to this project's GitHub page.
+ ///
+ public static readonly string GitHubPage = $"{GitHubHome}/{ProjectRepo}";
- ///
- /// The path where program data is stored.
- ///
- ///
- /// (C:\ProgramData\Sparronator9999\YAMDCC on Windows)
- ///
- public static readonly string Data = Path.Combine(
- Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
- ProjectRepo.Split('/')[0], ProjectRepo.Split('/')[1]);
+ ///
+ /// The path where program data is stored.
+ ///
+ ///
+ /// (C:\ProgramData\Sparronator9999\YAMDCC on Windows)
+ ///
+ public static readonly string Data = Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
+ ProjectRepo.Split('/')[0], ProjectRepo.Split('/')[1]);
- ///
- /// The path where YAMDCC service logs are saved.
- ///
- ///
- /// (C:\ProgramData\Sparronator9999\YAMDCC\Logs on Windows)
- ///
- public static readonly string Logs = Path.Combine(Data, "Logs");
+ ///
+ /// The path where YAMDCC service logs are saved.
+ ///
+ ///
+ /// (C:\ProgramData\Sparronator9999\YAMDCC\Logs on Windows)
+ ///
+ public static readonly string Logs = Path.Combine(Data, "Logs");
- public static readonly string GlobalConf = Path.Combine(Data, "GlobalConfig.xml");
+ public static readonly string GlobalConf = Path.Combine(Data, "GlobalConfig.xml");
- ///
- /// The path where the currently applied YAMDCC config is saved.
- ///
- ///
- /// (C:\ProgramData\Sparronator9999\YAMDCC\CurrentConfig.xml on Windows)
- ///
- public static readonly string CurrentConfig = Path.Combine(Data, "CurrentConfig.xml");
+ ///
+ /// The path where the currently applied YAMDCC config is saved.
+ ///
+ ///
+ /// (C:\ProgramData\Sparronator9999\YAMDCC\CurrentConfig.xml on Windows)
+ ///
+ public static readonly string CurrentConfig = Path.Combine(Data, "CurrentConfig.xml");
- ///
- /// The path where the path to the last saved YAMDCC config is saved.
- ///
- ///
- /// (C:\ProgramData\Sparronator9999\YAMDCC\CurrentConfig.xml on Windows)
- ///
- public static readonly string LastConfig = Path.Combine(Data, "LastConfig");
+ ///
+ /// The path where the path to the last saved YAMDCC config is saved.
+ ///
+ ///
+ /// (C:\ProgramData\Sparronator9999\YAMDCC\CurrentConfig.xml on Windows)
+ ///
+ public static readonly string LastConfig = Path.Combine(Data, "LastConfig");
- public static readonly string ECToConfSuccess = Path.Combine(Data, "ECToConfSuccess");
- public static readonly string ECToConfFail = Path.Combine(Data, "ECToConfFail");
- public static readonly string ECToConfPending = Path.Combine(Data, "ECToConfPending");
- }
+ public static readonly string ECToConfSuccess = Path.Combine(Data, "ECToConfSuccess");
+ public static readonly string ECToConfFail = Path.Combine(Data, "ECToConfFail");
+ public static readonly string ECToConfPending = Path.Combine(Data, "ECToConfPending");
}
diff --git a/YAMDCC.Common/Strings.cs b/YAMDCC.Common/Strings.cs
index d3f422f..2420cd6 100644
--- a/YAMDCC.Common/Strings.cs
+++ b/YAMDCC.Common/Strings.cs
@@ -17,58 +17,57 @@
using System.Globalization;
using System.Resources;
-namespace YAMDCC.Common
+namespace YAMDCC.Common;
+
+///
+/// A resource class for retrieving strings.
+///
+internal static class Strings
{
+ private static ResourceManager resMan;
+
///
- /// A resource class for retrieving strings.
+ /// Gets a string from the underlying resource file.
///
- internal static class Strings
+ ///
+ /// This function internally calls
+ /// to retrieve the string.
+ ///
+ ///
+ /// The name of the string to find.
+ ///
+ ///
+ /// The value of the specified string name, if found.
+ /// null if the string couldn't be found.
+ ///
+ public static string GetString(string name)
{
- private static ResourceManager resMan;
-
- ///
- /// Gets a string from the underlying resource file.
- ///
- ///
- /// This function internally calls
- /// to retrieve the string.
- ///
- ///
- /// The name of the string to find.
- ///
- ///
- /// The value of the specified string name, if found.
- /// null if the string couldn't be found.
- ///
- public static string GetString(string name)
- {
- resMan ??= new ResourceManager(typeof(Strings));
- return resMan.GetString(name, CultureInfo.InvariantCulture);
- }
+ resMan ??= new ResourceManager(typeof(Strings));
+ return resMan.GetString(name, CultureInfo.InvariantCulture);
+ }
- ///
- /// Gets a string from the underlying resource file, and
- /// replaces format objects with their string representation.
- ///
- ///
- /// The name of the string to find.
- ///
- ///
- /// The object to format the string with.
- ///
- ///
- ///
- /// The formatted string corresponding to
- /// the specified string name, if found.
- ///
- /// null if the string couldn't be found.
- ///
- public static string GetString(string name, object arg0)
- {
- string temp = GetString(name);
- return temp is null
- ? null
- : string.Format(CultureInfo.InvariantCulture, temp, arg0);
- }
+ ///
+ /// Gets a string from the underlying resource file, and
+ /// replaces format objects with their string representation.
+ ///
+ ///
+ /// The name of the string to find.
+ ///
+ ///
+ /// The object to format the string with.
+ ///
+ ///
+ ///
+ /// The formatted string corresponding to
+ /// the specified string name, if found.
+ ///
+ /// null if the string couldn't be found.
+ ///
+ public static string GetString(string name, object arg0)
+ {
+ string temp = GetString(name);
+ return temp is null
+ ? null
+ : string.Format(CultureInfo.InvariantCulture, temp, arg0);
}
}
diff --git a/YAMDCC.Common/Utils.cs b/YAMDCC.Common/Utils.cs
index f295650..d5d22cc 100644
--- a/YAMDCC.Common/Utils.cs
+++ b/YAMDCC.Common/Utils.cs
@@ -22,236 +22,233 @@
using System.ServiceProcess;
using System.Windows.Forms;
-namespace YAMDCC.Common
+namespace YAMDCC.Common;
+
+///
+/// A collection of miscellaneous useful utilities
+///
+public static class Utils
{
///
- /// A collection of miscellaneous useful utilities
+ /// Shows an error dialog.
///
- public static class Utils
+ ///
+ /// The message to show in the error dialog.
+ ///
+ ///
+ /// One of the values.
+ ///
+ public static DialogResult ShowError(string message)
{
- ///
- /// Shows an error dialog.
- ///
- ///
- /// The message to show in the error dialog.
- ///
- ///
- /// One of the values.
- ///
- public static DialogResult ShowError(string message)
- {
- return MessageBox.Show(message, "Error",
- MessageBoxButtons.OK, MessageBoxIcon.Error);
- }
-
- public static string GetVerString()
- {
- // format: X.Y.Z-SUFFIX[.W]+REVISION,
- // where W is a beta/release candidate version if applicable
- string prodVer = Application.ProductVersion;
+ return MessageBox.Show(message, "Error",
+ MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
- string suffix;
- if (prodVer.Contains("-"))
- {
- // remove the version number (SUFFIX[.W]+REVISION at this point):
- suffix = prodVer.Remove(0, prodVer.IndexOf('-') + 1);
+ public static string GetVerString()
+ {
+ // format: X.Y.Z-SUFFIX[.W]+REVISION,
+ // where W is a beta/release candidate version if applicable
+ string prodVer = Application.ProductVersion;
- // remove Git hash, if it exists (for "dev" detection)
- if (suffix.Contains("+"))
- {
- suffix = suffix.Remove(suffix.IndexOf('+'));
- }
- }
- else
- {
- // suffix probably doesn't exist...
- suffix = string.Empty;
- }
+ string suffix;
+ if (prodVer.Contains("-"))
+ {
+ // remove the version number (SUFFIX[.W]+REVISION at this point):
+ suffix = prodVer.Remove(0, prodVer.IndexOf('-') + 1);
- switch (suffix.ToLowerInvariant())
+ // remove Git hash, if it exists (for "dev" detection)
+ if (suffix.Contains("+"))
{
- case "release":
- // only show the version number (e.g. X.Y.Z):
- return prodVer.Remove(prodVer.IndexOf('-'));
- case "dev":
- return prodVer.Contains("+")
- // probably a snapshot release (e.g. X.Y.Z-SNAPSHOT+REVISION);
- // show shortened Git commit hash if it exists:
- ? prodVer.Remove(prodVer.IndexOf('+') + 8)
- // Return the product version if not in expected format
- : prodVer;
- default: // beta, RC, etc.
- return prodVer.Contains(".") && prodVer.Contains("+")
- // Beta releases should be in format X.Y.Z-beta.W+REVISION.
- // Remove the revision (i.e. only show X.Y.Z-beta.W):
- ? prodVer.Remove(prodVer.IndexOf('+'))
- // Return the product version if not in expected format
- : prodVer;
+ suffix = suffix.Remove(suffix.IndexOf('+'));
}
}
-
- ///
- /// Gets the Git revision of this program, if available.
- ///
- ///
- /// The Git hash of the program version if available,
- /// otherwise .
- ///
- public static string GetRevision()
+ else
{
- string prodVer = Application.ProductVersion;
-
- return prodVer.Contains("+")
- ? prodVer.Remove(0, prodVer.IndexOf('+') + 1)
- : string.Empty;
+ // suffix probably doesn't exist...
+ suffix = string.Empty;
}
- public static bool IsAdmin()
+ return suffix.ToLowerInvariant() switch
{
- WindowsIdentity identity = WindowsIdentity.GetCurrent();
- try
- {
- WindowsPrincipal principal = new(identity);
- return principal.IsInRole(WindowsBuiltInRole.Administrator);
- }
- catch
- {
- return false;
- }
- finally
- {
- identity.Dispose();
- }
- }
+ // only show the version number (e.g. X.Y.Z):
+ "release" => prodVer.Remove(prodVer.IndexOf('-')),
+ "dev" => prodVer.Contains("+")
+ // probably a snapshot release (e.g. X.Y.Z-SNAPSHOT+REVISION);
+ // show shortened Git commit hash if it exists:
+ ? prodVer.Remove(prodVer.IndexOf('+') + 8)
+ // Return the product version if not in expected format
+ : prodVer,
+ // everything else (i.e. beta, RC, etc.)
+ _ => prodVer.Contains(".") && prodVer.Contains("+")
+ // Beta releases should be in format X.Y.Z-beta.W+REVISION.
+ // Remove the revision (i.e. only show X.Y.Z-beta.W):
+ ? prodVer.Remove(prodVer.IndexOf('+'))
+ // Return the product version if not in expected format
+ : prodVer,
+ };
+ }
- ///
- /// Installs the specified .NET Framework
- /// service to the local computer.
- ///
- ///
- /// The service is not started automatically. Use
- /// to start it if needed.
- ///
- ///
- /// The path to the service executable.
- ///
- ///
- /// true if the service installation
- /// was successful, otherwise false.
- ///
- public static bool InstallService(string svcExe)
- {
- string runtimePath = RuntimeEnvironment.GetRuntimeDirectory();
- int exitCode = RunCmd($"{runtimePath}\\installutil.exe", $"{svcExe}.exe");
- DeleteInstallUtilLogs();
- return exitCode == 0;
- }
+ ///
+ /// Gets the Git revision of this program, if available.
+ ///
+ ///
+ /// The Git hash of the program version if available,
+ /// otherwise .
+ ///
+ public static string GetRevision()
+ {
+ string prodVer = Application.ProductVersion;
- ///
- /// Uninstalls the specified .NET Framework
- /// service from the local computer.
- ///
- ///
- /// The path to the service executable.
- ///
- ///
- /// true if the service uninstallation
- /// was successful, otherwise false.
- ///
- public static bool UninstallService(string svcExe)
- {
- string runtimePath = RuntimeEnvironment.GetRuntimeDirectory();
- int exitCode = RunCmd($"{runtimePath}\\installutil.exe", $"/u {svcExe}.exe");
- DeleteInstallUtilLogs();
- return exitCode == 0;
- }
+ return prodVer.Contains("+")
+ ? prodVer.Remove(0, prodVer.IndexOf('+') + 1)
+ : string.Empty;
+ }
- ///
- /// Starts the specified service.
- ///
- ///
- /// The service name, as shown in services.msc
- /// (NOT to be confused with its display name).
- ///
- ///
- /// true if the service started
- /// successfully, otherwise false.
- ///
- public static bool StartService(string svcName)
+ public static bool IsAdmin()
+ {
+ WindowsIdentity identity = WindowsIdentity.GetCurrent();
+ try
{
- return RunCmd("net.exe", $"start {svcName}") == 0;
+ WindowsPrincipal principal = new(identity);
+ return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
-
- ///
- /// Stops the specified service.
- ///
- ///
- /// The service name, as shown in services.msc
- /// (NOT to be confused with its display name).
- ///
- ///
- /// true if the service was stopped
- /// successfully, otherwise false.
- ///
- public static bool StopService(string svcName)
+ catch
{
- return RunCmd("net.exe", $"stop {svcName}") == 0;
+ return false;
}
-
- ///
- /// Checks to see if the specified service
- /// is installed on the computer.
- ///
- ///
- /// The service name, as shown in services.msc
- /// (NOT to be confused with its display name).
- ///
- ///
- /// true if the service was
- /// found, otherwise false.
- ///
- public static bool ServiceExists(string svcName)
+ finally
{
- return ServiceController.GetServices().Any(s => s.ServiceName == svcName);
+ identity.Dispose();
}
+ }
- private static void DeleteInstallUtilLogs()
+ ///
+ /// Installs the specified .NET Framework
+ /// service to the local computer.
+ ///
+ ///
+ /// The service is not started automatically. Use
+ /// to start it if needed.
+ ///
+ ///
+ /// The path to the service executable.
+ ///
+ ///
+ /// true if the service installation
+ /// was successful, otherwise false.
+ ///
+ public static bool InstallService(string svcExe)
+ {
+ string runtimePath = RuntimeEnvironment.GetRuntimeDirectory();
+ int exitCode = RunCmd($"{runtimePath}\\installutil.exe", $"{svcExe}.exe");
+ DeleteInstallUtilLogs();
+ return exitCode == 0;
+ }
+
+ ///
+ /// Uninstalls the specified .NET Framework
+ /// service from the local computer.
+ ///
+ ///
+ /// The path to the service executable.
+ ///
+ ///
+ /// true if the service uninstallation
+ /// was successful, otherwise false.
+ ///
+ public static bool UninstallService(string svcExe)
+ {
+ string runtimePath = RuntimeEnvironment.GetRuntimeDirectory();
+ int exitCode = RunCmd($"{runtimePath}\\installutil.exe", $"/u {svcExe}.exe");
+ DeleteInstallUtilLogs();
+ return exitCode == 0;
+ }
+
+ ///
+ /// Starts the specified service.
+ ///
+ ///
+ /// The service name, as shown in services.msc
+ /// (NOT to be confused with its display name).
+ ///
+ ///
+ /// true if the service started
+ /// successfully, otherwise false.
+ ///
+ public static bool StartService(string svcName)
+ {
+ return RunCmd("net.exe", $"start {svcName}") == 0;
+ }
+
+ ///
+ /// Stops the specified service.
+ ///
+ ///
+ /// The service name, as shown in services.msc
+ /// (NOT to be confused with its display name).
+ ///
+ ///
+ /// true if the service was stopped
+ /// successfully, otherwise false.
+ ///
+ public static bool StopService(string svcName)
+ {
+ return RunCmd("net.exe", $"stop {svcName}") == 0;
+ }
+
+ ///
+ /// Checks to see if the specified service
+ /// is installed on the computer.
+ ///
+ ///
+ /// The service name, as shown in services.msc
+ /// (NOT to be confused with its display name).
+ ///
+ ///
+ /// true if the service was
+ /// found, otherwise false.
+ ///
+ public static bool ServiceExists(string svcName)
+ {
+ return ServiceController.GetServices().Any(s => s.ServiceName == svcName);
+ }
+
+ private static void DeleteInstallUtilLogs()
+ {
+ foreach (string file in Directory.GetFiles(".", "*.InstallLog", SearchOption.TopDirectoryOnly))
{
- foreach (string file in Directory.GetFiles(".", "*.InstallLog", SearchOption.TopDirectoryOnly))
+ try
{
- try
- {
- File.Delete(file);
- }
- catch (DirectoryNotFoundException) { }
+ File.Delete(file);
}
+ catch (DirectoryNotFoundException) { }
}
+ }
- public static int RunCmd(string exe, string args, bool admin = true)
+ public static int RunCmd(string exe, string args, bool admin = true)
+ {
+ bool shellExecute = false;
+ if (admin && !IsAdmin())
{
- bool shellExecute = false;
- if (admin && !IsAdmin())
- {
- // if running unprivileged, we can't create an admin process
- // directly, so use shell execute (creating new cmd window) instead
- shellExecute = true;
- }
+ // if running unprivileged, we can't create an admin process
+ // directly, so use shell execute (creating new cmd window) instead
+ shellExecute = true;
+ }
- Process p = new()
+ Process p = new()
+ {
+ StartInfo = new ProcessStartInfo(exe)
{
- StartInfo = new ProcessStartInfo(exe)
- {
- CreateNoWindow = true,
- UseShellExecute = shellExecute,
- Verb = admin ? "runas" : string.Empty,
- Arguments = args,
- },
- };
+ CreateNoWindow = true,
+ UseShellExecute = shellExecute,
+ Verb = admin ? "runas" : string.Empty,
+ Arguments = args,
+ },
+ };
- p.Start();
- p.WaitForExit();
+ p.Start();
+ p.WaitForExit();
- return p.ExitCode;
- }
+ return p.ExitCode;
}
}
diff --git a/YAMDCC.Config/ChargeLimitConf.cs b/YAMDCC.Config/ChargeLimitConf.cs
index 0eb888a..ecbd37d 100644
--- a/YAMDCC.Config/ChargeLimitConf.cs
+++ b/YAMDCC.Config/ChargeLimitConf.cs
@@ -16,35 +16,34 @@
using System.Xml.Serialization;
-namespace YAMDCC.Config
+namespace YAMDCC.Config;
+
+///
+/// Represents a charge limit config for a laptop.
+///
+public sealed class ChargeLimitConf
{
///
- /// Represents a charge limit config for a laptop.
+ /// The register that controls the charge limit.
///
- public sealed class ChargeLimitConf
- {
- ///
- /// The register that controls the charge limit.
- ///
- [XmlElement]
- public byte Reg { get; set; }
+ [XmlElement]
+ public byte Reg { get; set; }
- ///
- /// The value that corresponds to 0% charge limit (i.e. disabled).
- ///
- [XmlElement]
- public byte MinVal { get; set; }
+ ///
+ /// The value that corresponds to 0% charge limit (i.e. disabled).
+ ///
+ [XmlElement]
+ public byte MinVal { get; set; }
- ///
- /// The value that corresponds to 100% charge limit.
- ///
- [XmlElement]
- public byte MaxVal { get; set; }
+ ///
+ /// The value that corresponds to 100% charge limit.
+ ///
+ [XmlElement]
+ public byte MaxVal { get; set; }
- ///
- /// The currently set charge limit value.
- ///
- [XmlElement]
- public byte CurVal { get; set; }
- }
+ ///
+ /// The currently set charge limit value.
+ ///
+ [XmlElement]
+ public byte CurVal { get; set; }
}
diff --git a/YAMDCC.Config/FanConf.cs b/YAMDCC.Config/FanConf.cs
index 069b59c..1a73645 100644
--- a/YAMDCC.Config/FanConf.cs
+++ b/YAMDCC.Config/FanConf.cs
@@ -16,85 +16,84 @@
using System.Xml.Serialization;
-namespace YAMDCC.Config
+namespace YAMDCC.Config;
+
+///
+/// Represents a configuration for a fan in the target laptop.
+///
+public sealed class FanConf
{
///
- /// Represents a configuration for a fan in the target laptop.
+ /// The display name of the fan in the config editor.
///
- public sealed class FanConf
- {
- ///
- /// The display name of the fan in the config editor.
- ///
- [XmlElement]
- public string Name { get; set; }
+ [XmlElement]
+ public string Name { get; set; }
- ///
- /// The minimum possible register value for the fan speed.
- ///
- [XmlElement]
- public byte MinSpeed { get; set; }
+ ///
+ /// The minimum possible register value for the fan speed.
+ ///
+ [XmlElement]
+ public byte MinSpeed { get; set; }
- ///
- /// The maximum possible register value for the fan speed.
- ///
- [XmlElement]
- public byte MaxSpeed { get; set; }
+ ///
+ /// The maximum possible register value for the fan speed.
+ ///
+ [XmlElement]
+ public byte MaxSpeed { get; set; }
- ///
- /// The zero-based index of the to apply for this fan.
- ///
- [XmlElement]
- public int CurveSel { get; set; }
+ ///
+ /// The zero-based index of the to apply for this fan.
+ ///
+ [XmlElement]
+ public int CurveSel { get; set; }
- ///
- /// The register to read to get the fan speed percentage.
- ///
- [XmlElement]
- public byte SpeedReadReg { get; set; }
+ ///
+ /// The register to read to get the fan speed percentage.
+ ///
+ [XmlElement]
+ public byte SpeedReadReg { get; set; }
- ///
- /// The register to read to get the temperature
- /// of the component that controls this fan's speed.
- ///
- [XmlElement]
- public byte TempReadReg { get; set; }
+ ///
+ /// The register to read to get the temperature
+ /// of the component that controls this fan's speed.
+ ///
+ [XmlElement]
+ public byte TempReadReg { get; set; }
- ///
- /// Contains information on how to calculate the fan RPM.
- ///
- ///
- /// May be null.
- ///
- [XmlElement]
- public FanRPMConf RPMConf { get; set; }
+ ///
+ /// Contains information on how to calculate the fan RPM.
+ ///
+ ///
+ /// May be null.
+ ///
+ [XmlElement]
+ public FanRPMConf RPMConf { get; set; }
- ///
- /// The registers that the up thresholds are written to.
- ///
- [XmlArray]
- public byte[] UpThresholdRegs { get; set; }
+ ///
+ /// The registers that the up thresholds are written to.
+ ///
+ [XmlArray]
+ public byte[] UpThresholdRegs { get; set; }
- ///
- /// The registers that the down thresholds are written to.
- ///
- [XmlArray]
- public byte[] DownThresholdRegs { get; set; }
+ ///
+ /// The registers that the down thresholds are written to.
+ ///
+ [XmlArray]
+ public byte[] DownThresholdRegs { get; set; }
- ///
- /// The registers to write a fan speed profile to.
- ///
- [XmlArray]
- public byte[] FanCurveRegs { get; set; }
+ ///
+ /// The registers to write a fan speed profile to.
+ ///
+ [XmlArray]
+ public byte[] FanCurveRegs { get; set; }
- ///
- /// The list of s associated with this fan.
- ///
- ///
- /// If the base config is a template, this may be null,
- /// otherwise at least one fan curve (the "default" curve) must exist.
- ///
- [XmlArray]
- public FanCurveConf[] FanCurveConfs { get; set; }
- }
+ ///
+ /// The list of s associated with this fan.
+ ///
+ ///
+ /// If the base config is a template, this may be null,
+ /// otherwise at least one fan curve (the "default" curve) must exist.
+ ///
+ [XmlArray]
+ public FanCurveConf[] FanCurveConfs { get; set; }
}
diff --git a/YAMDCC.Config/FanCurveConf.cs b/YAMDCC.Config/FanCurveConf.cs
index c3b1245..6a313e5 100644
--- a/YAMDCC.Config/FanCurveConf.cs
+++ b/YAMDCC.Config/FanCurveConf.cs
@@ -16,51 +16,50 @@
using System.Xml.Serialization;
-namespace YAMDCC.Config
+namespace YAMDCC.Config;
+
+///
+/// Represents a fan profile (a.k.a. fan curve) config.
+///
+public sealed class FanCurveConf
{
///
- /// Represents a fan profile (a.k.a. fan curve) config.
+ /// The name of the fan profile.
///
- public sealed class FanCurveConf
- {
- ///
- /// The name of the fan profile.
- ///
- [XmlElement]
- public string Name { get; set; }
+ [XmlElement]
+ public string Name { get; set; }
- ///
- /// The description of the fan profile.
- ///
- [XmlElement]
- public string Desc { get; set; }
+ ///
+ /// The description of the fan profile.
+ ///
+ [XmlElement]
+ public string Desc { get; set; }
- ///
- /// The fan speeds and associated up and down thresholds.
- ///
- [XmlArray]
- public TempThreshold[] TempThresholds { get; set; }
+ ///
+ /// The fan speeds and associated up and down thresholds.
+ ///
+ [XmlArray]
+ public TempThreshold[] TempThresholds { get; set; }
- ///
- /// Creates a deep copy of this .
- ///
- ///
- /// A copy of this .
- ///
- public FanCurveConf Copy()
- {
- // create a shallow copy of this FanCurveConfig
- FanCurveConf newCfg = (FanCurveConf)MemberwiseClone();
+ ///
+ /// Creates a deep copy of this .
+ ///
+ ///
+ /// A copy of this .
+ ///
+ public FanCurveConf Copy()
+ {
+ // create a shallow copy of this FanCurveConfig
+ FanCurveConf newCfg = (FanCurveConf)MemberwiseClone();
- // create a copy of everything that didn't get copied by the above
- newCfg.Name = string.Copy(Name);
- newCfg.Desc = string.Copy(Desc);
- newCfg.TempThresholds = new TempThreshold[TempThresholds.Length];
- for (int i = 0; i < newCfg.TempThresholds.Length; i++)
- {
- newCfg.TempThresholds[i] = TempThresholds[i].Copy();
- }
- return newCfg;
+ // create a copy of everything that didn't get copied by the above
+ newCfg.Name = string.Copy(Name);
+ newCfg.Desc = string.Copy(Desc);
+ newCfg.TempThresholds = new TempThreshold[TempThresholds.Length];
+ for (int i = 0; i < newCfg.TempThresholds.Length; i++)
+ {
+ newCfg.TempThresholds[i] = TempThresholds[i].Copy();
}
+ return newCfg;
}
}
diff --git a/YAMDCC.Config/FanRPMConf.cs b/YAMDCC.Config/FanRPMConf.cs
index e93efcb..6d3775b 100644
--- a/YAMDCC.Config/FanRPMConf.cs
+++ b/YAMDCC.Config/FanRPMConf.cs
@@ -16,52 +16,51 @@
using System.Xml.Serialization;
-namespace YAMDCC.Config
+namespace YAMDCC.Config;
+
+///
+/// Represents a configuration describing how
+/// a fan RPM is obtained and displayed.
+///
+public sealed class FanRPMConf
{
///
- /// Represents a configuration describing how
- /// a fan RPM is obtained and displayed.
+ /// The register to read to get the fan RPM.
///
- public sealed class FanRPMConf
- {
- ///
- /// The register to read to get the fan RPM.
- ///
- [XmlElement]
- public byte ReadReg { get; set; }
+ [XmlElement]
+ public byte ReadReg { get; set; }
- ///
- /// Is the RPM value stored as a word (16-bit) or byte (8-bit)?
- ///
- [XmlElement]
- public bool Is16Bit { get; set; }
+ ///
+ /// Is the RPM value stored as a word (16-bit) or byte (8-bit)?
+ ///
+ [XmlElement]
+ public bool Is16Bit { get; set; }
- ///
- /// Is the RPM value big-endian? This will only have an
- /// effect if is set to true.
- ///
- [XmlElement]
- public bool IsBigEndian { get; set; }
+ ///
+ /// Is the RPM value big-endian? This will only have an
+ /// effect if is set to true.
+ ///
+ [XmlElement]
+ public bool IsBigEndian { get; set; }
- ///
- /// The value to multiply (or divide, if
- /// is true) the read RPM value by.
- ///
- [XmlElement]
- public int RPMMult { get; set; } = 1;
+ ///
+ /// The value to multiply (or divide, if
+ /// is true) the read RPM value by.
+ ///
+ [XmlElement]
+ public int RPMMult { get; set; } = 1;
- ///
- /// If true, divides the read RPM value by
- /// instead of multiplying.
- ///
- [XmlElement]
- public bool DivideByMult { get; set; }
+ ///
+ /// If true, divides the read RPM value by
+ /// instead of multiplying.
+ ///
+ [XmlElement]
+ public bool DivideByMult { get; set; }
- ///
- /// Set to true if the read RPM value starts high
- /// and decreases as the fan speed increases.
- ///
- [XmlElement]
- public bool Invert { get; set; }
- }
+ ///
+ /// Set to true if the read RPM value starts high
+ /// and decreases as the fan speed increases.
+ ///
+ [XmlElement]
+ public bool Invert { get; set; }
}
diff --git a/YAMDCC.Config/FullBlastConf.cs b/YAMDCC.Config/FullBlastConf.cs
index e8bd5f2..7582e97 100644
--- a/YAMDCC.Config/FullBlastConf.cs
+++ b/YAMDCC.Config/FullBlastConf.cs
@@ -16,28 +16,27 @@
using System.Xml.Serialization;
-namespace YAMDCC.Config
+namespace YAMDCC.Config;
+
+///
+/// Represents a Full Blast configuration.
+///
+public sealed class FullBlastConf
{
///
- /// Represents a Full Blast configuration.
+ /// The register that controls the Full Blast function.
///
- public sealed class FullBlastConf
- {
- ///
- /// The register that controls the Full Blast function.
- ///
- [XmlElement]
- public byte Reg { get; set; }
+ [XmlElement]
+ public byte Reg { get; set; }
- ///
- /// A bitmask that controls which EC register
- /// bits to toggle when toggling Full Blast.
- ///
- ///
- /// For example, 128 (0x80, or 10000000b) would
- /// toggle the MSB of the Full Blast register.
- ///
- [XmlElement]
- public byte Mask { get; set; }
- }
+ ///
+ /// A bitmask that controls which EC register
+ /// bits to toggle when toggling Full Blast.
+ ///
+ ///
+ /// For example, 128 (0x80, or 10000000b) would
+ /// toggle the MSB of the Full Blast register.
+ ///
+ [XmlElement]
+ public byte Mask { get; set; }
}
diff --git a/YAMDCC.Config/KeyLightConf.cs b/YAMDCC.Config/KeyLightConf.cs
index 6cc3707..c9aa5a4 100644
--- a/YAMDCC.Config/KeyLightConf.cs
+++ b/YAMDCC.Config/KeyLightConf.cs
@@ -16,31 +16,30 @@
using System.Xml.Serialization;
-namespace YAMDCC.Config
+namespace YAMDCC.Config;
+
+///
+/// Represents a configuration for the keyboard backlight in a laptop.
+///
+public sealed class KeyLightConf
{
///
- /// Represents a configuration for the keyboard backlight in a laptop.
+ /// The register that controls the keyboard backlight.
///
- public sealed class KeyLightConf
- {
- ///
- /// The register that controls the keyboard backlight.
- ///
- [XmlElement]
- public byte Reg { get; set; }
+ [XmlElement]
+ public byte Reg { get; set; }
- ///
- /// The value that turns off the backlight
- /// (or reduces it to its minimum brightness).
- ///
- [XmlElement]
- public byte MinVal { get; set; }
+ ///
+ /// The value that turns off the backlight
+ /// (or reduces it to its minimum brightness).
+ ///
+ [XmlElement]
+ public byte MinVal { get; set; }
- ///
- /// The value that sets the keyboard
- /// backlight to the maximum brightness.
- ///
- [XmlElement]
- public byte MaxVal { get; set; }
- }
+ ///
+ /// The value that sets the keyboard
+ /// backlight to the maximum brightness.
+ ///
+ [XmlElement]
+ public byte MaxVal { get; set; }
}
diff --git a/YAMDCC.Config/KeySwapConf.cs b/YAMDCC.Config/KeySwapConf.cs
index 679d933..2f7dd05 100644
--- a/YAMDCC.Config/KeySwapConf.cs
+++ b/YAMDCC.Config/KeySwapConf.cs
@@ -16,35 +16,34 @@
using System.Xml.Serialization;
-namespace YAMDCC.Config
+namespace YAMDCC.Config;
+
+///
+/// Represents a configuration for the Win/Fn key swap feature of a laptop.
+///
+public sealed class KeySwapConf
{
///
- /// Represents a configuration for the Win/Fn key swap feature of a laptop.
+ /// The register that controls the Win/Fn key swap state.
///
- public sealed class KeySwapConf
- {
- ///
- /// The register that controls the Win/Fn key swap state.
- ///
- [XmlElement]
- public byte Reg { get; set; }
+ [XmlElement]
+ public byte Reg { get; set; }
- ///
- /// Is the Win/Fn key swap feature enabled?
- ///
- [XmlElement]
- public bool Enabled { get; set; }
+ ///
+ /// Is the Win/Fn key swap feature enabled?
+ ///
+ [XmlElement]
+ public bool Enabled { get; set; }
- ///
- /// The value to turn on Win/Fn key swapping.
- ///
- [XmlElement]
- public byte OnVal { get; set; }
+ ///
+ /// The value to turn on Win/Fn key swapping.
+ ///
+ [XmlElement]
+ public byte OnVal { get; set; }
- ///
- /// The value to turn off Win/Fn key swapping.
- ///
- [XmlElement]
- public byte OffVal { get; set; }
- }
+ ///
+ /// The value to turn off Win/Fn key swapping.
+ ///
+ [XmlElement]
+ public byte OffVal { get; set; }
}
diff --git a/YAMDCC.Config/PerfMode.cs b/YAMDCC.Config/PerfMode.cs
index f8b1b91..e6ee4e4 100644
--- a/YAMDCC.Config/PerfMode.cs
+++ b/YAMDCC.Config/PerfMode.cs
@@ -16,31 +16,30 @@
using System.Xml.Serialization;
-namespace YAMDCC.Config
+namespace YAMDCC.Config;
+
+///
+/// Represents a configuration for an
+/// individual performance mode of a laptop.
+///
+public sealed class PerfMode
{
///
- /// Represents a configuration for an
- /// individual performance mode of a laptop.
+ /// The name of the performance mode.
///
- public sealed class PerfMode
- {
- ///
- /// The name of the performance mode.
- ///
- [XmlElement]
- public string Name { get; set; }
+ [XmlElement]
+ public string Name { get; set; }
- ///
- /// The description of the performance mode.
- ///
- [XmlElement]
- public string Desc { get; set; }
+ ///
+ /// The description of the performance mode.
+ ///
+ [XmlElement]
+ public string Desc { get; set; }
- ///
- /// The value to write to the EC register
- /// when this performance mode is selected.
- ///
- [XmlElement]
- public byte Value { get; set; }
- }
+ ///
+ /// The value to write to the EC register
+ /// when this performance mode is selected.
+ ///
+ [XmlElement]
+ public byte Value { get; set; }
}
diff --git a/YAMDCC.Config/PerfModeConf.cs b/YAMDCC.Config/PerfModeConf.cs
index 0320c1b..f4d28f5 100644
--- a/YAMDCC.Config/PerfModeConf.cs
+++ b/YAMDCC.Config/PerfModeConf.cs
@@ -16,31 +16,30 @@
using System.Xml.Serialization;
-namespace YAMDCC.Config
+namespace YAMDCC.Config;
+
+///
+/// Represents a configuration for the performance modes of a laptop
+/// (separate from the Windows power plans).
+///
+public sealed class PerfModeConf
{
///
- /// Represents a configuration for the performance modes of a laptop
- /// (separate from the Windows power plans).
+ /// The register that controls the performance mode.
///
- public sealed class PerfModeConf
- {
- ///
- /// The register that controls the performance mode.
- ///
- [XmlElement]
- public byte Reg { get; set; }
+ [XmlElement]
+ public byte Reg { get; set; }
- ///
- /// The currently selected performance mode, as
- /// an index of the available performance modes.
- ///
- [XmlElement]
- public int ModeSel { get; set; }
+ ///
+ /// The currently selected performance mode, as
+ /// an index of the available performance modes.
+ ///
+ [XmlElement]
+ public int ModeSel { get; set; }
- ///
- /// An array of possible performance modes for the laptop.
- ///
- [XmlArray]
- public PerfMode[] PerfModes { get; set; }
- }
+ ///
+ /// An array of possible performance modes for the laptop.
+ ///
+ [XmlArray]
+ public PerfMode[] PerfModes { get; set; }
}
diff --git a/YAMDCC.Config/RegConf.cs b/YAMDCC.Config/RegConf.cs
index e248cef..2e52508 100644
--- a/YAMDCC.Config/RegConf.cs
+++ b/YAMDCC.Config/RegConf.cs
@@ -16,45 +16,44 @@
using System.Xml.Serialization;
-namespace YAMDCC.Config
+namespace YAMDCC.Config;
+
+///
+/// Represents miscellaneous EC register configurations for the target
+/// computer. May be required to enable fan control via YAMDCC.
+///
+///
+/// All RegConfs defined here will be applied on service start (unless disabled).
+///
+public sealed class RegConf
{
///
- /// Represents miscellaneous EC register configurations for the target
- /// computer. May be required to enable fan control via YAMDCC.
+ /// Should this be applied?
///
- ///
- /// All RegConfs defined here will be applied on service start (unless disabled).
- ///
- public sealed class RegConf
- {
- ///
- /// Should this be applied?
- ///
- [XmlElement]
- public bool Enabled { get; set; } = true;
+ [XmlElement]
+ public bool Enabled { get; set; } = true;
- ///
- /// A short name for this EC register config.
- ///
- [XmlElement]
- public string Name { get; set; }
+ ///
+ /// A short name for this EC register config.
+ ///
+ [XmlElement]
+ public string Name { get; set; }
- ///
- /// A longer description of what this config does.
- ///
- [XmlElement]
- public string Desc { get; set; }
+ ///
+ /// A longer description of what this config does.
+ ///
+ [XmlElement]
+ public string Desc { get; set; }
- ///
- /// The register to write to.
- ///
- [XmlElement]
- public byte Reg { get; set; }
+ ///
+ /// The register to write to.
+ ///
+ [XmlElement]
+ public byte Reg { get; set; }
- ///
- /// The value to write to the register.
- ///
- [XmlElement]
- public byte Value { get; set; }
- }
+ ///
+ /// The value to write to the register.
+ ///
+ [XmlElement]
+ public byte Value { get; set; }
}
diff --git a/YAMDCC.Config/TempThreshold.cs b/YAMDCC.Config/TempThreshold.cs
index de9f0d0..baf15f4 100644
--- a/YAMDCC.Config/TempThreshold.cs
+++ b/YAMDCC.Config/TempThreshold.cs
@@ -16,49 +16,48 @@
using System.Xml.Serialization;
-namespace YAMDCC.Config
+namespace YAMDCC.Config;
+
+///
+/// Represents a fan speed/temperature threshold setting for a fan curve.
+///
+public sealed class TempThreshold
{
///
- /// Represents a fan speed/temperature threshold setting for a fan curve.
+ /// The temperature threshold before the fan speeds up to this fan speed.
///
- public sealed class TempThreshold
- {
- ///
- /// The temperature threshold before the fan speeds up to this fan speed.
- ///
- ///
- /// Ignored if this is the last temperature threshold in the list
- /// (i.e. this is the highest fan speed that can be set).
- ///
- [XmlElement]
- public byte UpThreshold { get; set; }
+ ///
+ /// Ignored if this is the last temperature threshold in the list
+ /// (i.e. this is the highest fan speed that can be set).
+ ///
+ [XmlElement]
+ public byte UpThreshold { get; set; }
- ///
- /// The temperature threshold before the fan
- /// slows down to the previous fan speed.
- ///
- ///
- /// Ignored if this is the first temperature threshold in the list
- /// (i.e. this is the default fan speed).
- ///
- [XmlElement]
- public byte DownThreshold { get; set; }
+ ///
+ /// The temperature threshold before the fan
+ /// slows down to the previous fan speed.
+ ///
+ ///
+ /// Ignored if this is the first temperature threshold in the list
+ /// (i.e. this is the default fan speed).
+ ///
+ [XmlElement]
+ public byte DownThreshold { get; set; }
- ///
- /// The target fan speed to set when reaching the up threshold.
- ///
- [XmlElement]
- public byte FanSpeed { get; set; }
+ ///
+ /// The target fan speed to set when reaching the up threshold.
+ ///
+ [XmlElement]
+ public byte FanSpeed { get; set; }
- ///
- /// Creates a copy of this .
- ///
- ///
- /// The copy of this
- ///
- public TempThreshold Copy()
- {
- return (TempThreshold)MemberwiseClone();
- }
+ ///
+ /// Creates a copy of this .
+ ///
+ ///
+ /// The copy of this
+ ///
+ public TempThreshold Copy()
+ {
+ return (TempThreshold)MemberwiseClone();
}
}
diff --git a/YAMDCC.Config/YAMDCC_Config.cs b/YAMDCC.Config/YAMDCC_Config.cs
index 1f941fc..787bab2 100644
--- a/YAMDCC.Config/YAMDCC_Config.cs
+++ b/YAMDCC.Config/YAMDCC_Config.cs
@@ -20,334 +20,333 @@
using System.Xml.Serialization;
using YAMDCC.Common;
-namespace YAMDCC.Config
+namespace YAMDCC.Config;
+
+///
+/// Represents a YAMDCC configuration.
+///
+public sealed class YAMDCC_Config
{
///
- /// Represents a YAMDCC configuration.
+ /// The config version expected when loading a config.
+ ///
+ [XmlIgnore]
+ public const int ExpectedVer = 1;
+
+ ///
+ /// The config version. Should be the same as
+ /// unless the config is newer or invalid.
+ ///
+ [XmlAttribute]
+ public int Ver { get; set; }
+
+ ///
+ /// The manufacturer of the laptop the config was made for.
+ ///
+ [XmlElement]
+ public string Manufacturer { get; set; }
+
+ ///
+ /// The laptop model the config was made for.
+ ///
+ [XmlElement]
+ public string Model { get; set; }
+
+ ///
+ /// The author of the config file.
+ ///
+ [XmlElement]
+ public string Author { get; set; }
+
+ ///
+ /// The list of s associated with the laptop.
+ ///
+ [XmlArray]
+ public FanConf[] FanConfs { get; set; }
+
+ ///
+ /// The laptop's Full Blast config.
+ ///
+ ///
+ /// May be null if not supported on the laptop.
+ ///
+ [XmlElement]
+ public FullBlastConf FullBlastConf { get; set; }
+
+ ///
+ /// The laptop's charge threshold config.
+ ///
+ ///
+ /// May be null if not supported on the laptop.
+ ///
+ [XmlElement]
+ public ChargeLimitConf ChargeLimitConf { get; set; }
+
+ ///
+ /// The laptop's performance mode config.
+ ///
+ ///
+ /// May be null if not supported on the laptop.
+ ///
+ [XmlElement]
+ public PerfModeConf PerfModeConf { get; set; }
+
+ ///
+ /// The laptop's Win/Fn keyboard swap config.
+ ///
+ ///
+ /// May be null if not supported on the laptop.
+ ///
+ [XmlElement]
+ public KeySwapConf KeySwapConf { get; set; }
+
+ ///
+ /// The laptop's keyboard backlight config.
+ ///
+ ///
+ /// May be null if not supported on the laptop.
+ ///
+ [XmlElement]
+ public KeyLightConf KeyLightConf { get; set; }
+
+ ///
+ /// A list of registers to write when applying a fan config.
///
- public sealed class YAMDCC_Config
+ ///
+ /// May be null or empty if not needed.
+ ///
+ [XmlArray]
+ public RegConf[] RegConfs { get; set; }
+
+ ///
+ /// Parses a YAMDCC config XML and returns a
+ /// object.
+ ///
+ ///
+ /// The path to an XML config file.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static YAMDCC_Config Load(string xmlFile)
{
- ///
- /// The config version expected when loading a config.
- ///
- [XmlIgnore]
- public const int ExpectedVer = 1;
-
- ///
- /// The config version. Should be the same as
- /// unless the config is newer or invalid.
- ///
- [XmlAttribute]
- public int Ver { get; set; }
-
- ///
- /// The manufacturer of the laptop the config was made for.
- ///
- [XmlElement]
- public string Manufacturer { get; set; }
-
- ///
- /// The laptop model the config was made for.
- ///
- [XmlElement]
- public string Model { get; set; }
-
- ///
- /// The author of the config file.
- ///
- [XmlElement]
- public string Author { get; set; }
-
- ///
- /// The list of s associated with the laptop.
- ///
- [XmlArray]
- public FanConf[] FanConfs { get; set; }
-
- ///
- /// The laptop's Full Blast config.
- ///
- ///
- /// May be null if not supported on the laptop.
- ///
- [XmlElement]
- public FullBlastConf FullBlastConf { get; set; }
-
- ///
- /// The laptop's charge threshold config.
- ///
- ///
- /// May be null if not supported on the laptop.
- ///
- [XmlElement]
- public ChargeLimitConf ChargeLimitConf { get; set; }
-
- ///
- /// The laptop's performance mode config.
- ///
- ///
- /// May be null if not supported on the laptop.
- ///
- [XmlElement]
- public PerfModeConf PerfModeConf { get; set; }
-
- ///
- /// The laptop's Win/Fn keyboard swap config.
- ///
- ///
- /// May be null if not supported on the laptop.
- ///
- [XmlElement]
- public KeySwapConf KeySwapConf { get; set; }
-
- ///
- /// The laptop's keyboard backlight config.
- ///
- ///
- /// May be null if not supported on the laptop.
- ///
- [XmlElement]
- public KeyLightConf KeyLightConf { get; set; }
-
- ///
- /// A list of registers to write when applying a fan config.
- ///
- ///
- /// May be null or empty if not needed.
- ///
- [XmlArray]
- public RegConf[] RegConfs { get; set; }
-
- ///
- /// Parses a YAMDCC config XML and returns a
- /// object.
- ///
- ///
- /// The path to an XML config file.
- ///
- ///
- ///
- ///
- ///
- public static YAMDCC_Config Load(string xmlFile)
+ XmlSerializer serialiser = new(typeof(YAMDCC_Config));
+ using (XmlReader reader = XmlReader.Create(xmlFile))
{
- XmlSerializer serialiser = new(typeof(YAMDCC_Config));
- using (XmlReader reader = XmlReader.Create(xmlFile))
- {
- YAMDCC_Config cfg = (YAMDCC_Config)serialiser.Deserialize(reader);
- return cfg.IsValid() ? cfg : throw new InvalidConfigException();
- }
+ YAMDCC_Config cfg = (YAMDCC_Config)serialiser.Deserialize(reader);
+ return cfg.IsValid() ? cfg : throw new InvalidConfigException();
}
+ }
- ///
- /// Saves a YAMDCC config to the specified location.
- ///
- ///
- /// The XML file to write to.
- ///
- ///
- ///
- public void Save(string xmlFile)
+ ///
+ /// Saves a YAMDCC config to the specified location.
+ ///
+ ///
+ /// The XML file to write to.
+ ///
+ ///
+ ///
+ public void Save(string xmlFile)
+ {
+ XmlSerializer serializer = new(typeof(YAMDCC_Config));
+ XmlWriterSettings settings = new()
{
- XmlSerializer serializer = new(typeof(YAMDCC_Config));
- XmlWriterSettings settings = new()
- {
- Indent = true,
- IndentChars = "\t",
- };
+ Indent = true,
+ IndentChars = "\t",
+ };
- using (XmlWriter writer = XmlWriter.Create(xmlFile, settings))
- {
- serializer.Serialize(writer, this);
- }
+ using (XmlWriter writer = XmlWriter.Create(xmlFile, settings))
+ {
+ serializer.Serialize(writer, this);
}
+ }
- ///
- /// Performs some validation on the loaded config to make
- /// sure it is in the expected format.
- ///
- ///
- /// This does NOT guarantee the loaded config is valid!
- /// (e.g. register values are not checked)
- ///
- ///
- /// true if the config is valid, otherwise false.
- ///
- private bool IsValid()
+ ///
+ /// Performs some validation on the loaded config to make
+ /// sure it is in the expected format.
+ ///
+ ///
+ /// This does NOT guarantee the loaded config is valid!
+ /// (e.g. register values are not checked)
+ ///
+ ///
+ /// true if the config is valid, otherwise false.
+ ///
+ private bool IsValid()
+ {
+ // Check the config version.
+ // Pretty self-explanatory, if the loaded config is older/newer
+ // than the version expected by the config library, don't bother
+ // checking anything else as some/all of it is probably invalid.
+ if (Ver != ExpectedVer)
{
- // Check the config version.
- // Pretty self-explanatory, if the loaded config is older/newer
- // than the version expected by the config library, don't bother
- // checking anything else as some/all of it is probably invalid.
- if (Ver != ExpectedVer)
+ return false;
+ }
+
+ if (string.IsNullOrEmpty(Manufacturer) ||
+ string.IsNullOrEmpty(Model) ||
+ string.IsNullOrEmpty(Author))
+ {
+ return false;
+ }
+
+ // 1. Check if FanConfigs is not null
+ // 2. Check if there's at least 1 FanConfig
+ if (FanConfs?.Length < 1)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < FanConfs.Length; i++)
+ {
+ FanConf cfg = FanConfs[i];
+
+ if (string.IsNullOrEmpty(cfg.Name))
{
return false;
}
- if (string.IsNullOrEmpty(Manufacturer) ||
- string.IsNullOrEmpty(Model) ||
- string.IsNullOrEmpty(Author))
+ // YAMDCC doesn't handle MinSpeed lower than MaxSpeed,
+ // so return false if MinSpeed is lower or equal to MaxSpeed:
+ if (cfg.MinSpeed >= cfg.MaxSpeed)
{
return false;
}
- // 1. Check if FanConfigs is not null
- // 2. Check if there's at least 1 FanConfig
- if (FanConfs?.Length < 1)
+ // the selected fan curve shouldn't be higher than
+ // the number of fan curves in the config.
+ if (cfg.CurveSel >= FanConfs[i].FanCurveConfs.Length ||
+ cfg.CurveSel < 0)
{
- return false;
+ // if the fan profile selection is out of range,
+ // silently set it to 0 (the first fan curve)
+ // which should always exist:
+ cfg.CurveSel = 0;
}
- for (int i = 0; i < FanConfs.Length; i++)
+ // make sure that:
+ // - there is at least one each of up threshold, down threshold,
+ // and fan curve registers
+ // - there are the same amount of up threshold registers
+ // as down threshold registers
+ // - there is one more fan curve register than up/down threshold registers
+ // - there is at least one fan profile to apply (first should be Default)
+ if (cfg.UpThresholdRegs?.Length < 1 ||
+ cfg.UpThresholdRegs?.Length != cfg.DownThresholdRegs?.Length ||
+ cfg.FanCurveRegs?.Length != cfg.UpThresholdRegs?.Length + 1 ||
+ cfg.FanCurveConfs?.Length < 1)
{
- FanConf cfg = FanConfs[i];
-
- if (string.IsNullOrEmpty(cfg.Name))
- {
- return false;
- }
-
- // YAMDCC doesn't handle MinSpeed lower than MaxSpeed,
- // so return false if MinSpeed is lower or equal to MaxSpeed:
- if (cfg.MinSpeed >= cfg.MaxSpeed)
- {
- return false;
- }
-
- // the selected fan curve shouldn't be higher than
- // the number of fan curves in the config.
- if (cfg.CurveSel >= FanConfs[i].FanCurveConfs.Length ||
- cfg.CurveSel < 0)
- {
- // if the fan profile selection is out of range,
- // silently set it to 0 (the first fan curve)
- // which should always exist:
- cfg.CurveSel = 0;
- }
+ return false;
+ }
- // make sure that:
- // - there is at least one each of up threshold, down threshold,
- // and fan curve registers
- // - there are the same amount of up threshold registers
- // as down threshold registers
- // - there is one more fan curve register than up/down threshold registers
- // - there is at least one fan profile to apply (first should be Default)
- if (cfg.UpThresholdRegs?.Length < 1 ||
- cfg.UpThresholdRegs?.Length != cfg.DownThresholdRegs?.Length ||
- cfg.FanCurveRegs?.Length != cfg.UpThresholdRegs?.Length + 1 ||
- cfg.FanCurveConfs?.Length < 1)
+ for (int j = 0; j < cfg.FanCurveConfs.Length; j++)
+ {
+ FanCurveConf curveCfg = cfg.FanCurveConfs[j];
+ if (string.IsNullOrEmpty(curveCfg.Name) ||
+ string.IsNullOrEmpty(curveCfg.Desc) ||
+ // there should be exactly one temperature threshold
+ // per fan curve register; if there isn't, return false
+ curveCfg.TempThresholds?.Length != cfg.FanCurveRegs.Length)
{
return false;
}
- for (int j = 0; j < cfg.FanCurveConfs.Length; j++)
+ for (int k = 0; k < curveCfg.TempThresholds.Length; k++)
{
- FanCurveConf curveCfg = cfg.FanCurveConfs[j];
- if (string.IsNullOrEmpty(curveCfg.Name) ||
- string.IsNullOrEmpty(curveCfg.Desc) ||
- // there should be exactly one temperature threshold
- // per fan curve register; if there isn't, return false
- curveCfg.TempThresholds?.Length != cfg.FanCurveRegs.Length)
+ if (curveCfg.TempThresholds[k] is null)
{
return false;
}
-
- for (int k = 0; k < curveCfg.TempThresholds.Length; k++)
- {
- if (curveCfg.TempThresholds[k] is null)
- {
- return false;
- }
- }
}
}
+ }
- if (FullBlastConf is not null)
+ if (FullBlastConf is not null)
+ {
+ // full blast mask shouldn't be 0, as that would make it impossible
+ // to change the full blast register's value when full blast toggled on/off
+ if (FullBlastConf.Mask == 0)
{
- // full blast mask shouldn't be 0, as that would make it impossible
- // to change the full blast register's value when full blast toggled on/off
- if (FullBlastConf.Mask == 0)
- {
- return false;
- }
+ return false;
}
+ }
- if (ChargeLimitConf is not null)
+ if (ChargeLimitConf is not null)
+ {
+ // YAMDCC cannot handle a lower min value than max value,
+ // so return false if that's the case for this config
+ if (ChargeLimitConf.MinVal >= ChargeLimitConf.MaxVal)
{
- // YAMDCC cannot handle a lower min value than max value,
- // so return false if that's the case for this config
- if (ChargeLimitConf.MinVal >= ChargeLimitConf.MaxVal)
- {
- return false;
- }
-
- // make sure charge limit to apply is within the config's
- // defined bounds, but don't fail validation if it's not:
- if (ChargeLimitConf.CurVal > ChargeLimitConf.MaxVal - ChargeLimitConf.MinVal)
- {
- ChargeLimitConf.CurVal = ChargeLimitConf.MaxVal;
- }
- else if (ChargeLimitConf.CurVal < 0)
- {
- ChargeLimitConf.CurVal = ChargeLimitConf.MinVal;
- }
+ return false;
}
- if (PerfModeConf is not null)
+ // make sure charge limit to apply is within the config's
+ // defined bounds, but don't fail validation if it's not:
+ if (ChargeLimitConf.CurVal > ChargeLimitConf.MaxVal - ChargeLimitConf.MinVal)
{
- if (PerfModeConf.PerfModes?.Length < 1)
- {
- return false;
- }
-
- // the selected performance mode shouldn't be higher than
- // the number of performance modes in the config
- if (PerfModeConf.ModeSel >= PerfModeConf.PerfModes.Length ||
- PerfModeConf.ModeSel < 0)
- {
- // same as fan profile selection, set the performance
- // mode to the first available performance mode:
- PerfModeConf.ModeSel = 0;
- }
-
- for (int i = 0; i < PerfModeConf.PerfModes.Length; i++)
- {
- PerfMode perfMode = PerfModeConf.PerfModes[i];
-
- if (string.IsNullOrEmpty(perfMode.Name) ||
- string.IsNullOrEmpty(perfMode.Desc))
- {
- return false;
- }
- }
+ ChargeLimitConf.CurVal = ChargeLimitConf.MaxVal;
}
+ else if (ChargeLimitConf.CurVal < 0)
+ {
+ ChargeLimitConf.CurVal = ChargeLimitConf.MinVal;
+ }
+ }
- if (KeySwapConf?.OnVal == KeySwapConf?.OffVal)
+ if (PerfModeConf is not null)
+ {
+ if (PerfModeConf.PerfModes?.Length < 1)
{
return false;
}
- if (KeyLightConf?.MinVal >= KeyLightConf?.MaxVal)
+ // the selected performance mode shouldn't be higher than
+ // the number of performance modes in the config
+ if (PerfModeConf.ModeSel >= PerfModeConf.PerfModes.Length ||
+ PerfModeConf.ModeSel < 0)
{
- return false;
+ // same as fan profile selection, set the performance
+ // mode to the first available performance mode:
+ PerfModeConf.ModeSel = 0;
}
- if (RegConfs?.Length > 0)
+ for (int i = 0; i < PerfModeConf.PerfModes.Length; i++)
{
- for (int i = 0; i < RegConfs.Length; i++)
+ PerfMode perfMode = PerfModeConf.PerfModes[i];
+
+ if (string.IsNullOrEmpty(perfMode.Name) ||
+ string.IsNullOrEmpty(perfMode.Desc))
{
- if (string.IsNullOrEmpty(RegConfs[i].Name) ||
- string.IsNullOrEmpty(RegConfs[i].Desc))
- {
- return false;
- }
+ return false;
}
}
+ }
+
+ if (KeySwapConf?.OnVal == KeySwapConf?.OffVal)
+ {
+ return false;
+ }
+
+ if (KeyLightConf?.MinVal >= KeyLightConf?.MaxVal)
+ {
+ return false;
+ }
- // All other values are considered to be valid; return true.
- // Note that registers aren't checked and are (almost) always
- // expected to be nonzero.
- return true;
+ if (RegConfs?.Length > 0)
+ {
+ for (int i = 0; i < RegConfs.Length; i++)
+ {
+ if (string.IsNullOrEmpty(RegConfs[i].Name) ||
+ string.IsNullOrEmpty(RegConfs[i].Desc))
+ {
+ return false;
+ }
+ }
}
+
+ // All other values are considered to be valid; return true.
+ // Note that registers aren't checked and are (almost) always
+ // expected to be nonzero.
+ return true;
}
}
diff --git a/YAMDCC.ConfigEditor/MainWindow.cs b/YAMDCC.ConfigEditor/MainWindow.cs
index 0c4c9fe..bb38913 100644
--- a/YAMDCC.ConfigEditor/MainWindow.cs
+++ b/YAMDCC.ConfigEditor/MainWindow.cs
@@ -28,1406 +28,1405 @@
using YAMDCC.IPC;
using YAMDCC.Logs;
-namespace YAMDCC.ConfigEditor
+namespace YAMDCC.ConfigEditor;
+
+internal sealed partial class MainWindow : Form
{
- internal sealed partial class MainWindow : Form
- {
- #region Fields
- private readonly Status AppStatus = new();
-
- private readonly CommonConfig GlobalConfig;
-
- ///
- /// The YAMDCC config that is currently open for editing.
- ///
- private YAMDCC_Config Config;
-
- ///
- /// The client that connects to the YAMDCC Service
- ///
- private readonly NamedPipeClient IPCClient =
- new("YAMDCC-Server");
-
- private NumericUpDown[] numUpTs, numDownTs, numFanSpds;
- private TrackBar[] tbFanSpds;
-
- private readonly ToolTip ttMain = new();
-
- private readonly Timer tmrPoll, tmrStatusReset, tmrSvcTimeout;
-
- private int Debug;
- #endregion
-
- public MainWindow()
- {
- InitializeComponent();
-
- // Set the window icon using the application icon.
- // Saves about 8-9 KB from not having to embed the same icon twice.
- Icon = Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location);
-
- // set title text to include program version
- Text = $"YAMDCC config editor - v{Utils.GetVerString()}";
-
- // set literally every tooltip
- tsiLoadConf.ToolTipText = Strings.GetString("ttLoadConf");
- tsiSaveConf.ToolTipText = Strings.GetString("ttSaveConf");
- tsiApply.ToolTipText = Strings.GetString("ttApply");
- tsiRevert.ToolTipText = Strings.GetString("ttRevert");
- tsiExit.ToolTipText = Strings.GetString("ttExit");
- tsiProfAdd.ToolTipText = Strings.GetString("ttProfAdd");
- tsiProfRename.ToolTipText = Strings.GetString("ttProfRen");
- tsiProfChangeDesc.ToolTipText = Strings.GetString("ttProfChangeDesc");
- tsiSwitchAll.ToolTipText = Strings.GetString("ttSwitchAll");
- tsiECtoConf.ToolTipText = Strings.GetString("ttECtoConf");
- tsiProfDel.ToolTipText = Strings.GetString("ttProfDel");
- tsiECMon.ToolTipText = Strings.GetString("ttECMon");
- tsiStopSvc.ToolTipText = Strings.GetString("ttSvcStop");
- tsiUninstall.ToolTipText = Strings.GetString("ttSvcUninstall");
- tsiAbout.ToolTipText = Strings.GetString("ttAbout");
- tsiSource.ToolTipText = Strings.GetString("ttSource");
- ttMain.SetToolTip(cboFanSel, Strings.GetString("ttFanSel"));
- ttMain.SetToolTip(btnProfAdd, Strings.GetString("ttProfAdd"));
- ttMain.SetToolTip(btnProfDel, Strings.GetString("ttProfDel"));
- ttMain.SetToolTip(btnApply, Strings.GetString("ttApply"));
- ttMain.SetToolTip(btnRevert, Strings.GetString("ttRevert"));
-
- tmrPoll = new()
- {
- Interval = 1000,
- };
- tmrPoll.Tick += tmrPoll_Tick;
+ #region Fields
+ private readonly Status AppStatus = new();
- tmrStatusReset = new()
- {
- Interval = 5000,
- };
- tmrStatusReset.Tick += tmrStatusReset_Tick;
+ private readonly CommonConfig GlobalConfig;
- tmrSvcTimeout = new()
- {
- Interval = 10000,
- };
- tmrSvcTimeout.Tick += tmrSvcTimeout_Tick;
+ ///
+ /// The YAMDCC config that is currently open for editing.
+ ///
+ private YAMDCC_Config Config;
- GlobalConfig = CommonConfig.Load();
- if (GlobalConfig.App == "YAMDCC")
- {
- switch (GlobalConfig.LogLevel)
- {
- case LogLevel.None:
- tsiLogNone.Checked = true;
- break;
- case LogLevel.Fatal:
- tsiLogFatal.Checked = true;
- break;
- case LogLevel.Error:
- tsiLogError.Checked = true;
- break;
- case LogLevel.Warn:
- tsiLogWarn.Checked = true;
- break;
- case LogLevel.Info:
- tsiLogInfo.Checked = true;
- break;
- case LogLevel.Debug:
- tsiLogDebug.Checked = true;
- break;
- }
- }
- else
- {
- tsiLogDebug.Checked = true;
- }
+ ///
+ /// The client that connects to the YAMDCC Service
+ ///
+ private readonly NamedPipeClient IPCClient =
+ new("YAMDCC-Server");
- DisableAll();
- }
+ private NumericUpDown[] numUpTs, numDownTs, numFanSpds;
+ private TrackBar[] tbFanSpds;
- #region Events
- private void MainWindow_Load(object sender, EventArgs e)
- {
- IPCClient.ServerMessage += IPC_MessageReceived;
- IPCClient.Error += IPCClient_Error;
- IPCClient.Start();
+ private readonly ToolTip ttMain = new();
- ProgressDialog dlg = new("Connecting to YAMDCC service...",
- (e) => e.Result = !IPCClient.WaitForConnection(5000));
- dlg.ShowDialog();
+ private readonly Timer tmrPoll, tmrStatusReset, tmrSvcTimeout;
- if (dlg.Result is bool b && b)
- {
- throw new TimeoutException(Strings.GetString("exSvcTimeout"));
+ private int Debug;
+ #endregion
+
+ public MainWindow()
+ {
+ InitializeComponent();
+
+ // Set the window icon using the application icon.
+ // Saves about 8-9 KB from not having to embed the same icon twice.
+ Icon = Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location);
+
+ // set title text to include program version
+ Text = $"YAMDCC config editor - v{Utils.GetVerString()}";
+
+ // set literally every tooltip
+ tsiLoadConf.ToolTipText = Strings.GetString("ttLoadConf");
+ tsiSaveConf.ToolTipText = Strings.GetString("ttSaveConf");
+ tsiApply.ToolTipText = Strings.GetString("ttApply");
+ tsiRevert.ToolTipText = Strings.GetString("ttRevert");
+ tsiExit.ToolTipText = Strings.GetString("ttExit");
+ tsiProfAdd.ToolTipText = Strings.GetString("ttProfAdd");
+ tsiProfRename.ToolTipText = Strings.GetString("ttProfRen");
+ tsiProfChangeDesc.ToolTipText = Strings.GetString("ttProfChangeDesc");
+ tsiSwitchAll.ToolTipText = Strings.GetString("ttSwitchAll");
+ tsiECtoConf.ToolTipText = Strings.GetString("ttECtoConf");
+ tsiProfDel.ToolTipText = Strings.GetString("ttProfDel");
+ tsiECMon.ToolTipText = Strings.GetString("ttECMon");
+ tsiStopSvc.ToolTipText = Strings.GetString("ttSvcStop");
+ tsiUninstall.ToolTipText = Strings.GetString("ttSvcUninstall");
+ tsiAbout.ToolTipText = Strings.GetString("ttAbout");
+ tsiSource.ToolTipText = Strings.GetString("ttSource");
+ ttMain.SetToolTip(cboFanSel, Strings.GetString("ttFanSel"));
+ ttMain.SetToolTip(btnProfAdd, Strings.GetString("ttProfAdd"));
+ ttMain.SetToolTip(btnProfDel, Strings.GetString("ttProfDel"));
+ ttMain.SetToolTip(btnApply, Strings.GetString("ttApply"));
+ ttMain.SetToolTip(btnRevert, Strings.GetString("ttRevert"));
+
+ tmrPoll = new()
+ {
+ Interval = 1000,
+ };
+ tmrPoll.Tick += tmrPoll_Tick;
+
+ tmrStatusReset = new()
+ {
+ Interval = 5000,
+ };
+ tmrStatusReset.Tick += tmrStatusReset_Tick;
+
+ tmrSvcTimeout = new()
+ {
+ Interval = 10000,
+ };
+ tmrSvcTimeout.Tick += tmrSvcTimeout_Tick;
+
+ GlobalConfig = CommonConfig.Load();
+ if (GlobalConfig.App == "YAMDCC")
+ {
+ switch (GlobalConfig.LogLevel)
+ {
+ case LogLevel.None:
+ tsiLogNone.Checked = true;
+ break;
+ case LogLevel.Fatal:
+ tsiLogFatal.Checked = true;
+ break;
+ case LogLevel.Error:
+ tsiLogError.Checked = true;
+ break;
+ case LogLevel.Warn:
+ tsiLogWarn.Checked = true;
+ break;
+ case LogLevel.Info:
+ tsiLogInfo.Checked = true;
+ break;
+ case LogLevel.Debug:
+ tsiLogDebug.Checked = true;
+ break;
}
- AppDomain.CurrentDomain.ProcessExit += OnProcessExit;
+ }
+ else
+ {
+ tsiLogDebug.Checked = true;
+ }
- LoadConf(Paths.CurrentConfig);
+ DisableAll();
+ }
- if (Config is not null)
- {
- if (Config.KeyLightConf is null)
- {
- ttMain.SetToolTip(tbKeyLight, Strings.GetString("ttNotSupported"));
- }
- else
- {
- SendServiceMessage(new ServiceCommand(Command.GetKeyLightBright, string.Empty));
- }
- }
+ #region Events
+ private void MainWindow_Load(object sender, EventArgs e)
+ {
+ IPCClient.ServerMessage += IPC_MessageReceived;
+ IPCClient.Error += IPCClient_Error;
+ IPCClient.Start();
- if (File.Exists(Paths.ECToConfFail))
- {
- Utils.ShowError(Strings.GetString("dlgECtoConfErr", Paths.Logs));
- }
- else if (File.Exists(Paths.ECToConfSuccess))
- {
- MessageBox.Show(Strings.GetString("dlgECtoConfSuccess"),
- "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
- }
- try
- {
- File.Delete(Paths.ECToConfSuccess);
- File.Delete(Paths.ECToConfFail);
- }
- catch (DirectoryNotFoundException) { }
+ ProgressDialog dlg = new("Connecting to YAMDCC service...",
+ (e) => e.Result = !IPCClient.WaitForConnection(5000));
+ dlg.ShowDialog();
+
+ if (dlg.Result is bool b && b)
+ {
+ throw new TimeoutException(Strings.GetString("exSvcTimeout"));
}
+ AppDomain.CurrentDomain.ProcessExit += OnProcessExit;
+
+ LoadConf(Paths.CurrentConfig);
- private void MainWindow_Closing(object sender, FormClosingEventArgs e)
+ if (Config is not null)
{
- // Disable Full Blast if it was enabled while the program was running:
- if (chkFullBlast.Checked)
+ if (Config.KeyLightConf is null)
{
- SendServiceMessage(new ServiceCommand(Command.FullBlast, "0"));
+ ttMain.SetToolTip(tbKeyLight, Strings.GetString("ttNotSupported"));
}
- GlobalConfig.App = "YAMDCC";
- try
+ else
{
- GlobalConfig.Save();
+ SendServiceMessage(new ServiceCommand(Command.GetKeyLightBright, string.Empty));
}
- // ignore DirectoryNotFoundException, since we probably closed the
- // window due to uninstalling with data directory delete enabled
- catch (DirectoryNotFoundException) { }
}
- private void OnProcessExit(object sender, EventArgs e)
+ if (File.Exists(Paths.ECToConfFail))
{
- // Close the connection to the YAMDCC
- // Service before exiting the program:
- tmrPoll.Stop();
- IPCClient.Stop();
+ Utils.ShowError(Strings.GetString("dlgECtoConfErr", Paths.Logs));
+ }
+ else if (File.Exists(Paths.ECToConfSuccess))
+ {
+ MessageBox.Show(Strings.GetString("dlgECtoConfSuccess"),
+ "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+ try
+ {
+ File.Delete(Paths.ECToConfSuccess);
+ File.Delete(Paths.ECToConfFail);
+ }
+ catch (DirectoryNotFoundException) { }
+ }
+
+ private void MainWindow_Closing(object sender, FormClosingEventArgs e)
+ {
+ // Disable Full Blast if it was enabled while the program was running:
+ if (chkFullBlast.Checked)
+ {
+ SendServiceMessage(new ServiceCommand(Command.FullBlast, "0"));
+ }
+ GlobalConfig.App = "YAMDCC";
+ try
+ {
+ GlobalConfig.Save();
}
+ // ignore DirectoryNotFoundException, since we probably closed the
+ // window due to uninstalling with data directory delete enabled
+ catch (DirectoryNotFoundException) { }
+ }
+
+ private void OnProcessExit(object sender, EventArgs e)
+ {
+ // Close the connection to the YAMDCC
+ // Service before exiting the program:
+ tmrPoll.Stop();
+ IPCClient.Stop();
+ }
- private void IPC_MessageReceived(object sender, PipeMessageEventArgs e)
+ private void IPC_MessageReceived(object sender, PipeMessageEventArgs e)
+ {
+ tmrSvcTimeout.Stop();
+ string[] args = e.Message.Value.Split(' ');
+ if (args.Length == 1)
{
- tmrSvcTimeout.Stop();
- string[] args = e.Message.Value.Split(' ');
- if (args.Length == 1)
+ switch (e.Message.Response)
{
- switch (e.Message.Response)
+ case Response.Nothing:
{
- case Response.Nothing:
- {
- UpdateStatus(StatusCode.ServiceResponseEmpty);
- break;
- }
- case Response.Success:
+ UpdateStatus(StatusCode.ServiceResponseEmpty);
+ break;
+ }
+ case Response.Success:
+ {
+ HandleSuccessResponse(args);
+ break;
+ }
+ case Response.Error:
+ {
+ if (int.TryParse(args[0], out int value))
{
- HandleSuccessResponse(args);
- break;
+ UpdateStatus(StatusCode.ServiceCommandFail, value);
}
- case Response.Error:
+ break;
+ }
+ case Response.Temp:
+ {
+ if (int.TryParse(args[0], out int value))
{
- if (int.TryParse(args[0], out int value))
- {
- UpdateStatus(StatusCode.ServiceCommandFail, value);
- }
- break;
+ UpdateFanMon(value, 0);
}
- case Response.Temp:
+ break;
+ }
+ case Response.FanSpeed:
+ {
+ if (int.TryParse(args[0], out int value))
{
- if (int.TryParse(args[0], out int value))
- {
- UpdateFanMon(value, 0);
- }
- break;
+ UpdateFanMon(value, 1);
}
- case Response.FanSpeed:
+ break;
+ }
+ case Response.FanRPM:
+ {
+ if (int.TryParse(args[0], out int value))
{
- if (int.TryParse(args[0], out int value))
- {
- UpdateFanMon(value, 1);
- }
- break;
+ UpdateFanMon(value, 2);
}
- case Response.FanRPM:
+ break;
+ }
+ case Response.KeyLightBright:
+ {
+ if (int.TryParse(args[0], out int value))
{
- if (int.TryParse(args[0], out int value))
+ // value received from service should be valid,
+ // but let's check anyway to avoid potential crashes
+ // from non-official YAMDCC services
+ if (value < 0 || value > Config.KeyLightConf.MaxVal - Config.KeyLightConf.MinVal)
{
- UpdateFanMon(value, 2);
+ break;
}
- break;
- }
- case Response.KeyLightBright:
- {
- if (int.TryParse(args[0], out int value))
+
+ tbKeyLight.Invoke(new Action(delegate
{
- // value received from service should be valid,
- // but let's check anyway to avoid potential crashes
- // from non-official YAMDCC services
- if (value < 0 || value > Config.KeyLightConf.MaxVal - Config.KeyLightConf.MinVal)
- {
- break;
- }
-
- tbKeyLight.Invoke(new Action(delegate
- {
- tbKeyLight.Maximum = Config.KeyLightConf.MaxVal - Config.KeyLightConf.MinVal;
- tbKeyLight.Value = value;
- tbKeyLight.Enabled = lblKeyLightLow.Enabled = lblKeyLightHigh.Enabled = true;
- ttMain.SetToolTip(tbKeyLight, Strings.GetString("ttKeyLight"));
- }));
- }
- break;
+ tbKeyLight.Maximum = Config.KeyLightConf.MaxVal - Config.KeyLightConf.MinVal;
+ tbKeyLight.Value = value;
+ tbKeyLight.Enabled = lblKeyLightLow.Enabled = lblKeyLightHigh.Enabled = true;
+ ttMain.SetToolTip(tbKeyLight, Strings.GetString("ttKeyLight"));
+ }));
}
+ break;
}
}
}
+ }
- private void IPCClient_Error(object sender, PipeErrorEventArgs e)
- {
- CrashDialog dlg = new(e.Exception);
- dlg.ShowDialog();
- }
+ private void IPCClient_Error(object sender, PipeErrorEventArgs e)
+ {
+ CrashDialog dlg = new(e.Exception);
+ dlg.ShowDialog();
+ }
- private void HandleSuccessResponse(string[] args)
+ private void HandleSuccessResponse(string[] args)
+ {
+ if (int.TryParse(args[0], out int value))
{
- if (int.TryParse(args[0], out int value))
- {
- Command cmd = (Command)value;
+ Command cmd = (Command)value;
- switch (cmd)
- {
- case Command.ApplyConfig:
- btnApply.Invoke(() => btnApply.Enabled = tsiApply.Enabled = true);
- UpdateStatus(StatusCode.ConfApplySuccess);
- if (Config.KeyLightConf is not null)
- {
- SendServiceMessage(new ServiceCommand(Command.GetKeyLightBright, ""));
- }
- break;
- case Command.FullBlast:
- UpdateStatus(StatusCode.FullBlastToggleSuccess);
- break;
- }
+ switch (cmd)
+ {
+ case Command.ApplyConfig:
+ btnApply.Invoke(() => btnApply.Enabled = tsiApply.Enabled = true);
+ UpdateStatus(StatusCode.ConfApplySuccess);
+ if (Config.KeyLightConf is not null)
+ {
+ SendServiceMessage(new ServiceCommand(Command.GetKeyLightBright, ""));
+ }
+ break;
+ case Command.FullBlast:
+ UpdateStatus(StatusCode.FullBlastToggleSuccess);
+ break;
}
}
+ }
- #region Tool strip menu items
+ #region Tool strip menu items
- #region File
- private void tsiLoadConf_Click(object sender, EventArgs e)
+ #region File
+ private void tsiLoadConf_Click(object sender, EventArgs e)
+ {
+ OpenFileDialog ofd = new()
{
- OpenFileDialog ofd = new()
- {
- AddExtension = true,
- CheckFileExists = true,
- Filter = "YAMDCC config files|*.xml",
- Title = "Load config",
- };
-
- if (ofd.ShowDialog() == DialogResult.OK)
- {
- LoadConf(ofd.FileName);
- SetLastConfPath(ofd.FileName);
- btnRevert.Enabled = tsiRevert.Enabled = false;
- }
- }
+ AddExtension = true,
+ CheckFileExists = true,
+ Filter = "YAMDCC config files|*.xml",
+ Title = "Load config",
+ };
- private void tsiSaveConf_Click(object sender, EventArgs e)
+ if (ofd.ShowDialog() == DialogResult.OK)
{
- SaveFileDialog sfd = new()
- {
- AddExtension = true,
- Filter = "YAMDCC config files|*.xml",
- FileName = Config.Model.Replace(' ', '-'),
- Title = "Save config",
- };
-
- if (sfd.ShowDialog() == DialogResult.OK)
- {
- Config.ChargeLimitConf.CurVal = (byte)(chkChgLim.Checked
- ? numChgLim.Value : 0);
- Config.Save(sfd.FileName);
- SetLastConfPath(sfd.FileName);
- btnRevert.Enabled = tsiRevert.Enabled = false;
- }
+ LoadConf(ofd.FileName);
+ SetLastConfPath(ofd.FileName);
+ btnRevert.Enabled = tsiRevert.Enabled = false;
}
+ }
- private void tsiApply_Click(object sender, EventArgs e)
+ private void tsiSaveConf_Click(object sender, EventArgs e)
+ {
+ SaveFileDialog sfd = new()
{
- ApplyConf();
- }
+ AddExtension = true,
+ Filter = "YAMDCC config files|*.xml",
+ FileName = Config.Model.Replace(' ', '-'),
+ Title = "Save config",
+ };
- private void tsiRevert_Click(object sender, EventArgs e)
+ if (sfd.ShowDialog() == DialogResult.OK)
{
- RevertConf();
+ Config.ChargeLimitConf.CurVal = (byte)(chkChgLim.Checked
+ ? numChgLim.Value : 0);
+ Config.Save(sfd.FileName);
+ SetLastConfPath(sfd.FileName);
+ btnRevert.Enabled = tsiRevert.Enabled = false;
}
+ }
- private void tsiExit_Click(object sender, EventArgs e)
- {
- Close();
- }
- #endregion
+ private void tsiApply_Click(object sender, EventArgs e)
+ {
+ ApplyConf();
+ }
- #region Options
- private void tsiProfAdd_Click(object sender, EventArgs e)
- {
- AddFanProfile();
- }
+ private void tsiRevert_Click(object sender, EventArgs e)
+ {
+ RevertConf();
+ }
- private void tsiProfRename_Click(object sender, EventArgs e)
- {
- FanCurveConf curveCfg = Config.FanConfs[cboFanSel.SelectedIndex]
- .FanCurveConfs[cboProfSel.SelectedIndex];
+ private void tsiExit_Click(object sender, EventArgs e)
+ {
+ Close();
+ }
+ #endregion
- TextInputDialog dlg = new(
- Strings.GetString("dlgProfRen"),
- "Change Profile Name", curveCfg.Name);
- if (dlg.ShowDialog() == DialogResult.OK)
- {
- curveCfg.Name = dlg.Result;
- cboProfSel.Items[cboProfSel.SelectedIndex] = dlg.Result;
- btnRevert.Enabled = tsiRevert.Enabled = true;
- }
- }
+ #region Options
+ private void tsiProfAdd_Click(object sender, EventArgs e)
+ {
+ AddFanProfile();
+ }
- private void tsiProfChangeDesc_Click(object sender, EventArgs e)
- {
- FanCurveConf curveCfg = Config.FanConfs[cboFanSel.SelectedIndex]
- .FanCurveConfs[cboProfSel.SelectedIndex];
- TextInputDialog dlg = new(
- Strings.GetString("dlgProfChangeDesc"),
- "Change Profile Description", curveCfg.Desc, true);
- if (dlg.ShowDialog() == DialogResult.OK)
- {
- curveCfg.Desc = dlg.Result;
- ttMain.SetToolTip(cboProfSel, Strings.GetString(
- "ttProfSel", dlg.Result));
- btnRevert.Enabled = tsiRevert.Enabled = true;
- }
- }
+ private void tsiProfRename_Click(object sender, EventArgs e)
+ {
+ FanCurveConf curveCfg = Config.FanConfs[cboFanSel.SelectedIndex]
+ .FanCurveConfs[cboProfSel.SelectedIndex];
- private void tsiProfDel_Click(object sender, EventArgs e)
+ TextInputDialog dlg = new(
+ Strings.GetString("dlgProfRen"),
+ "Change Profile Name", curveCfg.Name);
+ if (dlg.ShowDialog() == DialogResult.OK)
{
- DelFanProfile();
+ curveCfg.Name = dlg.Result;
+ cboProfSel.Items[cboProfSel.SelectedIndex] = dlg.Result;
+ btnRevert.Enabled = tsiRevert.Enabled = true;
}
+ }
- private void tsiECtoConf_Click(object sender, EventArgs e)
- {
- if (MessageBox.Show(Strings.GetString("dlgECtoConfStart"),
- "Default fan profile from EC?", MessageBoxButtons.YesNo,
- MessageBoxIcon.Information) == DialogResult.Yes)
- {
- StreamWriter sw = new(Paths.ECToConfPending, false);
- try
- {
- sw.Write(1);
- sw.Flush();
- }
- finally
- {
- sw.Close();
- }
- Application.Exit();
- }
+ private void tsiProfChangeDesc_Click(object sender, EventArgs e)
+ {
+ FanCurveConf curveCfg = Config.FanConfs[cboFanSel.SelectedIndex]
+ .FanCurveConfs[cboProfSel.SelectedIndex];
+ TextInputDialog dlg = new(
+ Strings.GetString("dlgProfChangeDesc"),
+ "Change Profile Description", curveCfg.Desc, true);
+ if (dlg.ShowDialog() == DialogResult.OK)
+ {
+ curveCfg.Desc = dlg.Result;
+ ttMain.SetToolTip(cboProfSel, Strings.GetString(
+ "ttProfSel", dlg.Result));
+ btnRevert.Enabled = tsiRevert.Enabled = true;
}
+ }
- private void tsiECMon_Click(object sender, EventArgs e)
+ private void tsiProfDel_Click(object sender, EventArgs e)
+ {
+ DelFanProfile();
+ }
+
+ private void tsiECtoConf_Click(object sender, EventArgs e)
+ {
+ if (MessageBox.Show(Strings.GetString("dlgECtoConfStart"),
+ "Default fan profile from EC?", MessageBoxButtons.YesNo,
+ MessageBoxIcon.Information) == DialogResult.Yes)
{
- if (tsiECMon.Checked)
+ StreamWriter sw = new(Paths.ECToConfPending, false);
+ try
{
- tmrPoll.Start();
- PollEC();
- lblFanSpd.Visible = true;
- lblFanRPM.Visible = true;
- lblTemp.Visible = true;
+ sw.Write(1);
+ sw.Flush();
}
- else
+ finally
{
- tmrPoll.Stop();
- lblFanSpd.Visible = false;
- lblFanRPM.Visible = false;
- lblTemp.Visible = false;
+ sw.Close();
}
+ Application.Exit();
}
+ }
- private void tsiStopSvc_Click(object sender, EventArgs e)
+ private void tsiECMon_Click(object sender, EventArgs e)
+ {
+ if (tsiECMon.Checked)
{
- if (MessageBox.Show(
- Strings.GetString("dlgSvcStop"), "Stop Service",
- MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
- {
- tmrPoll.Stop();
- IPCClient.Stop();
- Hide();
+ tmrPoll.Start();
+ PollEC();
+ lblFanSpd.Visible = true;
+ lblFanRPM.Visible = true;
+ lblTemp.Visible = true;
+ }
+ else
+ {
+ tmrPoll.Stop();
+ lblFanSpd.Visible = false;
+ lblFanRPM.Visible = false;
+ lblTemp.Visible = false;
+ }
+ }
+
+ private void tsiStopSvc_Click(object sender, EventArgs e)
+ {
+ if (MessageBox.Show(
+ Strings.GetString("dlgSvcStop"), "Stop Service",
+ MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
+ {
+ tmrPoll.Stop();
+ IPCClient.Stop();
+ Hide();
- ProgressDialog dlg = new(Strings.GetString("dlgSvcStopping"),
- static (e) =>
+ ProgressDialog dlg = new(Strings.GetString("dlgSvcStopping"),
+ static (e) =>
+ {
+ if (!Utils.StopService("yamdccsvc"))
{
- if (!Utils.StopService("yamdccsvc"))
- {
- Utils.ShowError(Strings.GetString("dlgSvcStopErr"));
- }
- });
- dlg.ShowDialog();
+ Utils.ShowError(Strings.GetString("dlgSvcStopErr"));
+ }
+ });
+ dlg.ShowDialog();
- Close();
- }
+ Close();
}
+ }
- private void tsiUninstall_Click(object sender, EventArgs e)
+ private void tsiUninstall_Click(object sender, EventArgs e)
+ {
+ if (MessageBox.Show(Strings.GetString("dlgUninstall"), "Uninstall Service",
+ MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
{
- if (MessageBox.Show(Strings.GetString("dlgUninstall"), "Uninstall Service",
- MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
+ bool delData = MessageBox.Show(
+ Strings.GetString("dlgSvcDelData", Paths.Data),
+ "Delete configuration data?",
+ MessageBoxButtons.YesNo, MessageBoxIcon.Warning,
+ MessageBoxDefaultButton.Button2) == DialogResult.Yes;
+
+ tmrPoll.Stop();
+ IPCClient.Stop();
+ Hide();
+
+ // Apparently this fixes the YAMDCC service not uninstalling
+ // when YAMDCC is launched by certain means
+ ProgressDialog dlg = new(Strings.GetString("dlgSvcUninstalling"), (e) =>
{
- bool delData = MessageBox.Show(
- Strings.GetString("dlgSvcDelData", Paths.Data),
- "Delete configuration data?",
- MessageBoxButtons.YesNo, MessageBoxIcon.Warning,
- MessageBoxDefaultButton.Button2) == DialogResult.Yes;
-
- tmrPoll.Stop();
- IPCClient.Stop();
- Hide();
-
- // Apparently this fixes the YAMDCC service not uninstalling
- // when YAMDCC is launched by certain means
- ProgressDialog dlg = new(Strings.GetString("dlgSvcUninstalling"), (e) =>
+ if (Utils.StopService("yamdccsvc"))
{
- if (Utils.StopService("yamdccsvc"))
+ if (Utils.UninstallService("yamdccsvc"))
{
- if (Utils.UninstallService("yamdccsvc"))
- {
- // Only delete service data if the
- // service uninstalled successfully
- if (delData)
- {
- Directory.Delete(Paths.Data, true);
- }
- }
- else
+ // Only delete service data if the
+ // service uninstalled successfully
+ if (delData)
{
- Utils.ShowError(Strings.GetString("dlgUninstallErr"));
+ Directory.Delete(Paths.Data, true);
}
}
else
{
- Utils.ShowError(Strings.GetString("dlgSvcStopErr"));
+ Utils.ShowError(Strings.GetString("dlgUninstallErr"));
}
- });
- dlg.ShowDialog();
+ }
+ else
+ {
+ Utils.ShowError(Strings.GetString("dlgSvcStopErr"));
+ }
+ });
+ dlg.ShowDialog();
- Close();
- }
+ Close();
}
- #endregion
+ }
+ #endregion
+
+ #region Help
+ private void tsiAbout_Click(object sender, EventArgs e)
+ {
+ new VersionDialog().ShowDialog();
+ }
+
+ private void tsiSrc_Click(object sender, EventArgs e)
+ {
+ Process.Start(Paths.GitHubPage);
+ }
+ #endregion
- #region Help
- private void tsiAbout_Click(object sender, EventArgs e)
+ #endregion
+
+ private void cboFanSel_IndexChanged(object sender, EventArgs e)
+ {
+ if (Config is not null)
{
- new VersionDialog().ShowDialog();
+ UpdateFanCurveDisplay();
}
+ }
+
+ private void cboProfSel_IndexChanged(object sender, EventArgs e)
+ {
+ FanConf cfg = Config.FanConfs[cboFanSel.SelectedIndex];
+ FanCurveConf curveCfg = cfg.FanCurveConfs[cboProfSel.SelectedIndex];
- private void tsiSrc_Click(object sender, EventArgs e)
+ if (tsiSwitchAll.Checked)
+ {
+ for (int i = 0; i < Config.FanConfs.Length; i++)
+ {
+ Config.FanConfs[i].CurveSel = cboProfSel.SelectedIndex;
+ }
+ }
+ else
{
- Process.Start(Paths.GitHubPage);
+ cfg.CurveSel = cboProfSel.SelectedIndex;
}
- #endregion
- #endregion
+ ttMain.SetToolTip(cboProfSel, Strings.GetString(
+ "ttProfSel", cfg.FanCurveConfs[cfg.CurveSel].Desc));
+
+ int numTempThresholds = cfg.UpThresholdRegs.Length;
- private void cboFanSel_IndexChanged(object sender, EventArgs e)
+ // Fan curve
+ for (int i = 0; i < numFanSpds.Length; i++)
{
- if (Config is not null)
+ if (i <= numTempThresholds)
{
- UpdateFanCurveDisplay();
+ numFanSpds[i].Value = tbFanSpds[i].Value
+ = curveCfg.TempThresholds[i].FanSpeed;
+
+ numFanSpds[i].Enabled = tbFanSpds[i].Enabled = curveCfg.Name != "Default";
}
}
- private void cboProfSel_IndexChanged(object sender, EventArgs e)
+ // Temp thresholds
+ for (int i = 0; i < numUpTs.Length; i++)
{
- FanConf cfg = Config.FanConfs[cboFanSel.SelectedIndex];
- FanCurveConf curveCfg = cfg.FanCurveConfs[cboProfSel.SelectedIndex];
-
- if (tsiSwitchAll.Checked)
+ if (i <= numTempThresholds)
{
- for (int i = 0; i < Config.FanConfs.Length; i++)
- {
- Config.FanConfs[i].CurveSel = cboProfSel.SelectedIndex;
- }
+ TempThreshold t = curveCfg.TempThresholds[i + 1];
+ numUpTs[i].Value = t.UpThreshold;
+ numDownTs[i].Value = t.DownThreshold;
+
+ numUpTs[i].Enabled = numDownTs[i].Enabled = curveCfg.Name != "Default";
}
else
{
- cfg.CurveSel = cboProfSel.SelectedIndex;
+ numUpTs[i].Enabled = numDownTs[i].Enabled = false;
}
+ }
+ btnApply.Enabled = tsiApply.Enabled = true;
+ btnProfDel.Enabled = tsiProfDel.Enabled = curveCfg.Name != "Default";
+ }
- ttMain.SetToolTip(cboProfSel, Strings.GetString(
- "ttProfSel", cfg.FanCurveConfs[cfg.CurveSel].Desc));
-
- int numTempThresholds = cfg.UpThresholdRegs.Length;
+ private void btnProfAdd_Click(object sender, EventArgs e)
+ {
+ AddFanProfile();
+ }
- // Fan curve
- for (int i = 0; i < numFanSpds.Length; i++)
- {
- if (i <= numTempThresholds)
+ private void btnProfAdd_KeyPress(object sender, KeyPressEventArgs e)
+ {
+ // hidden crash test
+ switch (e.KeyChar)
+ {
+ case 'd':
+ Debug = Debug == 0 ? 1 : 0;
+ break;
+ case 'e':
+ Debug = Debug == 1 ? 2 : 0;
+ break;
+ case 'b':
+ Debug = Debug == 2 ? 3 : 0;
+ break;
+ case 'u':
+ Debug = Debug == 3 ? 4 : 0;
+ break;
+ case 'g':
+ if (Debug == 4)
{
- numFanSpds[i].Value = tbFanSpds[i].Value
- = curveCfg.TempThresholds[i].FanSpeed;
+ Debug = 0;
- numFanSpds[i].Enabled = tbFanSpds[i].Enabled = curveCfg.Name != "Default";
+ // should throw a NullReferenceException
+ // which should get caught by CrashDialog
+ YAMDCC_Config cfg = new();
+ lblFanSpd.Text = cfg.FanConfs[0].Name;
}
- }
-
- // Temp thresholds
- for (int i = 0; i < numUpTs.Length; i++)
- {
- if (i <= numTempThresholds)
- {
- TempThreshold t = curveCfg.TempThresholds[i + 1];
- numUpTs[i].Value = t.UpThreshold;
- numDownTs[i].Value = t.DownThreshold;
+ break;
+ default:
+ Debug = 0;
+ break;
+ }
+ }
- numUpTs[i].Enabled = numDownTs[i].Enabled = curveCfg.Name != "Default";
- }
- else
- {
- numUpTs[i].Enabled = numDownTs[i].Enabled = false;
- }
- }
- btnApply.Enabled = tsiApply.Enabled = true;
- btnProfDel.Enabled = tsiProfDel.Enabled = curveCfg.Name != "Default";
- }
+ private void btnProfDel_Click(object sender, EventArgs e)
+ {
+ DelFanProfile();
+ }
- private void btnProfAdd_Click(object sender, EventArgs e)
- {
- AddFanProfile();
- }
+ private void numFanSpd_Changed(object sender, EventArgs e)
+ {
+ NumericUpDown nud = (NumericUpDown)sender;
+ int i = (int)nud.Tag;
+ tbFanSpds[i].Value = (int)numFanSpds[i].Value;
- private void btnProfAdd_KeyPress(object sender, KeyPressEventArgs e)
- {
- // hidden crash test
- switch (e.KeyChar)
- {
- case 'd':
- Debug = Debug == 0 ? 1 : 0;
- break;
- case 'e':
- Debug = Debug == 1 ? 2 : 0;
- break;
- case 'b':
- Debug = Debug == 2 ? 3 : 0;
- break;
- case 'u':
- Debug = Debug == 3 ? 4 : 0;
- break;
- case 'g':
- if (Debug == 4)
- {
- Debug = 0;
+ Config.FanConfs[cboFanSel.SelectedIndex]
+ .FanCurveConfs[cboProfSel.SelectedIndex]
+ .TempThresholds[i].FanSpeed = (byte)numFanSpds[i].Value;
- // should throw a NullReferenceException
- // which should get caught by CrashDialog
- YAMDCC_Config cfg = new();
- lblFanSpd.Text = cfg.FanConfs[0].Name;
- }
- break;
- default:
- Debug = 0;
- break;
- }
- }
+ btnRevert.Enabled = tsiRevert.Enabled = true;
+ }
- private void btnProfDel_Click(object sender, EventArgs e)
- {
- DelFanProfile();
- }
+ private void tbFanSpd_Scroll(object sender, EventArgs e)
+ {
+ TrackBar tb = (TrackBar)sender;
+ int i = (int)tb.Tag;
+ numFanSpds[i].Value = tbFanSpds[i].Value;
- private void numFanSpd_Changed(object sender, EventArgs e)
- {
- NumericUpDown nud = (NumericUpDown)sender;
- int i = (int)nud.Tag;
- tbFanSpds[i].Value = (int)numFanSpds[i].Value;
+ Config.FanConfs[cboFanSel.SelectedIndex]
+ .FanCurveConfs[cboProfSel.SelectedIndex]
+ .TempThresholds[i].FanSpeed = (byte)numFanSpds[i].Value;
- Config.FanConfs[cboFanSel.SelectedIndex]
- .FanCurveConfs[cboProfSel.SelectedIndex]
- .TempThresholds[i].FanSpeed = (byte)numFanSpds[i].Value;
+ btnRevert.Enabled = tsiRevert.Enabled = true;
+ }
- btnRevert.Enabled = tsiRevert.Enabled = true;
- }
+ private void numUpT_Changed(object sender, EventArgs e)
+ {
+ NumericUpDown nud = (NumericUpDown)sender;
+ int i = (int)nud.Tag;
- private void tbFanSpd_Scroll(object sender, EventArgs e)
- {
- TrackBar tb = (TrackBar)sender;
- int i = (int)tb.Tag;
- numFanSpds[i].Value = tbFanSpds[i].Value;
+ TempThreshold threshold = Config.FanConfs[cboFanSel.SelectedIndex]
+ .FanCurveConfs[cboProfSel.SelectedIndex]
+ .TempThresholds[i + 1];
- Config.FanConfs[cboFanSel.SelectedIndex]
- .FanCurveConfs[cboProfSel.SelectedIndex]
- .TempThresholds[i].FanSpeed = (byte)numFanSpds[i].Value;
+ // Update associated down threshold slider
+ numDownTs[i].Value += nud.Value - threshold.UpThreshold;
- btnRevert.Enabled = tsiRevert.Enabled = true;
- }
+ threshold.UpThreshold = (byte)numUpTs[i].Value;
- private void numUpT_Changed(object sender, EventArgs e)
- {
- NumericUpDown nud = (NumericUpDown)sender;
- int i = (int)nud.Tag;
+ btnRevert.Enabled = tsiRevert.Enabled = true;
+ }
+
+ private void numDownT_Changed(object sender, EventArgs e)
+ {
+ NumericUpDown nud = (NumericUpDown)sender;
+ int i = (int)nud.Tag;
+
+ Config.FanConfs[cboFanSel.SelectedIndex]
+ .FanCurveConfs[cboProfSel.SelectedIndex]
+ .TempThresholds[i + 1].DownThreshold = (byte)numDownTs[i].Value;
- TempThreshold threshold = Config.FanConfs[cboFanSel.SelectedIndex]
- .FanCurveConfs[cboProfSel.SelectedIndex]
- .TempThresholds[i + 1];
+ btnRevert.Enabled = tsiRevert.Enabled = true;
+ }
- // Update associated down threshold slider
- numDownTs[i].Value += nud.Value - threshold.UpThreshold;
+ private void chkFullBlast_Toggled(object sender, EventArgs e)
+ {
+ SendServiceMessage(new ServiceCommand(Command.FullBlast, chkFullBlast.Checked ? "1" : "0"));
+ }
- threshold.UpThreshold = (byte)numUpTs[i].Value;
+ private void chkChgLim_CheckedChanged(object sender, EventArgs e)
+ {
+ numChgLim.Enabled = chkChgLim.Checked;
+ }
+ private void numChgLim_Changed(object sender, EventArgs e)
+ {
+ if (Config is not null)
+ {
btnRevert.Enabled = tsiRevert.Enabled = true;
}
+ }
- private void numDownT_Changed(object sender, EventArgs e)
+ private void cboPerfMode_IndexChanged(object sender, EventArgs e)
+ {
+ if (Config is not null)
{
- NumericUpDown nud = (NumericUpDown)sender;
- int i = (int)nud.Tag;
-
- Config.FanConfs[cboFanSel.SelectedIndex]
- .FanCurveConfs[cboProfSel.SelectedIndex]
- .TempThresholds[i + 1].DownThreshold = (byte)numDownTs[i].Value;
-
+ int idx = cboPerfMode.SelectedIndex;
+ Config.PerfModeConf.ModeSel = idx;
+ ttMain.SetToolTip(cboPerfMode,
+ Strings.GetString("ttPerfMode", Config.PerfModeConf.PerfModes[idx].Desc));
btnRevert.Enabled = tsiRevert.Enabled = true;
}
+ }
+
+ private void chkWinFnSwap_Toggled(object sender, EventArgs e)
+ {
+ Config.KeySwapConf.Enabled = chkWinFnSwap.Checked;
+ btnRevert.Enabled = tsiRevert.Enabled = true;
+ }
+
+ private void tbKeyLight_Scroll(object sender, EventArgs e)
+ {
+ SendServiceMessage(new ServiceCommand(Command.SetKeyLightBright, $"{tbKeyLight.Value}"));
+ }
+
+ private void btnRevert_Click(object sender, EventArgs e)
+ {
+ RevertConf();
+ }
+
+ private void btnApply_Click(object sender, EventArgs e)
+ {
+ btnApply.Enabled = tsiApply.Enabled = false;
+ ApplyConf();
+ }
+
+ private void tmrPoll_Tick(object sender, EventArgs e)
+ {
+ PollEC();
+ }
+
+ private void tmrStatusReset_Tick(object sender, EventArgs e)
+ {
+ UpdateStatus(StatusCode.None);
+ tmrStatusReset.Stop();
+ }
+
+ private void tmrSvcTimeout_Tick(object sender, EventArgs e)
+ {
+ UpdateStatus(StatusCode.ServiceTimeout);
+ tmrSvcTimeout.Stop();
+ }
+
+ #endregion // Events
- private void chkFullBlast_Toggled(object sender, EventArgs e)
+ #region Private methods
+ private void UpdateFanMon(int value, int i)
+ {
+ switch (i)
{
- SendServiceMessage(new ServiceCommand(Command.FullBlast, chkFullBlast.Checked ? "1" : "0"));
+ case 0:
+ lblTemp.Invoke(new Action(delegate
+ {
+ lblTemp.Text = $"Temp: {value}°C";
+ }));
+ break;
+ case 1:
+ lblFanSpd.Invoke(new Action(delegate
+ {
+ lblFanSpd.Text = $"Fan speed: {value}%";
+ }));
+ break;
+ case 2:
+ lblFanRPM.Invoke(new Action(delegate
+ {
+ lblFanRPM.Text = value == -1
+ ? "RPM: 0"
+ : $"RPM: {value}";
+ }));
+ break;
}
+ }
+
+ private void LoadConf(string confPath)
+ {
+ UpdateStatus(StatusCode.ConfLoading);
- private void chkChgLim_CheckedChanged(object sender, EventArgs e)
+ try
{
- numChgLim.Enabled = chkChgLim.Checked;
+ Config = YAMDCC_Config.Load(confPath);
+ LoadConf(Config);
}
-
- private void numChgLim_Changed(object sender, EventArgs e)
+ catch (Exception ex)
{
- if (Config is not null)
+ if (ex is InvalidConfigException or InvalidOperationException or FileNotFoundException)
{
- btnRevert.Enabled = tsiRevert.Enabled = true;
+ UpdateStatus(StatusCode.NoConfig);
+ return;
}
- }
-
- private void cboPerfMode_IndexChanged(object sender, EventArgs e)
- {
- if (Config is not null)
+ else
{
- int idx = cboPerfMode.SelectedIndex;
- Config.PerfModeConf.ModeSel = idx;
- ttMain.SetToolTip(cboPerfMode,
- Strings.GetString("ttPerfMode", Config.PerfModeConf.PerfModes[idx].Desc));
- btnRevert.Enabled = tsiRevert.Enabled = true;
+ throw;
}
}
+ }
- private void chkWinFnSwap_Toggled(object sender, EventArgs e)
- {
- Config.KeySwapConf.Enabled = chkWinFnSwap.Checked;
- btnRevert.Enabled = tsiRevert.Enabled = true;
- }
+ private void LoadConf(YAMDCC_Config cfg)
+ {
+ DisableAll();
+ tsiSwitchAll.Checked = FansHaveSameProfileCount();
- private void tbKeyLight_Scroll(object sender, EventArgs e)
- {
- SendServiceMessage(new ServiceCommand(Command.SetKeyLightBright, $"{tbKeyLight.Value}"));
- }
+ tsiSaveConf.Enabled = true;
- private void btnRevert_Click(object sender, EventArgs e)
+ if (cfg.FullBlastConf is null)
{
- RevertConf();
+ ttMain.SetToolTip(chkFullBlast, Strings.GetString("ttNotSupported"));
}
-
- private void btnApply_Click(object sender, EventArgs e)
+ else
{
- btnApply.Enabled = tsiApply.Enabled = false;
- ApplyConf();
+ ttMain.SetToolTip(chkFullBlast, Strings.GetString("ttFullBlast"));
+ chkFullBlast.Enabled = true;
}
- private void tmrPoll_Tick(object sender, EventArgs e)
+ if (cfg.ChargeLimitConf is null)
{
- PollEC();
+ ttMain.SetToolTip(chkFullBlast, Strings.GetString("ttNotSupported"));
}
-
- private void tmrStatusReset_Tick(object sender, EventArgs e)
+ else
{
- UpdateStatus(StatusCode.None);
- tmrStatusReset.Stop();
+ ttMain.SetToolTip(numChgLim, Strings.GetString("ttChgLim"));
+ ChargeLimitConf chgLimConf = cfg.ChargeLimitConf;
+ chkChgLim.Enabled = numChgLim.Enabled = true;
+ numChgLim.Maximum = Math.Abs(chgLimConf.MaxVal - chgLimConf.MinVal);
+ if (chgLimConf.CurVal == 0)
+ {
+ chkChgLim.Checked = false;
+ numChgLim.Value = 80;
+ }
+ else
+ {
+ chkChgLim.Checked = true;
+ numChgLim.Value = chgLimConf.CurVal;
+ }
}
- private void tmrSvcTimeout_Tick(object sender, EventArgs e)
+ cboPerfMode.Items.Clear();
+ if (cfg.PerfModeConf is null)
{
- UpdateStatus(StatusCode.ServiceTimeout);
- tmrSvcTimeout.Stop();
+ ttMain.SetToolTip(cboPerfMode, Strings.GetString("ttNotSupported"));
}
-
- #endregion // Events
-
- #region Private methods
- private void UpdateFanMon(int value, int i)
+ else
{
- switch (i)
+ PerfModeConf perfModeConf = cfg.PerfModeConf;
+ for (int i = 0; i < perfModeConf.PerfModes.Length; i++)
{
- case 0:
- lblTemp.Invoke(new Action(delegate
- {
- lblTemp.Text = $"Temp: {value}°C";
- }));
- break;
- case 1:
- lblFanSpd.Invoke(new Action(delegate
- {
- lblFanSpd.Text = $"Fan speed: {value}%";
- }));
- break;
- case 2:
- lblFanRPM.Invoke(new Action(delegate
- {
- lblFanRPM.Text = value == -1
- ? "RPM: 0"
- : $"RPM: {value}";
- }));
- break;
+ cboPerfMode.Items.Add(perfModeConf.PerfModes[i].Name);
}
+
+ cboPerfMode.SelectedIndex = perfModeConf.ModeSel;
+ ttMain.SetToolTip(cboPerfMode, Strings.GetString(
+ "ttPerfMode", perfModeConf.PerfModes[perfModeConf.ModeSel].Desc));
+ cboPerfMode.Enabled = true;
}
- private void LoadConf(string confPath)
+ if (cfg.KeySwapConf is null)
{
- UpdateStatus(StatusCode.ConfLoading);
-
- try
- {
- Config = YAMDCC_Config.Load(confPath);
- LoadConf(Config);
- }
- catch (Exception ex)
- {
- if (ex is InvalidConfigException or InvalidOperationException or FileNotFoundException)
- {
- UpdateStatus(StatusCode.NoConfig);
- return;
- }
- else
- {
- throw;
- }
- }
+ ttMain.SetToolTip(chkWinFnSwap, Strings.GetString("ttNotSupported"));
+ }
+ else
+ {
+ chkWinFnSwap.Checked = cfg.KeySwapConf.Enabled;
+ ttMain.SetToolTip(chkWinFnSwap, Strings.GetString("ttKeySwap"));
+ chkWinFnSwap.Enabled = true;
}
- private void LoadConf(YAMDCC_Config cfg)
+ cboFanSel.Items.Clear();
+ for (int i = 0; i < cfg.FanConfs.Length; i++)
{
- DisableAll();
- tsiSwitchAll.Checked = FansHaveSameProfileCount();
+ cboFanSel.Items.Add(cfg.FanConfs[i].Name);
+ }
- tsiSaveConf.Enabled = true;
+ btnProfAdd.Enabled = true;
+ tsiProfAdd.Enabled = tsiProfEdit.Enabled = true;
+ tsiECtoConf.Enabled = true;
+ cboFanSel.Enabled = true;
+ cboFanSel.SelectedIndex = 0;
+ tsiECMon.Enabled = true;
- if (cfg.FullBlastConf is null)
- {
- ttMain.SetToolTip(chkFullBlast, Strings.GetString("ttNotSupported"));
- }
- else
- {
- ttMain.SetToolTip(chkFullBlast, Strings.GetString("ttFullBlast"));
- chkFullBlast.Enabled = true;
- }
+ UpdateStatus(StatusCode.None);
+ }
+
+ private void ApplyConf()
+ {
+ // Save the updated config
+ Config.ChargeLimitConf.CurVal = (byte)(chkChgLim.Checked
+ ? numChgLim.Value : 0);
+ Config.Save(Paths.CurrentConfig);
+
+ // Tell the service to reload and apply the updated config
+ SendServiceMessage(new ServiceCommand(Command.ApplyConfig, null));
+ }
- if (cfg.ChargeLimitConf is null)
+ private void RevertConf()
+ {
+ if (MessageBox.Show(
+ Strings.GetString("dlgRevert"),
+ "Revert?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning)
+ == DialogResult.Yes)
+ {
+ try
{
- ttMain.SetToolTip(chkFullBlast, Strings.GetString("ttNotSupported"));
+ YAMDCC_Config tempConf = YAMDCC_Config.Load(GetLastConfPath());
+ LoadConf(tempConf);
+ Config = tempConf;
+ UpdateFanCurveDisplay();
+ ApplyConf();
+ btnRevert.Enabled = tsiRevert.Enabled = false;
}
- else
+ catch (Exception ex)
{
- ttMain.SetToolTip(numChgLim, Strings.GetString("ttChgLim"));
- ChargeLimitConf chgLimConf = cfg.ChargeLimitConf;
- chkChgLim.Enabled = numChgLim.Enabled = true;
- numChgLim.Maximum = Math.Abs(chgLimConf.MaxVal - chgLimConf.MinVal);
- if (chgLimConf.CurVal == 0)
+ if (ex is FileNotFoundException)
{
- chkChgLim.Checked = false;
- numChgLim.Value = 80;
+ Utils.ShowError(Strings.GetString("dlgOldConfMissing"));
}
- else
+ else if (ex is InvalidConfigException or InvalidOperationException)
{
- chkChgLim.Checked = true;
- numChgLim.Value = chgLimConf.CurVal;
+ Utils.ShowError(Strings.GetString("dlgOldConfInvalid"));
}
- }
-
- cboPerfMode.Items.Clear();
- if (cfg.PerfModeConf is null)
- {
- ttMain.SetToolTip(cboPerfMode, Strings.GetString("ttNotSupported"));
- }
- else
- {
- PerfModeConf perfModeConf = cfg.PerfModeConf;
- for (int i = 0; i < perfModeConf.PerfModes.Length; i++)
+ else
{
- cboPerfMode.Items.Add(perfModeConf.PerfModes[i].Name);
+ throw;
}
-
- cboPerfMode.SelectedIndex = perfModeConf.ModeSel;
- ttMain.SetToolTip(cboPerfMode, Strings.GetString(
- "ttPerfMode", perfModeConf.PerfModes[perfModeConf.ModeSel].Desc));
- cboPerfMode.Enabled = true;
- }
-
- if (cfg.KeySwapConf is null)
- {
- ttMain.SetToolTip(chkWinFnSwap, Strings.GetString("ttNotSupported"));
- }
- else
- {
- chkWinFnSwap.Checked = cfg.KeySwapConf.Enabled;
- ttMain.SetToolTip(chkWinFnSwap, Strings.GetString("ttKeySwap"));
- chkWinFnSwap.Enabled = true;
- }
-
- cboFanSel.Items.Clear();
- for (int i = 0; i < cfg.FanConfs.Length; i++)
- {
- cboFanSel.Items.Add(cfg.FanConfs[i].Name);
}
-
- btnProfAdd.Enabled = true;
- tsiProfAdd.Enabled = tsiProfEdit.Enabled = true;
- tsiECtoConf.Enabled = true;
- cboFanSel.Enabled = true;
- cboFanSel.SelectedIndex = 0;
- tsiECMon.Enabled = true;
-
- UpdateStatus(StatusCode.None);
}
+ }
- private void ApplyConf()
- {
- // Save the updated config
- Config.ChargeLimitConf.CurVal = (byte)(chkChgLim.Checked
- ? numChgLim.Value : 0);
- Config.Save(Paths.CurrentConfig);
+ private void PollEC()
+ {
+ SendServiceMessage(new ServiceCommand(Command.GetTemp, $"{cboFanSel.SelectedIndex}"));
+ SendServiceMessage(new ServiceCommand(Command.GetFanSpeed, $"{cboFanSel.SelectedIndex}"));
+ SendServiceMessage(new ServiceCommand(Command.GetFanRPM, $"{cboFanSel.SelectedIndex}"));
+ }
- // Tell the service to reload and apply the updated config
- SendServiceMessage(new ServiceCommand(Command.ApplyConfig, null));
+ private void AddFanProfile()
+ {
+ if (tsiSwitchAll.Checked)
+ {
+ bool switchAll = tsiSwitchAll.Checked;
+ tsiSwitchAll.Checked = false;
+ AddFanProfImpl(0, cboFanSel.Items.Count);
+ tsiSwitchAll.Checked = switchAll;
}
-
- private void RevertConf()
+ else
{
- if (MessageBox.Show(
- Strings.GetString("dlgRevert"),
- "Revert?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning)
- == DialogResult.Yes)
- {
- try
- {
- YAMDCC_Config tempConf = YAMDCC_Config.Load(GetLastConfPath());
- LoadConf(tempConf);
- Config = tempConf;
- UpdateFanCurveDisplay();
- ApplyConf();
- btnRevert.Enabled = tsiRevert.Enabled = false;
- }
- catch (Exception ex)
- {
- if (ex is FileNotFoundException)
- {
- Utils.ShowError(Strings.GetString("dlgOldConfMissing"));
- }
- else if (ex is InvalidConfigException or InvalidOperationException)
- {
- Utils.ShowError(Strings.GetString("dlgOldConfInvalid"));
- }
- else
- {
- throw;
- }
- }
- }
+ AddFanProfImpl(cboFanSel.SelectedIndex, cboFanSel.SelectedIndex + 1);
}
- private void PollEC()
+ if (!FansHaveSameProfileCount())
{
- SendServiceMessage(new ServiceCommand(Command.GetTemp, $"{cboFanSel.SelectedIndex}"));
- SendServiceMessage(new ServiceCommand(Command.GetFanSpeed, $"{cboFanSel.SelectedIndex}"));
- SendServiceMessage(new ServiceCommand(Command.GetFanRPM, $"{cboFanSel.SelectedIndex}"));
+ tsiSwitchAll.Checked = false;
}
- private void AddFanProfile()
- {
- if (tsiSwitchAll.Checked)
- {
- bool switchAll = tsiSwitchAll.Checked;
- tsiSwitchAll.Checked = false;
- AddFanProfImpl(0, cboFanSel.Items.Count);
- tsiSwitchAll.Checked = switchAll;
- }
- else
- {
- AddFanProfImpl(cboFanSel.SelectedIndex, cboFanSel.SelectedIndex + 1);
- }
+ btnRevert.Enabled = tsiRevert.Enabled = true;
+ }
- if (!FansHaveSameProfileCount())
- {
- tsiSwitchAll.Checked = false;
- }
+ private void AddFanProfImpl(int start, int end)
+ {
+ FanConf cfg = Config.FanConfs[cboFanSel.SelectedIndex];
+ string oldProfName = cfg.FanCurveConfs[cboProfSel.SelectedIndex].Name;
- btnRevert.Enabled = tsiRevert.Enabled = true;
- }
+ TextInputDialog dlg = new(
+ Strings.GetString("dlgProfAdd"),
+ "New Profile", $"Copy of {oldProfName}");
- private void AddFanProfImpl(int start, int end)
+ if (dlg.ShowDialog() == DialogResult.OK)
{
- FanConf cfg = Config.FanConfs[cboFanSel.SelectedIndex];
- string oldProfName = cfg.FanCurveConfs[cboProfSel.SelectedIndex].Name;
-
- TextInputDialog dlg = new(
- Strings.GetString("dlgProfAdd"),
- "New Profile", $"Copy of {oldProfName}");
-
- if (dlg.ShowDialog() == DialogResult.OK)
+ for (int i = start; i < end; i++)
{
- for (int i = start; i < end; i++)
- {
- cfg = Config.FanConfs[i];
- FanCurveConf oldCurveCfg = cfg.FanCurveConfs[cfg.CurveSel];
+ cfg = Config.FanConfs[i];
+ FanCurveConf oldCurveCfg = cfg.FanCurveConfs[cfg.CurveSel];
- // Create a copy of the currently selected fan profile:
- FanCurveConf newCurveCfg = oldCurveCfg.Copy();
+ // Create a copy of the currently selected fan profile:
+ FanCurveConf newCurveCfg = oldCurveCfg.Copy();
- // Name it according to what the user specified
- newCurveCfg.Name = dlg.Result;
- newCurveCfg.Desc = $"(Copy of {oldCurveCfg.Name})\n{oldCurveCfg.Desc}";
+ // Name it according to what the user specified
+ newCurveCfg.Name = dlg.Result;
+ newCurveCfg.Desc = $"(Copy of {oldCurveCfg.Name})\n{oldCurveCfg.Desc}";
- // Add the new fan profile to the config's list
- cfg.FanCurveConfs = [.. cfg.FanCurveConfs, newCurveCfg];
- cfg.CurveSel = cfg.FanCurveConfs.Length - 1;
+ // Add the new fan profile to the config's list
+ cfg.FanCurveConfs = [.. cfg.FanCurveConfs, newCurveCfg];
+ cfg.CurveSel = cfg.FanCurveConfs.Length - 1;
- // Add the new fan profile to the UI's profile list and select it:
- if (i == cboFanSel.SelectedIndex)
- {
- cboProfSel.Items.Add(dlg.Result);
- cboProfSel.SelectedIndex = cfg.CurveSel;
- }
+ // Add the new fan profile to the UI's profile list and select it:
+ if (i == cboFanSel.SelectedIndex)
+ {
+ cboProfSel.Items.Add(dlg.Result);
+ cboProfSel.SelectedIndex = cfg.CurveSel;
}
}
}
+ }
- private void DelFanProfile()
+ private void DelFanProfile()
+ {
+ if (tsiSwitchAll.Checked)
{
- if (tsiSwitchAll.Checked)
- {
- DelFanProfImpl(0, cboFanSel.Items.Count);
- }
- else
- {
- DelFanProfImpl(cboFanSel.SelectedIndex, cboFanSel.SelectedIndex + 1);
- }
-
- if (!FansHaveSameProfileCount())
- {
- tsiSwitchAll.Checked = false;
- }
+ DelFanProfImpl(0, cboFanSel.Items.Count);
+ }
+ else
+ {
+ DelFanProfImpl(cboFanSel.SelectedIndex, cboFanSel.SelectedIndex + 1);
+ }
- btnRevert.Enabled = tsiRevert.Enabled = true;
+ if (!FansHaveSameProfileCount())
+ {
+ tsiSwitchAll.Checked = false;
}
- private void DelFanProfImpl(int start, int end)
+ btnRevert.Enabled = tsiRevert.Enabled = true;
+ }
+
+ private void DelFanProfImpl(int start, int end)
+ {
+ for (int i = start; i < end; i++)
{
- for (int i = start; i < end; i++)
+ FanConf cfg = Config.FanConfs[i];
+ FanCurveConf curveCfg = cfg.FanCurveConfs[cfg.CurveSel];
+
+ if (curveCfg.Name != "Default" && MessageBox.Show(
+ Strings.GetString("dlgProfDel", curveCfg.Name),
+ $"Delete fan profile? ({cfg.Name})", MessageBoxButtons.YesNo,
+ MessageBoxIcon.Warning) == DialogResult.Yes)
{
- FanConf cfg = Config.FanConfs[i];
- FanCurveConf curveCfg = cfg.FanCurveConfs[cfg.CurveSel];
+ // Remove the fan profile from the config's list
+ List curveCfgList = [.. cfg.FanCurveConfs];
+ curveCfgList.RemoveAt(cfg.CurveSel);
+ cfg.FanCurveConfs = [.. curveCfgList];
+ cfg.CurveSel -= 1;
- if (curveCfg.Name != "Default" && MessageBox.Show(
- Strings.GetString("dlgProfDel", curveCfg.Name),
- $"Delete fan profile? ({cfg.Name})", MessageBoxButtons.YesNo,
- MessageBoxIcon.Warning) == DialogResult.Yes)
+ // Remove from the list client-side, and select a different fan profile
+ if (i == cboFanSel.SelectedIndex)
{
- // Remove the fan profile from the config's list
- List curveCfgList = [.. cfg.FanCurveConfs];
- curveCfgList.RemoveAt(cfg.CurveSel);
- cfg.FanCurveConfs = [.. curveCfgList];
- cfg.CurveSel -= 1;
-
- // Remove from the list client-side, and select a different fan profile
- if (i == cboFanSel.SelectedIndex)
- {
- cboProfSel.Items.RemoveAt(cboProfSel.SelectedIndex);
- cboProfSel.SelectedIndex = cfg.CurveSel;
- }
+ cboProfSel.Items.RemoveAt(cboProfSel.SelectedIndex);
+ cboProfSel.SelectedIndex = cfg.CurveSel;
}
}
}
+ }
- private static string GetLastConfPath()
+ private static string GetLastConfPath()
+ {
+ StreamReader sr = new(Paths.LastConfig, Encoding.UTF8);
+ try
{
- StreamReader sr = new(Paths.LastConfig, Encoding.UTF8);
- try
- {
- string path = sr.ReadLine();
- return path;
- }
- finally
- {
- sr.Close();
- }
+ string path = sr.ReadLine();
+ return path;
}
-
- private static void SetLastConfPath(string path)
+ finally
{
- StreamWriter sw = new(Paths.LastConfig, false, Encoding.UTF8);
- try
- {
- sw.WriteLine(path);
- }
- finally
- {
- sw.Close();
- }
+ sr.Close();
}
+ }
- private void UpdateFanCurveDisplay()
+ private static void SetLastConfPath(string path)
+ {
+ StreamWriter sw = new(Paths.LastConfig, false, Encoding.UTF8);
+ try
{
- FanConf cfg = Config.FanConfs[cboFanSel.SelectedIndex];
-
- cboProfSel.Items.Clear();
- foreach (FanCurveConf curve in cfg.FanCurveConfs)
- {
- cboProfSel.Items.Add(curve.Name);
- }
-
- if (numUpTs is null || numDownTs is null || numFanSpds is null || tbFanSpds is null ||
- numUpTs.Length != cfg.UpThresholdRegs.Length ||
- numDownTs.Length != cfg.DownThresholdRegs.Length ||
- numFanSpds.Length != cfg.FanCurveRegs.Length ||
- tbFanSpds.Length != cfg.FanCurveRegs.Length)
- {
- float scale = CurrentAutoScaleDimensions.Height / 72;
+ sw.WriteLine(path);
+ }
+ finally
+ {
+ sw.Close();
+ }
+ }
- tblCurve.Controls.Clear();
- numUpTs = new NumericUpDown[cfg.UpThresholdRegs.Length];
- numDownTs = new NumericUpDown[cfg.DownThresholdRegs.Length];
- numFanSpds = new NumericUpDown[cfg.FanCurveRegs.Length];
- tbFanSpds = new TrackBar[cfg.FanCurveRegs.Length];
+ private void UpdateFanCurveDisplay()
+ {
+ FanConf cfg = Config.FanConfs[cboFanSel.SelectedIndex];
- tblCurve.ColumnStyles.Clear();
- tblCurve.ColumnCount = numFanSpds.Length + 2;
+ cboProfSel.Items.Clear();
+ foreach (FanCurveConf curve in cfg.FanCurveConfs)
+ {
+ cboProfSel.Items.Add(curve.Name);
+ }
- // labels on left side
- tblCurve.ColumnStyles.Add(new ColumnStyle());
- tblCurve.Controls.Add(FanCurveLabel("Speed (%)", scale, ContentAlignment.MiddleRight), 0, 0);
- tblCurve.Controls.Add(FanCurveLabel("Up (°C)", scale, ContentAlignment.MiddleRight), 0, 2);
- tblCurve.Controls.Add(FanCurveLabel("Down (°C)", scale, ContentAlignment.MiddleRight), 0, 3);
+ if (numUpTs is null || numDownTs is null || numFanSpds is null || tbFanSpds is null ||
+ numUpTs.Length != cfg.UpThresholdRegs.Length ||
+ numDownTs.Length != cfg.DownThresholdRegs.Length ||
+ numFanSpds.Length != cfg.FanCurveRegs.Length ||
+ tbFanSpds.Length != cfg.FanCurveRegs.Length)
+ {
+ float scale = CurrentAutoScaleDimensions.Height / 72;
- for (int i = 0; i < numFanSpds.Length; i++)
- {
- tblCurve.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F / numFanSpds.Length));
- numFanSpds[i] = FanCurveNUD(i, scale);
- ttMain.SetToolTip(numFanSpds[i], Strings.GetString("ttFanSpd"));
- numFanSpds[i].ValueChanged += numFanSpd_Changed;
- tblCurve.Controls.Add(numFanSpds[i], i + 1, 0);
+ tblCurve.Controls.Clear();
+ numUpTs = new NumericUpDown[cfg.UpThresholdRegs.Length];
+ numDownTs = new NumericUpDown[cfg.DownThresholdRegs.Length];
+ numFanSpds = new NumericUpDown[cfg.FanCurveRegs.Length];
+ tbFanSpds = new TrackBar[cfg.FanCurveRegs.Length];
- tbFanSpds[i] = new TrackBar()
- {
- Dock = DockStyle.Fill,
- LargeChange = 10,
- Margin = new Padding((int)(10 * scale), 0, (int)(10 * scale), 0),
- Orientation = Orientation.Vertical,
- Tag = i,
- TickFrequency = 5,
- TickStyle = TickStyle.Both,
- };
- ttMain.SetToolTip(tbFanSpds[i], Strings.GetString("ttFanSpd"));
- tbFanSpds[i].ValueChanged += tbFanSpd_Scroll;
- tblCurve.Controls.Add(tbFanSpds[i], i + 1, 1);
-
- if (i != 0)
- {
- numUpTs[i - 1] = FanCurveNUD(i - 1, scale);
- ttMain.SetToolTip(numUpTs[i - 1], Strings.GetString("ttUpT"));
- numUpTs[i - 1].ValueChanged += numUpT_Changed;
- tblCurve.Controls.Add(numUpTs[i - 1], i + 1, 2);
- }
- else
- {
- tblCurve.Controls.Add(FanCurveLabel("Default", scale), i + 1, 2);
- }
+ tblCurve.ColumnStyles.Clear();
+ tblCurve.ColumnCount = numFanSpds.Length + 2;
- if (i != numFanSpds.Length - 1)
- {
- numDownTs[i] = FanCurveNUD(i, scale);
- ttMain.SetToolTip(numDownTs[i], Strings.GetString("ttDownT"));
- numDownTs[i].ValueChanged += numDownT_Changed;
- tblCurve.Controls.Add(numDownTs[i], i + 1, 3);
- }
- else
- {
- tblCurve.Controls.Add(FanCurveLabel("Max", scale), i + 1, 3);
- }
- }
- }
+ // labels on left side
+ tblCurve.ColumnStyles.Add(new ColumnStyle());
+ tblCurve.Controls.Add(FanCurveLabel("Speed (%)", scale, ContentAlignment.MiddleRight), 0, 0);
+ tblCurve.Controls.Add(FanCurveLabel("Up (°C)", scale, ContentAlignment.MiddleRight), 0, 2);
+ tblCurve.Controls.Add(FanCurveLabel("Down (°C)", scale, ContentAlignment.MiddleRight), 0, 3);
for (int i = 0; i < numFanSpds.Length; i++)
{
- if (cfg.FanCurveRegs.Length >= i)
+ tblCurve.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F / numFanSpds.Length));
+ numFanSpds[i] = FanCurveNUD(i, scale);
+ ttMain.SetToolTip(numFanSpds[i], Strings.GetString("ttFanSpd"));
+ numFanSpds[i].ValueChanged += numFanSpd_Changed;
+ tblCurve.Controls.Add(numFanSpds[i], i + 1, 0);
+
+ tbFanSpds[i] = new TrackBar()
+ {
+ Dock = DockStyle.Fill,
+ LargeChange = 10,
+ Margin = new Padding((int)(10 * scale), 0, (int)(10 * scale), 0),
+ Orientation = Orientation.Vertical,
+ Tag = i,
+ TickFrequency = 5,
+ TickStyle = TickStyle.Both,
+ };
+ ttMain.SetToolTip(tbFanSpds[i], Strings.GetString("ttFanSpd"));
+ tbFanSpds[i].ValueChanged += tbFanSpd_Scroll;
+ tblCurve.Controls.Add(tbFanSpds[i], i + 1, 1);
+
+ if (i != 0)
{
- numFanSpds[i].Maximum = tbFanSpds[i].Maximum
- = Math.Abs(cfg.MaxSpeed - cfg.MinSpeed);
+ numUpTs[i - 1] = FanCurveNUD(i - 1, scale);
+ ttMain.SetToolTip(numUpTs[i - 1], Strings.GetString("ttUpT"));
+ numUpTs[i - 1].ValueChanged += numUpT_Changed;
+ tblCurve.Controls.Add(numUpTs[i - 1], i + 1, 2);
}
else
{
- numFanSpds[i].Enabled = tbFanSpds[i].Enabled = false;
+ tblCurve.Controls.Add(FanCurveLabel("Default", scale), i + 1, 2);
}
- }
- cboProfSel.Enabled = true;
- cboProfSel.SelectedIndex = cfg.CurveSel;
-
- if (tsiECMon.Checked)
- {
- tmrPoll.Stop();
- PollEC();
- tmrPoll.Start();
+ if (i != numFanSpds.Length - 1)
+ {
+ numDownTs[i] = FanCurveNUD(i, scale);
+ ttMain.SetToolTip(numDownTs[i], Strings.GetString("ttDownT"));
+ numDownTs[i].ValueChanged += numDownT_Changed;
+ tblCurve.Controls.Add(numDownTs[i], i + 1, 3);
+ }
+ else
+ {
+ tblCurve.Controls.Add(FanCurveLabel("Max", scale), i + 1, 3);
+ }
}
}
- private static Label FanCurveLabel(string text, float scale, ContentAlignment textAlign = ContentAlignment.MiddleCenter)
+ for (int i = 0; i < numFanSpds.Length; i++)
{
- return new Label
+ if (cfg.FanCurveRegs.Length >= i)
+ {
+ numFanSpds[i].Maximum = tbFanSpds[i].Maximum
+ = Math.Abs(cfg.MaxSpeed - cfg.MinSpeed);
+ }
+ else
{
- AutoSize = true,
- Dock = DockStyle.Fill,
- Margin = new Padding((int)(2 * scale)),
- Padding = new Padding(0, 0, 0, (int)(3 * scale)),
- Text = text,
- TextAlign = textAlign,
- };
+ numFanSpds[i].Enabled = tbFanSpds[i].Enabled = false;
+ }
}
- private void tsiLogNone_Click(object sender, EventArgs e)
- {
- tsiLogNone.Checked = true;
- tsiLogDebug.Checked = false;
- tsiLogInfo.Checked = false;
- tsiLogWarn.Checked = false;
- tsiLogError.Checked = false;
- tsiLogFatal.Checked = false;
- }
+ cboProfSel.Enabled = true;
+ cboProfSel.SelectedIndex = cfg.CurveSel;
- private void tsiLogDebug_Click(object sender, EventArgs e)
+ if (tsiECMon.Checked)
{
- tsiLogNone.Checked = false;
- tsiLogDebug.Checked = true;
- tsiLogInfo.Checked = false;
- tsiLogWarn.Checked = false;
- tsiLogError.Checked = false;
- tsiLogFatal.Checked = false;
+ tmrPoll.Stop();
+ PollEC();
+ tmrPoll.Start();
}
+ }
- private void tsiLogInfo_Click(object sender, EventArgs e)
- {
- tsiLogNone.Checked = false;
- tsiLogDebug.Checked = false;
- tsiLogInfo.Checked = true;
- tsiLogWarn.Checked = false;
- tsiLogError.Checked = false;
- tsiLogFatal.Checked = false;
- }
+ private static Label FanCurveLabel(string text, float scale, ContentAlignment textAlign = ContentAlignment.MiddleCenter)
+ {
+ return new Label
+ {
+ AutoSize = true,
+ Dock = DockStyle.Fill,
+ Margin = new Padding((int)(2 * scale)),
+ Padding = new Padding(0, 0, 0, (int)(3 * scale)),
+ Text = text,
+ TextAlign = textAlign,
+ };
+ }
- private void tsiLogWarn_Click(object sender, EventArgs e)
- {
- tsiLogNone.Checked = false;
- tsiLogDebug.Checked = false;
- tsiLogInfo.Checked = false;
- tsiLogWarn.Checked = true;
- tsiLogError.Checked = false;
- tsiLogFatal.Checked = false;
- }
+ private void tsiLogNone_Click(object sender, EventArgs e)
+ {
+ tsiLogNone.Checked = true;
+ tsiLogDebug.Checked = false;
+ tsiLogInfo.Checked = false;
+ tsiLogWarn.Checked = false;
+ tsiLogError.Checked = false;
+ tsiLogFatal.Checked = false;
+ }
- private void tsiLogError_Click(object sender, EventArgs e)
- {
- tsiLogNone.Checked = false;
- tsiLogDebug.Checked = false;
- tsiLogInfo.Checked = false;
- tsiLogWarn.Checked = false;
- tsiLogError.Checked = true;
- tsiLogFatal.Checked = false;
- }
+ private void tsiLogDebug_Click(object sender, EventArgs e)
+ {
+ tsiLogNone.Checked = false;
+ tsiLogDebug.Checked = true;
+ tsiLogInfo.Checked = false;
+ tsiLogWarn.Checked = false;
+ tsiLogError.Checked = false;
+ tsiLogFatal.Checked = false;
+ }
- private void tsiLogFatal_Click(object sender, EventArgs e)
- {
- tsiLogNone.Checked = false;
- tsiLogDebug.Checked = false;
- tsiLogInfo.Checked = false;
- tsiLogWarn.Checked = false;
- tsiLogError.Checked = false;
- tsiLogFatal.Checked = true;
- }
+ private void tsiLogInfo_Click(object sender, EventArgs e)
+ {
+ tsiLogNone.Checked = false;
+ tsiLogDebug.Checked = false;
+ tsiLogInfo.Checked = true;
+ tsiLogWarn.Checked = false;
+ tsiLogError.Checked = false;
+ tsiLogFatal.Checked = false;
+ }
+
+ private void tsiLogWarn_Click(object sender, EventArgs e)
+ {
+ tsiLogNone.Checked = false;
+ tsiLogDebug.Checked = false;
+ tsiLogInfo.Checked = false;
+ tsiLogWarn.Checked = true;
+ tsiLogError.Checked = false;
+ tsiLogFatal.Checked = false;
+ }
- private void tsiSwitchAll_Click(object sender, EventArgs e)
+ private void tsiLogError_Click(object sender, EventArgs e)
+ {
+ tsiLogNone.Checked = false;
+ tsiLogDebug.Checked = false;
+ tsiLogInfo.Checked = false;
+ tsiLogWarn.Checked = false;
+ tsiLogError.Checked = true;
+ tsiLogFatal.Checked = false;
+ }
+
+ private void tsiLogFatal_Click(object sender, EventArgs e)
+ {
+ tsiLogNone.Checked = false;
+ tsiLogDebug.Checked = false;
+ tsiLogInfo.Checked = false;
+ tsiLogWarn.Checked = false;
+ tsiLogError.Checked = false;
+ tsiLogFatal.Checked = true;
+ }
+
+ private void tsiSwitchAll_Click(object sender, EventArgs e)
+ {
+ if (!tsiSwitchAll.Checked)
{
- if (!tsiSwitchAll.Checked)
+ if (FansHaveSameProfileCount())
{
- if (FansHaveSameProfileCount())
- {
- tsiSwitchAll.Checked = true;
- }
- else
- {
- Utils.ShowError("All fans must have the same number of fan profiles.");
- }
+ tsiSwitchAll.Checked = true;
}
else
{
- tsiSwitchAll.Checked = false;
+ Utils.ShowError("All fans must have the same number of fan profiles.");
}
-
}
-
- private static NumericUpDown FanCurveNUD(int tag, float scale)
+ else
{
- return new NumericUpDown()
- {
- Dock = DockStyle.Fill,
- Height = (int)(23 * scale),
- Margin = new Padding((int)(2 * scale)),
- Tag = tag,
- };
+ tsiSwitchAll.Checked = false;
}
- private void DisableAll()
- {
- btnProfAdd.Enabled = false;
- btnProfDel.Enabled = false;
- btnRevert.Enabled = false;
- btnApply.Enabled = false;
- cboFanSel.Enabled = false;
- cboProfSel.Enabled = false;
- cboPerfMode.Enabled = false;
- chkFullBlast.Enabled = false;
- chkWinFnSwap.Enabled = false;
- chkChgLim.Enabled = false;
- numChgLim.Enabled = false;
- lblKeyLightLow.Enabled = false;
- lblKeyLightHigh.Enabled = false;
- tbKeyLight.Enabled = false;
-
- tsiSaveConf.Enabled = false;
- tsiApply.Enabled = false;
- tsiRevert.Enabled = false;
- tsiProfAdd.Enabled = false;
- tsiProfEdit.Enabled = false;
- tsiProfDel.Enabled = false;
- tsiECtoConf.Enabled = false;
- tsiECMon.Enabled = false;
-
- if (tbFanSpds is not null)
- {
- for (int i = 0; i < tbFanSpds.Length; i++)
+ }
+
+ private static NumericUpDown FanCurveNUD(int tag, float scale)
+ {
+ return new NumericUpDown()
+ {
+ Dock = DockStyle.Fill,
+ Height = (int)(23 * scale),
+ Margin = new Padding((int)(2 * scale)),
+ Tag = tag,
+ };
+ }
+
+ private void DisableAll()
+ {
+ btnProfAdd.Enabled = false;
+ btnProfDel.Enabled = false;
+ btnRevert.Enabled = false;
+ btnApply.Enabled = false;
+ cboFanSel.Enabled = false;
+ cboProfSel.Enabled = false;
+ cboPerfMode.Enabled = false;
+ chkFullBlast.Enabled = false;
+ chkWinFnSwap.Enabled = false;
+ chkChgLim.Enabled = false;
+ numChgLim.Enabled = false;
+ lblKeyLightLow.Enabled = false;
+ lblKeyLightHigh.Enabled = false;
+ tbKeyLight.Enabled = false;
+
+ tsiSaveConf.Enabled = false;
+ tsiApply.Enabled = false;
+ tsiRevert.Enabled = false;
+ tsiProfAdd.Enabled = false;
+ tsiProfEdit.Enabled = false;
+ tsiProfDel.Enabled = false;
+ tsiECtoConf.Enabled = false;
+ tsiECMon.Enabled = false;
+
+ if (tbFanSpds is not null)
+ {
+ for (int i = 0; i < tbFanSpds.Length; i++)
+ {
+ tbFanSpds[i].Enabled = false;
+ numFanSpds[i].Enabled = false;
+ if (i != 0)
{
- tbFanSpds[i].Enabled = false;
- numFanSpds[i].Enabled = false;
- if (i != 0)
- {
- numUpTs[i - 1].Enabled = false;
- numDownTs[i - 1].Enabled = false;
- }
+ numUpTs[i - 1].Enabled = false;
+ numDownTs[i - 1].Enabled = false;
}
}
}
+ }
- private bool FansHaveSameProfileCount()
+ private bool FansHaveSameProfileCount()
+ {
+ for (int i = 0; i < Config.FanConfs.Length - 1; i++)
{
- for (int i = 0; i < Config.FanConfs.Length - 1; i++)
- {
- FanConf[] fanCfgs = Config.FanConfs;
+ FanConf[] fanCfgs = Config.FanConfs;
- if (fanCfgs[i].FanCurveConfs.Length != fanCfgs[i + 1].FanCurveConfs.Length)
- {
- return false;
- }
+ if (fanCfgs[i].FanCurveConfs.Length != fanCfgs[i + 1].FanCurveConfs.Length)
+ {
+ return false;
}
- return true;
}
+ return true;
+ }
- private void UpdateStatus(StatusCode status, int data = 0)
+ private void UpdateStatus(StatusCode status, int data = 0)
+ {
+ lblStatus.Invoke(() =>
{
- lblStatus.Invoke(() =>
+ if (AppStatus.Code == status)
{
- if (AppStatus.Code == status)
- {
- AppStatus.RepeatCount++;
- }
- else
- {
- AppStatus.Code = status;
- AppStatus.RepeatCount = 0;
- }
+ AppStatus.RepeatCount++;
+ }
+ else
+ {
+ AppStatus.Code = status;
+ AppStatus.RepeatCount = 0;
+ }
- // set status text
- bool persist = false;
- switch (AppStatus.Code)
- {
- case StatusCode.ServiceCommandFail:
- persist = true;
- lblStatus.Text = Strings.GetString("statSvcErr", (Command)data);
- break;
- case StatusCode.ServiceResponseEmpty:
- lblStatus.Text = Strings.GetString("statResponseEmpty");
- break;
- case StatusCode.ServiceTimeout:
- lblStatus.Text = Strings.GetString("statSvcTimeout");
- break;
- case StatusCode.NoConfig:
- persist = true;
- lblStatus.Text = Strings.GetString("statNoConf");
- break;
- case StatusCode.ConfLoading:
- lblStatus.Text = Strings.GetString("statConfLoading");
- break;
- case StatusCode.ConfApplySuccess:
- lblStatus.Text = Strings.GetString("statConfApplied");
- break;
- case StatusCode.FullBlastToggleSuccess:
- lblStatus.Text = Strings.GetString("statFBToggled");
- break;
- default:
- persist = true;
- AppStatus.RepeatCount = 0;
- lblStatus.Text = "Ready";
- break;
- }
+ // set status text
+ bool persist = false;
+ switch (AppStatus.Code)
+ {
+ case StatusCode.ServiceCommandFail:
+ persist = true;
+ lblStatus.Text = Strings.GetString("statSvcErr", (Command)data);
+ break;
+ case StatusCode.ServiceResponseEmpty:
+ lblStatus.Text = Strings.GetString("statResponseEmpty");
+ break;
+ case StatusCode.ServiceTimeout:
+ lblStatus.Text = Strings.GetString("statSvcTimeout");
+ break;
+ case StatusCode.NoConfig:
+ persist = true;
+ lblStatus.Text = Strings.GetString("statNoConf");
+ break;
+ case StatusCode.ConfLoading:
+ lblStatus.Text = Strings.GetString("statConfLoading");
+ break;
+ case StatusCode.ConfApplySuccess:
+ lblStatus.Text = Strings.GetString("statConfApplied");
+ break;
+ case StatusCode.FullBlastToggleSuccess:
+ lblStatus.Text = Strings.GetString("statFBToggled");
+ break;
+ default:
+ persist = true;
+ AppStatus.RepeatCount = 0;
+ lblStatus.Text = "Ready";
+ break;
+ }
- if (AppStatus.RepeatCount > 0)
- {
- lblStatus.Text += $" (x{AppStatus.RepeatCount + 1})";
- }
+ if (AppStatus.RepeatCount > 0)
+ {
+ lblStatus.Text += $" (x{AppStatus.RepeatCount + 1})";
+ }
- tmrStatusReset.Stop();
- if (!persist)
- {
- tmrStatusReset.Start();
- }
- });
- }
+ tmrStatusReset.Stop();
+ if (!persist)
+ {
+ tmrStatusReset.Start();
+ }
+ });
+ }
- private void SendServiceMessage(ServiceCommand command)
- {
- IPCClient.PushMessage(command);
- tmrSvcTimeout.Start();
- }
- #endregion // Private methods
+ private void SendServiceMessage(ServiceCommand command)
+ {
+ IPCClient.PushMessage(command);
+ tmrSvcTimeout.Start();
}
+ #endregion // Private methods
}
diff --git a/YAMDCC.ConfigEditor/Program.cs b/YAMDCC.ConfigEditor/Program.cs
index bc08147..69f8e81 100644
--- a/YAMDCC.ConfigEditor/Program.cs
+++ b/YAMDCC.ConfigEditor/Program.cs
@@ -25,207 +25,206 @@
using YAMDCC.Common;
using YAMDCC.Common.Dialogs;
-namespace YAMDCC.ConfigEditor
-{
- internal static class Program
- {
- private const int SW_RESTORE = 9;
+namespace YAMDCC.ConfigEditor;
- ///
- /// The main entry point for the application.
- ///
- [STAThread]
- private static void Main()
- {
- Application.EnableVisualStyles();
- Application.SetCompatibleTextRenderingDefault(false);
+internal static class Program
+{
+ private const int SW_RESTORE = 9;
- #region Global exception handlers
- Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
- Application.ThreadException += static (sender, e) =>
- new CrashDialog(e.Exception).ShowDialog();
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ private static void Main()
+ {
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
- AppDomain.CurrentDomain.UnhandledException += static (sender, e) =>
- {
- if (e.ExceptionObject is Exception ex)
- {
- new CrashDialog(ex).ShowDialog();
- }
- };
- #endregion
+ #region Global exception handlers
+ Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
+ Application.ThreadException += static (sender, e) =>
+ new CrashDialog(e.Exception).ShowDialog();
- if (!Utils.IsAdmin())
+ AppDomain.CurrentDomain.UnhandledException += static (sender, e) =>
+ {
+ if (e.ExceptionObject is Exception ex)
{
- Utils.ShowError(Strings.GetString("dlgNoAdmin"));
- return;
+ new CrashDialog(ex).ShowDialog();
}
+ };
+ #endregion
- // multi-instance detection
- // NOTE: GUID is used to prevent conflicts with potential
- // identically named but different program
- // based on: https://stackoverflow.com/a/184143
- using (Mutex mutex = new(true, "{10572c4f-894e-4837-b31c-356d70c44e19}", out bool createdNew))
+ if (!Utils.IsAdmin())
+ {
+ Utils.ShowError(Strings.GetString("dlgNoAdmin"));
+ return;
+ }
+
+ // multi-instance detection
+ // NOTE: GUID is used to prevent conflicts with potential
+ // identically named but different program
+ // based on: https://stackoverflow.com/a/184143
+ using (Mutex mutex = new(true, "{10572c4f-894e-4837-b31c-356d70c44e19}", out bool createdNew))
+ {
+ // this instance is the first to open; proceed as normal:
+ if (createdNew)
{
- // this instance is the first to open; proceed as normal:
- if (createdNew)
- {
- // Make sure the application data directory structure is set up
- // because apparently windows services don't know how to create
- // directories:
- Directory.CreateDirectory(Paths.Logs);
+ // Make sure the application data directory structure is set up
+ // because apparently windows services don't know how to create
+ // directories:
+ Directory.CreateDirectory(Paths.Logs);
- if (!Utils.ServiceExists("yamdccsvc"))
+ if (!Utils.ServiceExists("yamdccsvc"))
+ {
+ if (File.Exists("yamdccsvc.exe"))
{
- if (File.Exists("yamdccsvc.exe"))
+ if (MessageBox.Show(
+ Strings.GetString("dlgSvcNotInstalled"),
+ "Service not installed",
+ MessageBoxButtons.YesNo,
+ MessageBoxIcon.Information) == DialogResult.Yes)
{
- if (MessageBox.Show(
- Strings.GetString("dlgSvcNotInstalled"),
- "Service not installed",
- MessageBoxButtons.YesNo,
- MessageBoxIcon.Information) == DialogResult.Yes)
+ ProgressDialog dlg = new(Strings.GetString("dlgSvcInstalling"), (e) =>
{
- ProgressDialog dlg = new(Strings.GetString("dlgSvcInstalling"), (e) =>
+ e.Result = false;
+ if (Utils.InstallService("yamdccsvc"))
{
- e.Result = false;
- if (Utils.InstallService("yamdccsvc"))
+ if (Utils.StartService("yamdccsvc"))
{
- if (Utils.StartService("yamdccsvc"))
- {
- e.Result = true;
- }
- else
- {
- Utils.ShowError(Strings.GetString("dlgSvcStartCrash"));
- }
+ e.Result = true;
}
else
{
- Utils.ShowError(Strings.GetString("dlgSvcInstallFail"));
+ Utils.ShowError(Strings.GetString("dlgSvcStartCrash"));
}
- });
- dlg.ShowDialog();
-
- if (dlg.Result is bool b && b)
+ }
+ else
{
- // Start the program when the service finishes starting:
- Start();
+ Utils.ShowError(Strings.GetString("dlgSvcInstallFail"));
}
+ });
+ dlg.ShowDialog();
+
+ if (dlg.Result is bool b && b)
+ {
+ // Start the program when the service finishes starting:
+ Start();
}
- return;
- }
- else
- {
- Utils.ShowError(Strings.GetString("dlgSvcNotFound"));
- return;
}
+ return;
}
+ else
+ {
+ Utils.ShowError(Strings.GetString("dlgSvcNotFound"));
+ return;
+ }
+ }
- // Check if the service is stopped:
- ServiceController yamdccSvc = new("yamdccsvc");
- try
+ // Check if the service is stopped:
+ ServiceController yamdccSvc = new("yamdccsvc");
+ try
+ {
+ ServiceControllerStatus status = yamdccSvc.Status;
+ if (status == ServiceControllerStatus.Stopped)
{
- ServiceControllerStatus status = yamdccSvc.Status;
- if (status == ServiceControllerStatus.Stopped)
+ if (MessageBox.Show(
+ Strings.GetString("dlgSvcStopped"),
+ "Service not running", MessageBoxButtons.YesNo,
+ MessageBoxIcon.Information) == DialogResult.Yes)
{
- if (MessageBox.Show(
- Strings.GetString("dlgSvcStopped"),
- "Service not running", MessageBoxButtons.YesNo,
- MessageBoxIcon.Information) == DialogResult.Yes)
+ ProgressDialog dlg = new(Strings.GetString("dlgSvcStarting"), (e) =>
{
- ProgressDialog dlg = new(Strings.GetString("dlgSvcStarting"), (e) =>
+ if (Utils.StartService("yamdccsvc"))
{
- if (Utils.StartService("yamdccsvc"))
- {
- e.Result = false;
- }
- else
- {
- Utils.ShowError(Strings.GetString("dlgSvcStartCrash"));
- e.Result = true;
- }
- });
- dlg.ShowDialog();
-
- if (dlg.Result is bool b && b)
+ e.Result = false;
+ }
+ else
{
- return;
+ Utils.ShowError(Strings.GetString("dlgSvcStartCrash"));
+ e.Result = true;
}
- }
- else
+ });
+ dlg.ShowDialog();
+
+ if (dlg.Result is bool b && b)
{
return;
}
}
+ else
+ {
+ return;
+ }
}
- finally
- {
- yamdccSvc?.Close();
- }
-
- // Start the program when the service finishes starting:
- Start();
}
- else
+ finally
+ {
+ yamdccSvc?.Close();
+ }
+
+ // Start the program when the service finishes starting:
+ Start();
+ }
+ else
+ {
+ // YAMDCC is already running, focus
+ // (and restore, if minimised) its window:
+ Process current = Process.GetCurrentProcess();
+ foreach (Process process in Process.GetProcessesByName(current.ProcessName))
{
- // YAMDCC is already running, focus
- // (and restore, if minimised) its window:
- Process current = Process.GetCurrentProcess();
- foreach (Process process in Process.GetProcessesByName(current.ProcessName))
+ if (process.Id != current.Id)
{
- if (process.Id != current.Id)
+ if (process.MainWindowHandle != IntPtr.Zero)
{
- if (process.MainWindowHandle != IntPtr.Zero)
- {
- ShowWindow(process.MainWindowHandle, SW_RESTORE);
- SetForegroundWindow(process.MainWindowHandle);
- }
- break;
+ ShowWindow(process.MainWindowHandle, SW_RESTORE);
+ SetForegroundWindow(process.MainWindowHandle);
}
+ break;
}
}
}
}
+ }
- private static void Start()
+ private static void Start()
+ {
+ int rebootFlag = -1;
+ try
{
- int rebootFlag = -1;
- try
+ StreamReader sr = new(Paths.ECToConfPending);
+ if (int.TryParse(sr.ReadToEnd(), NumberStyles.Integer, CultureInfo.InvariantCulture, out int value))
{
- StreamReader sr = new(Paths.ECToConfPending);
- if (int.TryParse(sr.ReadToEnd(), NumberStyles.Integer, CultureInfo.InvariantCulture, out int value))
- {
- rebootFlag = value;
- }
- sr.Close();
+ rebootFlag = value;
}
- catch (FileNotFoundException) { }
- catch (DirectoryNotFoundException) { }
+ sr.Close();
+ }
+ catch (FileNotFoundException) { }
+ catch (DirectoryNotFoundException) { }
- if (rebootFlag == 1)
+ if (rebootFlag == 1)
+ {
+ if (MessageBox.Show(Strings.GetString("dlgECtoConfReboot"),
+ "Reboot pending", MessageBoxButtons.YesNo, MessageBoxIcon.Warning,
+ MessageBoxDefaultButton.Button2) == DialogResult.Yes)
{
- if (MessageBox.Show(Strings.GetString("dlgECtoConfReboot"),
- "Reboot pending", MessageBoxButtons.YesNo, MessageBoxIcon.Warning,
- MessageBoxDefaultButton.Button2) == DialogResult.Yes)
+ try
{
- try
- {
- File.Delete(Paths.ECToConfPending);
- }
- catch (DirectoryNotFoundException) { }
- }
- else
- {
- return;
+ File.Delete(Paths.ECToConfPending);
}
+ catch (DirectoryNotFoundException) { }
+ }
+ else
+ {
+ return;
}
-
- Application.Run(new MainWindow());
}
- [DllImport("user32.dll")]
- private static extern bool SetForegroundWindow(IntPtr hWnd);
-
- [DllImport("user32.dll")]
- private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
+ Application.Run(new MainWindow());
}
+
+ [DllImport("user32.dll")]
+ private static extern bool SetForegroundWindow(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
diff --git a/YAMDCC.ConfigEditor/Status.cs b/YAMDCC.ConfigEditor/Status.cs
index eb30de3..732431c 100644
--- a/YAMDCC.ConfigEditor/Status.cs
+++ b/YAMDCC.ConfigEditor/Status.cs
@@ -14,29 +14,28 @@
// You should have received a copy of the GNU General Public License along with
// YAMDCC. If not, see .
-namespace YAMDCC.ConfigEditor
-{
- internal sealed class Status
- {
- internal StatusCode Code;
- internal int RepeatCount;
+namespace YAMDCC.ConfigEditor;
- internal Status()
- {
- Code = StatusCode.None;
- RepeatCount = 0;
- }
- }
+internal sealed class Status
+{
+ internal StatusCode Code;
+ internal int RepeatCount;
- internal enum StatusCode
+ internal Status()
{
- None = 0,
- ServiceCommandFail,
- ServiceResponseEmpty,
- ServiceTimeout,
- ConfLoading,
- NoConfig,
- ConfApplySuccess,
- FullBlastToggleSuccess,
+ Code = StatusCode.None;
+ RepeatCount = 0;
}
}
+
+internal enum StatusCode
+{
+ None = 0,
+ ServiceCommandFail,
+ ServiceResponseEmpty,
+ ServiceTimeout,
+ ConfLoading,
+ NoConfig,
+ ConfApplySuccess,
+ FullBlastToggleSuccess,
+}
diff --git a/YAMDCC.ConfigEditor/Strings.cs b/YAMDCC.ConfigEditor/Strings.cs
index 576b264..a8b7ea4 100644
--- a/YAMDCC.ConfigEditor/Strings.cs
+++ b/YAMDCC.ConfigEditor/Strings.cs
@@ -17,58 +17,57 @@
using System.Globalization;
using System.Resources;
-namespace YAMDCC.ConfigEditor
+namespace YAMDCC.ConfigEditor;
+
+///
+/// A resource class for retrieving strings.
+///
+internal static class Strings
{
+ private static ResourceManager resMan;
+
///
- /// A resource class for retrieving strings.
+ /// Gets a string from the underlying resource file.
///
- internal static class Strings
+ ///
+ /// This function internally calls
+ /// to retrieve the string.
+ ///
+ ///
+ /// The name of the string to find.
+ ///
+ ///
+ /// The value of the specified string name, if found.
+ /// null if the string couldn't be found.
+ ///
+ public static string GetString(string name)
{
- private static ResourceManager resMan;
-
- ///
- /// Gets a string from the underlying resource file.
- ///
- ///
- /// This function internally calls
- /// to retrieve the string.
- ///
- ///
- /// The name of the string to find.
- ///
- ///
- /// The value of the specified string name, if found.
- /// null if the string couldn't be found.
- ///
- public static string GetString(string name)
- {
- resMan ??= new ResourceManager(typeof(Strings));
- return resMan.GetString(name, CultureInfo.InvariantCulture);
- }
+ resMan ??= new ResourceManager(typeof(Strings));
+ return resMan.GetString(name, CultureInfo.InvariantCulture);
+ }
- ///
- /// Gets a string from the underlying resource file, and
- /// replaces format objects with their string representation.
- ///
- ///
- /// The name of the string to find.
- ///
- ///
- /// The object to format the string with.
- ///
- ///
- ///
- /// The formatted string corresponding to
- /// the specified string name, if found.
- ///
- /// null if the string couldn't be found.
- ///
- public static string GetString(string name, object arg0)
- {
- string temp = GetString(name);
- return temp is null
- ? null
- : string.Format(CultureInfo.InvariantCulture, temp, arg0);
- }
+ ///
+ /// Gets a string from the underlying resource file, and
+ /// replaces format objects with their string representation.
+ ///
+ ///
+ /// The name of the string to find.
+ ///
+ ///
+ /// The object to format the string with.
+ ///
+ ///
+ ///
+ /// The formatted string corresponding to
+ /// the specified string name, if found.
+ ///
+ /// null if the string couldn't be found.
+ ///
+ public static string GetString(string name, object arg0)
+ {
+ string temp = GetString(name);
+ return temp is null
+ ? null
+ : string.Format(CultureInfo.InvariantCulture, temp, arg0);
}
}
diff --git a/YAMDCC.ECAccess/Driver.cs b/YAMDCC.ECAccess/Driver.cs
index db82040..1474285 100644
--- a/YAMDCC.ECAccess/Driver.cs
+++ b/YAMDCC.ECAccess/Driver.cs
@@ -17,373 +17,371 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.ComTypes;
using System.Security.AccessControl;
using YAMDCC.ECAccess.Win32;
-namespace YAMDCC.ECAccess
+namespace YAMDCC.ECAccess;
+
+///
+/// Contains functions to install and manage kernel-level device drivers.
+///
+internal sealed class Driver
{
+ private readonly string DeviceName;
+ private readonly string DriverPath = string.Empty;
+ private IntPtr hDevice;
+
+ ///
+ /// Gets whether the driver connection is open.
+ ///
+ public bool IsOpen { get; private set; }
+
+ ///
+ /// Gets whether the driver is installed to the computer.
+ ///
+ ///
+ /// This will be false if the driver has not been
+ /// installed by this instance of the ,
+ /// even if it is actaully installed to the system.
+ ///
+ public bool IsInstalled { get; private set; }
+
+ ///
+ /// The underlying Win32 Error code generated
+ /// by the last called method in this class instance.
+ ///
+ public int ErrorCode { get; private set; }
+
///
- /// Contains functions to install and manage kernel-level device drivers.
+ /// Create an instance of the
+ /// class with the specified name and driver path,
+ /// automatically installing the driver to the system.
///
- internal sealed class Driver
+ ///
+ /// The driver name. This will be used as the device driver service name.
+ ///
+ ///
+ /// The path to the driver file (C:\path\to\driver.sys).
+ ///
+ public Driver(string name, string path)
{
- private readonly string DeviceName;
- private readonly string DriverPath = string.Empty;
- private IntPtr hDevice;
-
- ///
- /// Gets whether the driver connection is open.
- ///
- public bool IsOpen { get; private set; }
-
- ///
- /// Gets whether the driver is installed to the computer.
- ///
- ///
- /// This will be false if the driver has not been
- /// installed by this instance of the ,
- /// even if it is actaully installed to the system.
- ///
- public bool IsInstalled { get; private set; }
-
- ///
- /// The underlying Win32 Error code generated
- /// by the last called method in this class instance.
- ///
- public int ErrorCode { get; private set; }
-
- ///
- /// Create an instance of the
- /// class with the specified name and driver path,
- /// automatically installing the driver to the system.
- ///
- ///
- /// The driver name. This will be used as the device driver service name.
- ///
- ///
- /// The path to the driver file (C:\path\to\driver.sys).
- ///
- public Driver(string name, string path)
- {
- DeviceName = name;
- DriverPath = path;
- }
+ DeviceName = name;
+ DriverPath = path;
+ }
- ///
- /// Installs the driver on the local computer.
- ///
- ///
- /// true if the driver was installed
- /// successfully, otherwise false.
- ///
- public bool Install()
- {
- ErrorCode = 0;
+ ///
+ /// Installs the driver on the local computer.
+ ///
+ ///
+ /// true if the driver was installed
+ /// successfully, otherwise false.
+ ///
+ public bool Install()
+ {
+ ErrorCode = 0;
- if (string.IsNullOrEmpty(DriverPath))
- {
- throw new ArgumentException(
- "The driver path is set to a null or empty string.", DriverPath);
- }
+ if (string.IsNullOrEmpty(DriverPath))
+ {
+ throw new ArgumentException(
+ "The driver path is set to a null or empty string.", DriverPath);
+ }
- // Make sure the file we're trying to install actually exists:
- string fullPath = Path.GetFullPath(DriverPath);
+ // Make sure the file we're trying to install actually exists:
+ string fullPath = Path.GetFullPath(DriverPath);
- if (!File.Exists(fullPath))
- {
- throw new FileNotFoundException($"{fullPath} was not found.", fullPath);
- }
+ if (!File.Exists(fullPath))
+ {
+ throw new FileNotFoundException($"{fullPath} was not found.", fullPath);
+ }
- // Try to open the Service Control Manager:
- IntPtr hSCM = AdvApi32.OpenSCManager(null, null, AdvApi32.SCMAccess.All);
- if (hSCM == IntPtr.Zero)
- {
- // the SCM connection wasn't opened
- // successfully, return false:
- ErrorCode = Marshal.GetLastWin32Error();
- return false;
- }
+ // Try to open the Service Control Manager:
+ IntPtr hSCM = AdvApi32.OpenSCManager(null, null, AdvApi32.SCMAccess.All);
+ if (hSCM == IntPtr.Zero)
+ {
+ // the SCM connection wasn't opened
+ // successfully, return false:
+ ErrorCode = Marshal.GetLastWin32Error();
+ return false;
+ }
- // Try to create the service:
- IntPtr hSvc = AdvApi32.CreateService(
- hSCM, DeviceName, DeviceName,
- AdvApi32.ServiceAccess.All,
- AdvApi32.ServiceType.KernelDriver,
- AdvApi32.ServiceStartType.DemandStart,
- AdvApi32.ServiceError.Normal,
- DriverPath, null, null, null, null, null);
+ // Try to create the service:
+ IntPtr hSvc = AdvApi32.CreateService(
+ hSCM, DeviceName, DeviceName,
+ AdvApi32.ServiceAccess.All,
+ AdvApi32.ServiceType.KernelDriver,
+ AdvApi32.ServiceStartType.DemandStart,
+ AdvApi32.ServiceError.Normal,
+ DriverPath, null, null, null, null, null);
- if (hSvc == IntPtr.Zero)
+ if (hSvc == IntPtr.Zero)
+ {
+ ErrorCode = Marshal.GetLastWin32Error();
+ if (ErrorCode == 1073) // ERROR_SERVICE_EXISTS
{
- ErrorCode = Marshal.GetLastWin32Error();
- if (ErrorCode == 1073) // ERROR_SERVICE_EXISTS
- {
- hSvc = AdvApi32.OpenService(hSCM, DeviceName, AdvApi32.ServiceAccess.All);
- if (hSvc == IntPtr.Zero)
- {
- ErrorCode = Marshal.GetLastWin32Error();
- AdvApi32.CloseServiceHandle(hSCM);
- return false;
- }
- }
- else
+ hSvc = AdvApi32.OpenService(hSCM, DeviceName, AdvApi32.ServiceAccess.All);
+ if (hSvc == IntPtr.Zero)
{
ErrorCode = Marshal.GetLastWin32Error();
AdvApi32.CloseServiceHandle(hSCM);
return false;
}
}
- IsInstalled = true;
-
- // Try to start the service:
- if (!AdvApi32.StartService(hSvc, 0, IntPtr.Zero))
+ else
{
- int error = Marshal.GetLastWin32Error();
- if (error != 1056) // ERROR_SERVICE_ALREADY_RUNNING
- {
- ErrorCode = error;
- AdvApi32.CloseServiceHandle(hSvc);
- AdvApi32.CloseServiceHandle(hSCM);
- return false;
- }
+ ErrorCode = Marshal.GetLastWin32Error();
+ AdvApi32.CloseServiceHandle(hSCM);
+ return false;
}
-
- // Perform some cleanup:
- AdvApi32.CloseServiceHandle(hSvc);
- AdvApi32.CloseServiceHandle(hSCM);
-
- // Security fix for WinRing0 access from unprivileged processes.
- // This fix is present in the WinRing0 driver itself (WinRing0.sys)
- // in an updated fork (https://github.com/GermanAizek/WinRing0), but no
- // public production-signed build of the driver exists with the fixes.
- // This fix was "borrowed" from OpenHardwareMonitor:
- // https://github.com/openhardwaremonitor/openhardwaremonitor/
- FileInfo fi = new($"\\\\.\\{DeviceName}");
- FileSecurity security = fi.GetAccessControl();
- security.SetSecurityDescriptorSddlForm("O:BAG:SYD:(A;;FA;;;SY)(A;;FA;;;BA)");
- fi.SetAccessControl(security);
-
- return true;
}
+ IsInstalled = true;
- ///
- /// Uninstalls the driver from the local computer.
- ///
- ///
- /// true if the driver was uninstalled
- /// successfully, otherwise false.
- ///
- public bool Uninstall()
+ // Try to start the service:
+ if (!AdvApi32.StartService(hSvc, 0, IntPtr.Zero))
{
- ErrorCode = 0;
-
- // Close the driver file handle (if it's open)
- Close();
-
- IntPtr hSCM = AdvApi32.OpenSCManager(null, null, AdvApi32.SCMAccess.All);
- if (hSCM == IntPtr.Zero)
+ int error = Marshal.GetLastWin32Error();
+ if (error != 1056) // ERROR_SERVICE_ALREADY_RUNNING
{
- // the SCM connection wasn't opened
- // successfully, return false:
- ErrorCode = Marshal.GetLastWin32Error();
+ ErrorCode = error;
+ AdvApi32.CloseServiceHandle(hSvc);
+ AdvApi32.CloseServiceHandle(hSCM);
return false;
}
+ }
- // Try to open the service:
- IntPtr hSvc = AdvApi32.OpenService(hSCM, DeviceName, AdvApi32.ServiceAccess.All);
- if (hSvc == IntPtr.Zero)
- {
- // Ignore ERROR_SERVICE_DOES_NOT_EXIST:
- int error = Marshal.GetLastWin32Error();
- bool success = error == 1060;
- if (success)
- {
- IsInstalled = false;
- }
- else
- {
- ErrorCode = error;
- }
+ // Perform some cleanup:
+ AdvApi32.CloseServiceHandle(hSvc);
+ AdvApi32.CloseServiceHandle(hSCM);
+
+ // Security fix for WinRing0 access from unprivileged processes.
+ // This fix is present in the WinRing0 driver itself (WinRing0.sys)
+ // in an updated fork (https://github.com/GermanAizek/WinRing0), but no
+ // public production-signed build of the driver exists with the fixes.
+ // This fix was "borrowed" from OpenHardwareMonitor:
+ // https://github.com/openhardwaremonitor/openhardwaremonitor/
+ FileInfo fi = new($"\\\\.\\{DeviceName}");
+ FileSecurity security = fi.GetAccessControl();
+ security.SetSecurityDescriptorSddlForm("O:BAG:SYD:(A;;FA;;;SY)(A;;FA;;;BA)");
+ fi.SetAccessControl(security);
+
+ return true;
+ }
- AdvApi32.CloseServiceHandle(hSCM);
- return success;
- }
+ ///
+ /// Uninstalls the driver from the local computer.
+ ///
+ ///
+ /// true if the driver was uninstalled
+ /// successfully, otherwise false.
+ ///
+ public bool Uninstall()
+ {
+ ErrorCode = 0;
- // Stop and delete the service:
- AdvApi32.ControlService(hSvc, AdvApi32.ServiceControlCode.Stop, out _);
- AdvApi32.DeleteService(hSvc);
- IsInstalled = false;
+ // Close the driver file handle (if it's open)
+ Close();
- // Close service handles
- AdvApi32.CloseServiceHandle(hSvc);
- AdvApi32.CloseServiceHandle(hSCM);
- return true;
+ IntPtr hSCM = AdvApi32.OpenSCManager(null, null, AdvApi32.SCMAccess.All);
+ if (hSCM == IntPtr.Zero)
+ {
+ // the SCM connection wasn't opened
+ // successfully, return false:
+ ErrorCode = Marshal.GetLastWin32Error();
+ return false;
}
- ///
- /// Opens a connection to the driver.
- ///
- ///
- /// true if the driver connection was
- /// opened successfully, otherwise false.
- ///
- public bool Open()
+ // Try to open the service:
+ IntPtr hSvc = AdvApi32.OpenService(hSCM, DeviceName, AdvApi32.ServiceAccess.All);
+ if (hSvc == IntPtr.Zero)
{
- if (IsOpen)
+ // Ignore ERROR_SERVICE_DOES_NOT_EXIST:
+ int error = Marshal.GetLastWin32Error();
+ bool success = error == 1060;
+ if (success)
{
- return true;
+ IsInstalled = false;
}
-
- ErrorCode = 0;
-
- if (hDevice == IntPtr.Zero)
+ else
{
- hDevice = Kernel32.CreateFile(
- $"\\\\.\\{DeviceName}",
- Kernel32.GenericAccessRights.Read | Kernel32.GenericAccessRights.Write,
- FileShare.None,
- IntPtr.Zero,
- FileMode.Open,
- FileAttributes.Normal,
- IntPtr.Zero);
-
- // Apparently CreateFileW() can return -1 instead of 0 for some reason
- if (hDevice == IntPtr.Zero || hDevice == new IntPtr(-1))
- {
- ErrorCode = Marshal.GetLastWin32Error();
- return false;
- }
-
- IsOpen = true;
- return true;
+ ErrorCode = error;
}
- return true;
+
+ AdvApi32.CloseServiceHandle(hSCM);
+ return success;
}
- ///
- /// Closes the connection to the device driver, if open.
- ///
- public void Close()
+ // Stop and delete the service:
+ AdvApi32.ControlService(hSvc, AdvApi32.ServiceControlCode.Stop, out _);
+ AdvApi32.DeleteService(hSvc);
+ IsInstalled = false;
+
+ // Close service handles
+ AdvApi32.CloseServiceHandle(hSvc);
+ AdvApi32.CloseServiceHandle(hSCM);
+ return true;
+ }
+
+ ///
+ /// Opens a connection to the driver.
+ ///
+ ///
+ /// true if the driver connection was
+ /// opened successfully, otherwise false.
+ ///
+ public bool Open()
+ {
+ if (IsOpen)
{
- if (hDevice != IntPtr.Zero)
- {
- Kernel32.CloseHandle(hDevice);
- hDevice = IntPtr.Zero;
- IsOpen = false;
- }
+ return true;
}
- public unsafe bool IOControl(uint ctlCode, void* inBuffer, uint inBufSize, void* outBuffer, uint outBufSize, out uint bytesReturned)
+ ErrorCode = 0;
+
+ if (hDevice == IntPtr.Zero)
{
- if (hDevice == IntPtr.Zero)
+ hDevice = Kernel32.CreateFile(
+ $"\\\\.\\{DeviceName}",
+ Kernel32.GenericAccessRights.Read | Kernel32.GenericAccessRights.Write,
+ FileShare.None,
+ IntPtr.Zero,
+ FileMode.Open,
+ FileAttributes.Normal,
+ IntPtr.Zero);
+
+ // Apparently CreateFileW() can return -1 instead of 0 for some reason
+ if (hDevice == IntPtr.Zero || hDevice == new IntPtr(-1))
{
- bytesReturned = 0;
+ ErrorCode = Marshal.GetLastWin32Error();
return false;
}
- bool success = Kernel32.DeviceIoControl(
- hDevice, ctlCode,
- inBuffer, inBufSize,
- outBuffer, outBufSize,
- out bytesReturned, null);
+ IsOpen = true;
+ return true;
+ }
+ return true;
+ }
- ErrorCode = success
- ? 0
- : Marshal.GetLastWin32Error();
+ ///
+ /// Closes the connection to the device driver, if open.
+ ///
+ public void Close()
+ {
+ if (hDevice != IntPtr.Zero)
+ {
+ Kernel32.CloseHandle(hDevice);
+ hDevice = IntPtr.Zero;
+ IsOpen = false;
+ }
+ }
- return success;
+ public unsafe bool IOControl(uint ctlCode, void* inBuffer, uint inBufSize, void* outBuffer, uint outBufSize, out uint bytesReturned)
+ {
+ if (hDevice == IntPtr.Zero)
+ {
+ bytesReturned = 0;
+ return false;
}
- public unsafe bool IOControl(uint ctlCode, ref T inBuffer)
- where T : unmanaged
+ bool success = Kernel32.DeviceIoControl(
+ hDevice, ctlCode,
+ inBuffer, inBufSize,
+ outBuffer, outBufSize,
+ out bytesReturned, null);
+
+ ErrorCode = success
+ ? 0
+ : Marshal.GetLastWin32Error();
+
+ return success;
+ }
+
+ public unsafe bool IOControl(uint ctlCode, ref T inBuffer)
+ where T : unmanaged
+ {
+ if (typeof(T).IsValueType)
{
- if (typeof(T).IsValueType)
+ fixed (T* pInBuffer = &inBuffer)
{
- fixed (T* pInBuffer = &inBuffer)
- {
- return IOControl(ctlCode,
- pInBuffer, (uint)Marshal.SizeOf(inBuffer),
- null, 0,
- out _);
- }
+ return IOControl(ctlCode,
+ pInBuffer, (uint)Marshal.SizeOf(inBuffer),
+ null, 0,
+ out _);
}
- else
+ }
+ else
+ {
+ IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(inBuffer));
+ try
{
- IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(inBuffer));
- try
- {
- Marshal.StructureToPtr(inBuffer, ptr, false);
+ Marshal.StructureToPtr(inBuffer, ptr, false);
- return IOControl(ctlCode,
- ptr.ToPointer(), (uint)Marshal.SizeOf(inBuffer),
- null, 0,
- out _);
- }
- finally
- {
- Marshal.DestroyStructure(ptr);
- Marshal.FreeHGlobal(ptr);
- }
+ return IOControl(ctlCode,
+ ptr.ToPointer(), (uint)Marshal.SizeOf(inBuffer),
+ null, 0,
+ out _);
+ }
+ finally
+ {
+ Marshal.DestroyStructure(ptr);
+ Marshal.FreeHGlobal(ptr);
}
}
+ }
- public unsafe bool IOControl(uint ctlCode, ref TIn inBuffer, out TOut outBuffer)
- where TIn : unmanaged
- where TOut : unmanaged
+ public unsafe bool IOControl(uint ctlCode, ref TIn inBuffer, out TOut outBuffer)
+ where TIn : unmanaged
+ where TOut : unmanaged
+ {
+ fixed (TIn* pInBuffer = &inBuffer)
+ fixed (TOut* pOutBuffer = &outBuffer)
{
- fixed (TIn* pInBuffer = &inBuffer)
- fixed (TOut* pOutBuffer = &outBuffer)
+ IntPtr inPtr = typeof(TIn).IsValueType
+ ? (IntPtr)pInBuffer
+ : Marshal.AllocHGlobal(Marshal.SizeOf(inBuffer));
+ IntPtr outPtr = typeof(TOut).IsValueType
+ ? (IntPtr)pOutBuffer
+ : Marshal.AllocHGlobal(Marshal.SizeOf(outBuffer));
+
+ try
{
- IntPtr inPtr = typeof(TIn).IsValueType
- ? (IntPtr)pInBuffer
- : Marshal.AllocHGlobal(Marshal.SizeOf(inBuffer));
- IntPtr outPtr = typeof(TOut).IsValueType
- ? (IntPtr)pOutBuffer
- : Marshal.AllocHGlobal(Marshal.SizeOf(outBuffer));
-
- try
+ if (!typeof(TIn).IsValueType)
{
- if (!typeof(TIn).IsValueType)
- {
- Marshal.StructureToPtr(inBuffer, inPtr, false);
- }
-
- if (IOControl(ctlCode,
- inPtr.ToPointer(), (uint)Marshal.SizeOf(inBuffer),
- outPtr.ToPointer(), (uint)Marshal.SizeOf(outBuffer),
- out _))
- {
- if (!typeof(TOut).IsValueType)
- {
- Marshal.PtrToStructure(outPtr, outBuffer);
- }
- return true;
- }
- return false;
+ Marshal.StructureToPtr(inBuffer, inPtr, false);
}
- finally
+
+ if (IOControl(ctlCode,
+ inPtr.ToPointer(), (uint)Marshal.SizeOf(inBuffer),
+ outPtr.ToPointer(), (uint)Marshal.SizeOf(outBuffer),
+ out _))
{
- if (!typeof(TIn).IsValueType)
- {
- Marshal.DestroyStructure(inPtr);
- Marshal.FreeHGlobal(inPtr);
- }
if (!typeof(TOut).IsValueType)
{
- Marshal.DestroyStructure(outPtr);
- Marshal.FreeHGlobal(outPtr);
+ Marshal.PtrToStructure(outPtr, outBuffer);
}
+ return true;
+ }
+ return false;
+ }
+ finally
+ {
+ if (!typeof(TIn).IsValueType)
+ {
+ Marshal.DestroyStructure(inPtr);
+ Marshal.FreeHGlobal(inPtr);
+ }
+ if (!typeof(TOut).IsValueType)
+ {
+ Marshal.DestroyStructure(outPtr);
+ Marshal.FreeHGlobal(outPtr);
}
}
}
+ }
- #region Cleanup code
- ~Driver()
- {
- // Close all open file and service handles
- Close();
- }
- #endregion
+ #region Cleanup code
+ ~Driver()
+ {
+ // Close all open file and service handles
+ Close();
}
+ #endregion
}
diff --git a/YAMDCC.ECAccess/EC.cs b/YAMDCC.ECAccess/EC.cs
index 0f23ea2..c51d0da 100644
--- a/YAMDCC.ECAccess/EC.cs
+++ b/YAMDCC.ECAccess/EC.cs
@@ -20,446 +20,445 @@
using System.Runtime.InteropServices;
using System.Threading;
-namespace YAMDCC.ECAccess
+namespace YAMDCC.ECAccess;
+
+///
+/// Methods to access the embedded controller in a computer.
+///
+public sealed class EC
{
- ///
- /// Methods to access the embedded controller in a computer.
- ///
- public sealed class EC
+ // See ACPI specs ch 12.2
+ [Flags]
+ private enum ECStatus : byte
{
- // See ACPI specs ch 12.2
- [Flags]
- private enum ECStatus : byte
- {
- None = 0x00,
- OutputBufferFull = 0x01, // OBF
- InputBufferFull = 0x02, // IBF
- Command = 0x08, // CMD
- BurstMode = 0x10, // BURST
- SCIEventPending = 0x20, // SCI_EVT
- SMIEventPending = 0x40 // SMI_EVT
- }
+ None = 0x00,
+ OutputBufferFull = 0x01, // OBF
+ InputBufferFull = 0x02, // IBF
+ Command = 0x08, // CMD
+ BurstMode = 0x10, // BURST
+ SCIEventPending = 0x20, // SCI_EVT
+ SMIEventPending = 0x40 // SMI_EVT
+ }
- // See ACPI specs ch 12.3
- private enum ECCommand : byte
- {
- Read = 0x80, // RD_EC
- Write = 0x81, // WR_EC
- BurstEnable = 0x82, // BE_EC
- BurstDisable = 0x83, // BD_EC
- Query = 0x84 // QR_EC
- }
+ // See ACPI specs ch 12.3
+ private enum ECCommand : byte
+ {
+ Read = 0x80, // RD_EC
+ Write = 0x81, // WR_EC
+ BurstEnable = 0x82, // BE_EC
+ BurstDisable = 0x83, // BD_EC
+ Query = 0x84 // QR_EC
+ }
- private const byte PORT_COMMAND = 0x66; //EC_SC
- private const byte PORT_DATA = 0x62; //EC_DATA
+ private const byte PORT_COMMAND = 0x66; //EC_SC
+ private const byte PORT_DATA = 0x62; //EC_DATA
- ///
- /// The maximum number of read/write attempts before returning an error.
- ///
- private const int RW_MAX_RETRIES = 5;
+ ///
+ /// The maximum number of read/write attempts before returning an error.
+ ///
+ private const int RW_MAX_RETRIES = 5;
- ///
- /// The maximum time (in ticks)
- /// to wait for an EC status.
- ///
- private static readonly long ECStatusTimeoutTicks =
- Stopwatch.Frequency / 100; // 10 ms, should be plenty for EC status waits
+ ///
+ /// The maximum time (in ticks)
+ /// to wait for an EC status.
+ ///
+ private static readonly long ECStatusTimeoutTicks =
+ Stopwatch.Frequency / 100; // 10 ms, should be plenty for EC status waits
- ///
- /// Used to synchronise EC access.
- ///
- private static readonly Mutex EcMutex = new();
+ ///
+ /// Used to synchronise EC access.
+ ///
+ private static readonly Mutex EcMutex = new();
- ///
- /// The underlying driver interface object.
- ///
- private readonly Driver _Driver;
+ ///
+ /// The underlying driver interface object.
+ ///
+ private readonly Driver _Driver;
- public EC()
- {
- _Driver = new Driver("WinRing0_1_2_0",
- Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
- Environment.Is64BitOperatingSystem
- ? "WinRing0x64.sys"
- : "WinRing0.sys"));
- }
+ public EC()
+ {
+ _Driver = new Driver("WinRing0_1_2_0",
+ Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
+ Environment.Is64BitOperatingSystem
+ ? "WinRing0x64.sys"
+ : "WinRing0.sys"));
+ }
- ///
- /// Loads the WinRing0 driver (if not already loaded).
- ///
- ///
- /// If false was returned by this function,
- /// can be called to check for driver errors.
- ///
- ///
- /// true if the WinRing0 driver was loaded successfully
- /// (or is already loaded), false otherwise.
- ///
- public bool LoadDriver()
+ ///
+ /// Loads the WinRing0 driver (if not already loaded).
+ ///
+ ///
+ /// If false was returned by this function,
+ /// can be called to check for driver errors.
+ ///
+ ///
+ /// true if the WinRing0 driver was loaded successfully
+ /// (or is already loaded), false otherwise.
+ ///
+ public bool LoadDriver()
+ {
+ // Attempt to open an already installed WinRing0 driver first
+ if (_Driver.Open())
{
- // Attempt to open an already installed WinRing0 driver first
- if (_Driver.Open())
- {
- return true;
- }
-
- // If opening the driver fails, uninstall (if installed) and reinstall it
- if (!_Driver.Uninstall())
- {
- return false;
- }
-
- if (!_Driver.Install())
- {
- _Driver.Uninstall();
- return false;
- }
-
- return _Driver.Open();
+ return true;
}
- ///
- /// Unloads the WinRing0 driver (if loaded).
- ///
- ///
- /// This function should be called when the program exits
- /// or otherwise no longer requires EC access.
- ///
- public void UnloadDriver()
+ // If opening the driver fails, uninstall (if installed) and reinstall it
+ if (!_Driver.Uninstall())
{
- if (GetRefCount() <= 1)
- {
- // only uninstall the driver if we're the last program using it
- // (Driver.Uninstall() calls Driver.Close() internally)
- _Driver.Uninstall();
- }
- else
- {
- // otherwise, just close the handle to the driver
- _Driver.Close();
- }
+ return false;
}
- ///
- /// Reads a byte from the EC at the specified register.
- ///
- ///
- /// The register to read from.
- ///
- ///
- /// If successful, contains the value at the specified register (otherwise zero).
- ///
- ///
- /// true if the operation was successful, otherwise false.
- ///
- public bool ReadByte(byte reg, out byte value)
+ if (!_Driver.Install())
{
- value = 0;
-
- // only attempt to read EC if driver connection has been opened
- if (_Driver.IsOpen)
- {
- for (int i = 0; i < RW_MAX_RETRIES; i++)
- {
- if (TryReadByte(reg, out value))
- {
- return true;
- }
- }
- }
+ _Driver.Uninstall();
return false;
}
- ///
- /// Writes a byte to the EC at the specified register.
- ///
- ///
- /// The register to write to.
- ///
- ///
- /// The value to write to the register.
- ///
- ///
- /// true if the operation was successful, otherwise false.
- ///
- public bool WriteByte(byte reg, byte value)
+ return _Driver.Open();
+ }
+
+ ///
+ /// Unloads the WinRing0 driver (if loaded).
+ ///
+ ///
+ /// This function should be called when the program exits
+ /// or otherwise no longer requires EC access.
+ ///
+ public void UnloadDriver()
+ {
+ if (GetRefCount() <= 1)
{
- // only attempt to write EC if driver connection has been opened
- if (_Driver.IsOpen)
- {
- for (int i = 0; i < RW_MAX_RETRIES; i++)
- {
- if (TryWriteByte(reg, value))
- {
- return true;
- }
- }
- }
- return false;
+ // only uninstall the driver if we're the last program using it
+ // (Driver.Uninstall() calls Driver.Close() internally)
+ _Driver.Uninstall();
}
-
- ///
- /// Reads a 16-bit integer (aka "word") from the EC at the specified register.
- ///
- ///
- /// The register to read from.
- ///
- ///
- /// Indicates the endianness of the value to be read.
- /// Defaults to false (little-endian).
- ///
- ///
- /// If successful, contains the value at the specified register (otherwise zero).
- ///
- ///
- /// true if the operation was successful, otherwise false.
- ///
- public bool ReadWord(byte reg, out ushort value, bool bigEndian = false)
+ else
{
- value = 0;
+ // otherwise, just close the handle to the driver
+ _Driver.Close();
+ }
+ }
+
+ ///
+ /// Reads a byte from the EC at the specified register.
+ ///
+ ///
+ /// The register to read from.
+ ///
+ ///
+ /// If successful, contains the value at the specified register (otherwise zero).
+ ///
+ ///
+ /// true if the operation was successful, otherwise false.
+ ///
+ public bool ReadByte(byte reg, out byte value)
+ {
+ value = 0;
- // only attempt to read EC if driver connection has been opened
- if (_Driver.IsOpen)
+ // only attempt to read EC if driver connection has been opened
+ if (_Driver.IsOpen)
+ {
+ for (int i = 0; i < RW_MAX_RETRIES; i++)
{
- for (int i = 0; i < RW_MAX_RETRIES; i++)
+ if (TryReadByte(reg, out value))
{
- if (TryReadWord(reg, bigEndian, out value))
- {
- return true;
- }
+ return true;
}
}
- return false;
}
+ return false;
+ }
- ///
- /// Writes a 16-bit integer (aka "word") to the EC at the specified register.
- ///
- ///
- /// The register to write to.
- ///
- ///
- /// The value to write at the register.
- ///
- ///
- /// Indicates the endianness of the value to be written.
- /// Defaults to false (little-endian).
- ///
- ///
- /// true if the operation was successful, otherwise false.
- ///
- public bool WriteWord(byte reg, ushort value, bool bigEndian = false)
+ ///
+ /// Writes a byte to the EC at the specified register.
+ ///
+ ///
+ /// The register to write to.
+ ///
+ ///
+ /// The value to write to the register.
+ ///
+ ///
+ /// true if the operation was successful, otherwise false.
+ ///
+ public bool WriteByte(byte reg, byte value)
+ {
+ // only attempt to write EC if driver connection has been opened
+ if (_Driver.IsOpen)
{
- // only attempt to write EC if driver connection has been opened
- if (_Driver.IsOpen)
+ for (int i = 0; i < RW_MAX_RETRIES; i++)
{
- for (int i = 0; i < RW_MAX_RETRIES; i++)
+ if (TryWriteByte(reg, value))
{
- if (TryWriteWord(reg, value, bigEndian))
- {
- return true;
- }
+ return true;
}
}
- return false;
}
+ return false;
+ }
- private bool TryReadByte(byte reg, out byte value)
+ ///
+ /// Reads a 16-bit integer (aka "word") from the EC at the specified register.
+ ///
+ ///
+ /// The register to read from.
+ ///
+ ///
+ /// Indicates the endianness of the value to be read.
+ /// Defaults to false (little-endian).
+ ///
+ ///
+ /// If successful, contains the value at the specified register (otherwise zero).
+ ///
+ ///
+ /// true if the operation was successful, otherwise false.
+ ///
+ public bool ReadWord(byte reg, out ushort value, bool bigEndian = false)
+ {
+ value = 0;
+
+ // only attempt to read EC if driver connection has been opened
+ if (_Driver.IsOpen)
{
- value = 0;
- if (EcMutex.WaitOne(2000))
+ for (int i = 0; i < RW_MAX_RETRIES; i++)
{
- try
+ if (TryReadWord(reg, bigEndian, out value))
{
- return WaitWrite() && WriteIOPort(PORT_COMMAND, (byte)ECCommand.Read)
- && WaitWrite() && WriteIOPort(PORT_DATA, reg)
- && WaitWrite() && WaitRead()
- && ReadIOPort(PORT_DATA, out value);
- }
- finally
- {
- EcMutex.ReleaseMutex();
+ return true;
}
}
- return false;
}
+ return false;
+ }
- private bool TryWriteByte(byte reg, byte value)
+ ///
+ /// Writes a 16-bit integer (aka "word") to the EC at the specified register.
+ ///
+ ///
+ /// The register to write to.
+ ///
+ ///
+ /// The value to write at the register.
+ ///
+ ///
+ /// Indicates the endianness of the value to be written.
+ /// Defaults to false (little-endian).
+ ///
+ ///
+ /// true if the operation was successful, otherwise false.
+ ///
+ public bool WriteWord(byte reg, ushort value, bool bigEndian = false)
+ {
+ // only attempt to write EC if driver connection has been opened
+ if (_Driver.IsOpen)
{
- if (EcMutex.WaitOne(2000))
+ for (int i = 0; i < RW_MAX_RETRIES; i++)
{
- try
- {
- return WaitWrite() && WriteIOPort(PORT_COMMAND, (byte)ECCommand.Write)
- && WaitWrite() && WriteIOPort(PORT_DATA, reg)
- && WaitWrite() && WriteIOPort(PORT_DATA, value);
- }
- finally
+ if (TryWriteWord(reg, value, bigEndian))
{
- EcMutex.ReleaseMutex();
+ return true;
}
}
- return false;
}
+ return false;
+ }
- private bool TryReadWord(byte reg, bool bigEndian, out ushort value)
+ private bool TryReadByte(byte reg, out byte value)
+ {
+ value = 0;
+ if (EcMutex.WaitOne(2000))
{
- value = 0;
-
- // read least-significant byte
- if (!TryReadByte(bigEndian ? (byte)(reg + 1) : reg, out byte result))
+ try
{
- return false;
+ return WaitWrite() && WriteIOPort(PORT_COMMAND, (byte)ECCommand.Read)
+ && WaitWrite() && WriteIOPort(PORT_DATA, reg)
+ && WaitWrite() && WaitRead()
+ && ReadIOPort(PORT_DATA, out value);
}
- value = result;
-
- // read most-significant byte
- if (!TryReadByte(bigEndian ? reg : (byte)(reg + 1), out result))
+ finally
{
- return false;
+ EcMutex.ReleaseMutex();
}
- value |= (ushort)(result << 8);
-
- return true;
}
+ return false;
+ }
- private bool TryWriteWord(byte reg, ushort value, bool bigEndian)
+ private bool TryWriteByte(byte reg, byte value)
+ {
+ if (EcMutex.WaitOne(2000))
{
- byte lsb, msb;
-
- if (bigEndian)
+ try
{
- msb = (byte)value;
- lsb = (byte)(value >> 8);
+ return WaitWrite() && WriteIOPort(PORT_COMMAND, (byte)ECCommand.Write)
+ && WaitWrite() && WriteIOPort(PORT_DATA, reg)
+ && WaitWrite() && WriteIOPort(PORT_DATA, value);
}
- else
+ finally
{
- msb = (byte)(value >> 8);
- lsb = (byte)value;
+ EcMutex.ReleaseMutex();
}
+ }
+ return false;
+ }
- return TryWriteByte(reg, lsb) && TryWriteByte((byte)(reg + 1), msb);
+ private bool TryReadWord(byte reg, bool bigEndian, out ushort value)
+ {
+ value = 0;
+
+ // read least-significant byte
+ if (!TryReadByte(bigEndian ? (byte)(reg + 1) : reg, out byte result))
+ {
+ return false;
}
+ value = result;
- ///
- /// Waits for the EC to process a read command.
- ///
- ///
- /// true if the EC is ready to have data read from it,
- /// false if the operation timed out.
- ///
- private bool WaitRead()
+ // read most-significant byte
+ if (!TryReadByte(bigEndian ? reg : (byte)(reg + 1), out result))
{
- return WaitForECStatus(ECStatus.OutputBufferFull, true);
+ return false;
}
+ value |= (ushort)(result << 8);
- ///
- /// Waits for the EC to process a write command.
- ///
- ///
- /// true if the EC is ready to accept data,
- /// false if the operation timed out.
- ///
- private bool WaitWrite()
+ return true;
+ }
+
+ private bool TryWriteWord(byte reg, ushort value, bool bigEndian)
+ {
+ byte lsb, msb;
+
+ if (bigEndian)
+ {
+ msb = (byte)value;
+ lsb = (byte)(value >> 8);
+ }
+ else
{
- return WaitForECStatus(ECStatus.InputBufferFull, false);
+ msb = (byte)(value >> 8);
+ lsb = (byte)value;
}
- ///
- /// Waits for the specified to be set/unset.
- ///
- ///
- /// The to wait for.
- ///
- ///
- /// Whether to wait for the status to be set or unset.
- ///
- ///
- /// true if the EC status was (un)set before timing out,
- /// otherwise false.
- ///
- private bool WaitForECStatus(ECStatus status, bool isSet)
+ return TryWriteByte(reg, lsb) && TryWriteByte((byte)(reg + 1), msb);
+ }
+
+ ///
+ /// Waits for the EC to process a read command.
+ ///
+ ///
+ /// true if the EC is ready to have data read from it,
+ /// false if the operation timed out.
+ ///
+ private bool WaitRead()
+ {
+ return WaitForECStatus(ECStatus.OutputBufferFull, true);
+ }
+
+ ///
+ /// Waits for the EC to process a write command.
+ ///
+ ///
+ /// true if the EC is ready to accept data,
+ /// false if the operation timed out.
+ ///
+ private bool WaitWrite()
+ {
+ return WaitForECStatus(ECStatus.InputBufferFull, false);
+ }
+
+ ///
+ /// Waits for the specified to be set/unset.
+ ///
+ ///
+ /// The to wait for.
+ ///
+ ///
+ /// Whether to wait for the status to be set or unset.
+ ///
+ ///
+ /// true if the EC status was (un)set before timing out,
+ /// otherwise false.
+ ///
+ private bool WaitForECStatus(ECStatus status, bool isSet)
+ {
+ Stopwatch sw = Stopwatch.StartNew();
+ try
{
- Stopwatch sw = Stopwatch.StartNew();
- try
+ while (sw.ElapsedTicks < ECStatusTimeoutTicks)
{
- while (sw.ElapsedTicks < ECStatusTimeoutTicks)
+ // Read the EC status from the command port
+ if (ReadIOPort(PORT_COMMAND, out byte value))
{
- // Read the EC status from the command port
- if (ReadIOPort(PORT_COMMAND, out byte value))
- {
- ECStatus ecStatus = (ECStatus)value;
- bool ecIsSet = (status & ecStatus) == status;
+ ECStatus ecStatus = (ECStatus)value;
+ bool ecIsSet = (status & ecStatus) == status;
- if (isSet == ecIsSet)
- {
- return true;
- }
+ if (isSet == ecIsSet)
+ {
+ return true;
}
}
}
- finally
- {
- sw.Stop();
- }
-
- return false;
}
-
- private bool ReadIOPort(uint port, out byte value)
+ finally
{
- bool success = _Driver.IOControl(
- (uint)Ring0Control.ReadIOPortByte,
- ref port, out uint val);
-
- // bitwise AND operation prevents integer overflow
- value = (byte)(val & 0xFF);
- return success;
+ sw.Stop();
}
- private bool WriteIOPort(ushort port, byte value)
- {
- WriteIOPortInput input = new(port, value);
- return _Driver.IOControl((uint)Ring0Control.WriteIOPortByte, ref input);
- }
+ return false;
+ }
- private uint GetRefCount()
- {
- uint refCount = 0;
- return _Driver.IOControl((uint)Ring0Control.GetRefCount, ref refCount, out refCount) ? refCount : 0;
- }
+ private bool ReadIOPort(uint port, out byte value)
+ {
+ bool success = _Driver.IOControl(
+ (uint)Ring0Control.ReadIOPortByte,
+ ref port, out uint val);
- ///
- /// Gets the last error produced by the underlying driver library.
- ///
- ///
- /// The last error code produced by the driver library.
- ///
- public int GetDriverError()
- {
- return _Driver.ErrorCode;
- }
+ // bitwise AND operation prevents integer overflow
+ value = (byte)(val & 0xFF);
+ return success;
+ }
- private enum Ring0Control : uint
- {
- // DeviceType, Function, Access (1 = Read, 2 = Write, 0 = Any)
- GetDriverVersion = 40000u << 16 | 0x800 << 2,
- GetRefCount = 40000u << 16 | 0x801 << 2,
- ReadIOPortByte = 40000u << 16 | 0x833 << 2 | 1 << 14,
- WriteIOPortByte = 40000u << 16 | 0x836 << 2 | 2 << 14,
- }
+ private bool WriteIOPort(ushort port, byte value)
+ {
+ WriteIOPortInput input = new(port, value);
+ return _Driver.IOControl((uint)Ring0Control.WriteIOPortByte, ref input);
+ }
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
- private struct WriteIOPortInput
- {
- public uint Port;
- public byte Value;
+ private uint GetRefCount()
+ {
+ uint refCount = 0;
+ return _Driver.IOControl((uint)Ring0Control.GetRefCount, ref refCount, out refCount) ? refCount : 0;
+ }
- public WriteIOPortInput(uint port, byte value)
- {
- Port = port;
- Value = value;
- }
+ ///
+ /// Gets the last error produced by the underlying driver library.
+ ///
+ ///
+ /// The last error code produced by the driver library.
+ ///
+ public int GetDriverError()
+ {
+ return _Driver.ErrorCode;
+ }
+
+ private enum Ring0Control : uint
+ {
+ // DeviceType, Function, Access (1 = Read, 2 = Write, 0 = Any)
+ GetDriverVersion = 40000u << 16 | 0x800 << 2,
+ GetRefCount = 40000u << 16 | 0x801 << 2,
+ ReadIOPortByte = 40000u << 16 | 0x833 << 2 | 1 << 14,
+ WriteIOPortByte = 40000u << 16 | 0x836 << 2 | 2 << 14,
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ private struct WriteIOPortInput
+ {
+ public uint Port;
+ public byte Value;
+
+ public WriteIOPortInput(uint port, byte value)
+ {
+ Port = port;
+ Value = value;
}
}
}
diff --git a/YAMDCC.ECAccess/Win32/AdvApi32.cs b/YAMDCC.ECAccess/Win32/AdvApi32.cs
index 2beae0f..7e16bc4 100644
--- a/YAMDCC.ECAccess/Win32/AdvApi32.cs
+++ b/YAMDCC.ECAccess/Win32/AdvApi32.cs
@@ -17,329 +17,328 @@
using System;
using System.Runtime.InteropServices;
-namespace YAMDCC.ECAccess.Win32
+namespace YAMDCC.ECAccess.Win32;
+
+///
+/// Wraps native Win32 functions from advapi32.dll.
+///
+internal static class AdvApi32
{
///
- /// Wraps native Win32 functions from advapi32.dll.
+ /// Opens an handle with full access to the local computer's
+ /// active service control manager (SCM) database.
+ ///
+ ///
+ /// See the MSDN documentation for more info:
+ ///
+ ///
+ ///
+ /// An handle (as an ) to the local computer's
+ /// active SCM database, if the function succeeds.
+ /// if the function fails. Call
+ /// to get error information.
+ ///
+ [DllImport("advapi32.dll",
+ CharSet = CharSet.Unicode, ExactSpelling = true,
+ EntryPoint = "OpenSCManagerW", SetLastError = true)]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
+ internal static extern IntPtr OpenSCManager(
+ string lpMachineName,
+ string lpDatabaseName,
+ [MarshalAs(UnmanagedType.U4)] SCMAccess dwDesiredAccess);
+
+ ///
+ /// Creates and adds a service to the local computer.
+ ///
+ ///
+ /// See the MSDN documentation for more info:
+ ///
+ ///
+ ///
+ /// An handle to the service if the function succeeds.
+ /// if the function fails. Call
+ /// for error information.
+ ///
+ [DllImport("advapi32.dll",
+ CharSet = CharSet.Unicode, ExactSpelling = true,
+ EntryPoint = "CreateServiceW", SetLastError = true)]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
+ internal static extern IntPtr CreateService(
+ IntPtr hSCManager,
+ string lpServiceName,
+ [Optional] string lpDisplayName,
+ [MarshalAs(UnmanagedType.U4)] ServiceAccess dwDesiredAccess,
+ [MarshalAs(UnmanagedType.U4)] ServiceType dwServiceType,
+ [MarshalAs(UnmanagedType.U4)] ServiceStartType dwStartType,
+ [MarshalAs(UnmanagedType.U4)] ServiceError dwErrorControl,
+ [Optional] string lpBinaryPathName,
+ [Optional] string lpLoadOrderGroup,
+ [Optional] string lpdwTagId,
+ [Optional] string lpDependencies,
+ [Optional] string lpServiceStartName,
+ [Optional] string lpPassword);
+
+ ///
+ /// Opens an existing service.
+ ///
+ ///
+ /// See the MSDN documentation for more info:
+ ///
+ ///
+ ///
+ /// An handle to the service if the function succeeds.
+ /// if the function fails. Call
+ /// for error information.
+ ///
+ [DllImport("advapi32.dll",
+ CharSet = CharSet.Unicode, ExactSpelling = true,
+ EntryPoint = "OpenServiceW", SetLastError = true)]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
+ internal static extern IntPtr OpenService(
+ IntPtr hSCManager,
+ string lpServiceName,
+ [MarshalAs(UnmanagedType.U4)] ServiceAccess dwDesiredAccess);
+
+ ///
+ /// Starts a service.
+ ///
+ ///
+ /// See the MSDN documentation for more info:
+ ///
+ ///
+ ///
+ /// true if the function succeeds, otherwise false.
+ /// Call to get error information.
+ ///
+ [DllImport("advapi32.dll",
+ CharSet = CharSet.Unicode, ExactSpelling = true,
+ EntryPoint = "StartServiceW", SetLastError = true)]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool StartService(
+ IntPtr hService,
+ uint dwNumServiceArgs,
+ [Optional] IntPtr lpServiceArgVectors);
+
+ ///
+ /// Sends a control code to a service.
+ ///
+ ///
+ /// See the MSDN documentation for more info:
+ ///
+ ///
+ ///
+ /// true if the function succeeds, otherwise false.
+ /// Call to get error information.
+ ///
+ [DllImport("advapi32.dll",
+ ExactSpelling = true, SetLastError = true)]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool ControlService(
+ IntPtr hService,
+ uint dwControl,
+ out ServiceStatus lpServiceStatus);
+
+ ///
+ [DllImport("advapi32.dll",
+ ExactSpelling = true, SetLastError = true)]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool ControlService(
+ IntPtr hService,
+ [MarshalAs(UnmanagedType.U4)] ServiceControlCode dwControl,
+ out ServiceStatus lpServiceStatus);
+
+ ///
+ /// Deletes a service from the system.
///
- internal static class AdvApi32
+ ///
+ /// See the MSDN documentation for more info:
+ ///
+ ///
+ ///
+ /// true if the function succeeds, otherwise false.
+ /// Call to get error information.
+ ///
+ [DllImport("advapi32.dll",
+ ExactSpelling = true, SetLastError = true)]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
+ internal static extern bool DeleteService(IntPtr hService);
+
+ ///
+ /// Closes an handle to a service control manager or service.
+ ///
+ ///
+ /// See the MSDN documentation for more info:
+ ///
+ ///
+ ///
+ /// true if the function succeeds, otherwise false.
+ /// To get error information, call .
+ ///
+ [DllImport("advapi32.dll",
+ ExactSpelling = true, SetLastError = true)]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
+ internal static extern bool CloseServiceHandle(IntPtr hSCObject);
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct ServiceStatus
+ {
+ internal ServiceType dwServiceType;
+ internal ServiceState dwCurrentState;
+ internal uint dwControlsAccepted;
+ internal uint dwWin32ExitCode;
+ internal uint dwServiceSpecificExitCode;
+ internal uint dwCheckPoint;
+ internal uint dwWaitHint;
+ }
+
+ internal enum ServiceControlCode : uint
+ {
+ Stop = 0x01,
+ Pause = 0x02,
+ Continue = 0x03,
+ Interrogate = 0x04,
+ ParamChange = 0x06,
+ NetBindAdd = 0x07,
+ NetBindRemove = 0x08,
+ NetBindEnable = 0x09,
+ NetBindDisable = 0x0A,
+ }
+
+ [Flags]
+ internal enum SCMAccess : uint
+ {
+ Connect = 0x0001,
+ CreateService = 0x0002,
+ EnumerateService = 0x0004,
+ Lock = 0x0008,
+ QueryLockStatus = 0x0010,
+ ModifyBootConfig = 0x0020,
+ All = 0xF003F,
+ }
+
+ [Flags]
+ internal enum ServiceAccess : uint
+ {
+ QueryConfig = 0x0001,
+ ChangeConfig = 0x0002,
+ QueryStatus = 0x0004,
+ EnumerateDependents = 0x0008,
+ Start = 0x0010,
+ Stop = 0x0020,
+ PauseContinue = 0x0040,
+ Interrogate = 0x0080,
+ UserDefinedControl = 0x0100,
+ Delete = 0x10000,
+ ReadControl = 0x20000,
+ WriteDac = 0x40000,
+ WriteOwner = 0x80000,
+ All = 0xF01FF,
+ }
+
+ [Flags]
+ internal enum ServiceType : uint
{
///
- /// Opens an handle with full access to the local computer's
- /// active service control manager (SCM) database.
+ /// A kernel-mode driver service.
///
- ///
- /// See the MSDN documentation for more info:
- ///
- ///
- ///
- /// An handle (as an ) to the local computer's
- /// active SCM database, if the function succeeds.
- /// if the function fails. Call
- /// to get error information.
- ///
- [DllImport("advapi32.dll",
- CharSet = CharSet.Unicode, ExactSpelling = true,
- EntryPoint = "OpenSCManagerW", SetLastError = true)]
- [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- internal static extern IntPtr OpenSCManager(
- string lpMachineName,
- string lpDatabaseName,
- [MarshalAs(UnmanagedType.U4)] SCMAccess dwDesiredAccess);
-
+ KernelDriver = 0x00000001,
///
- /// Creates and adds a service to the local computer.
+ /// A file system driver service.
///
- ///
- /// See the MSDN documentation for more info:
- ///
- ///
- ///
- /// An handle to the service if the function succeeds.
- /// if the function fails. Call
- /// for error information.
- ///
- [DllImport("advapi32.dll",
- CharSet = CharSet.Unicode, ExactSpelling = true,
- EntryPoint = "CreateServiceW", SetLastError = true)]
- [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- internal static extern IntPtr CreateService(
- IntPtr hSCManager,
- string lpServiceName,
- [Optional] string lpDisplayName,
- [MarshalAs(UnmanagedType.U4)] ServiceAccess dwDesiredAccess,
- [MarshalAs(UnmanagedType.U4)] ServiceType dwServiceType,
- [MarshalAs(UnmanagedType.U4)] ServiceStartType dwStartType,
- [MarshalAs(UnmanagedType.U4)] ServiceError dwErrorControl,
- [Optional] string lpBinaryPathName,
- [Optional] string lpLoadOrderGroup,
- [Optional] string lpdwTagId,
- [Optional] string lpDependencies,
- [Optional] string lpServiceStartName,
- [Optional] string lpPassword);
-
+ FileSystemDriver = 0x00000002,
///
- /// Opens an existing service.
+ /// A service that runs in its own process.
///
- ///
- /// See the MSDN documentation for more info:
- ///
- ///
- ///
- /// An handle to the service if the function succeeds.
- /// if the function fails. Call
- /// for error information.
- ///
- [DllImport("advapi32.dll",
- CharSet = CharSet.Unicode, ExactSpelling = true,
- EntryPoint = "OpenServiceW", SetLastError = true)]
- [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- internal static extern IntPtr OpenService(
- IntPtr hSCManager,
- string lpServiceName,
- [MarshalAs(UnmanagedType.U4)] ServiceAccess dwDesiredAccess);
-
+ Win32OwnProcess = 0x00000010,
///
- /// Starts a service.
+ /// A service that shares a process with one or more other
+ /// services.
///
///
- /// See the MSDN documentation for more info:
- ///
+ /// An example of an executable that spawns multiple services
+ /// is Windows' svchost.exe, which hosts many internal
+ /// Windows services.
///
- ///
- /// true if the function succeeds, otherwise false.
- /// Call to get error information.
- ///
- [DllImport("advapi32.dll",
- CharSet = CharSet.Unicode, ExactSpelling = true,
- EntryPoint = "StartServiceW", SetLastError = true)]
- [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool StartService(
- IntPtr hService,
- uint dwNumServiceArgs,
- [Optional] IntPtr lpServiceArgVectors);
+ Win32ShareProcess = 0x00000020,
+ }
+ internal enum ServiceState : uint
+ {
+ Stopped = 1U,
+ StartPending = 2U,
+ StopPending = 3U,
+ Running = 4U,
+ ContinuePending = 5U,
+ PausePending = 6U,
+ Paused = 7U,
+ }
+
+ internal enum ServiceStartType : uint
+ {
///
- /// Sends a control code to a service.
+ /// A device driver started by the system loader.
///
///
- /// See the MSDN documentation for more info:
- ///
+ /// Valid only for driver services.
///
- ///
- /// true if the function succeeds, otherwise false.
- /// Call to get error information.
- ///
- [DllImport("advapi32.dll",
- ExactSpelling = true, SetLastError = true)]
- [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool ControlService(
- IntPtr hService,
- uint dwControl,
- out ServiceStatus lpServiceStatus);
-
- ///
- [DllImport("advapi32.dll",
- ExactSpelling = true, SetLastError = true)]
- [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern bool ControlService(
- IntPtr hService,
- [MarshalAs(UnmanagedType.U4)] ServiceControlCode dwControl,
- out ServiceStatus lpServiceStatus);
-
+ BootStart = 0U,
///
- /// Deletes a service from the system.
+ /// A device driver started by the IoInitSystem function.
///
///
- /// See the MSDN documentation for more info:
- ///
+ /// Valid only for driver services.
///
- ///
- /// true if the function succeeds, otherwise false.
- /// Call to get error information.
- ///
- [DllImport("advapi32.dll",
- ExactSpelling = true, SetLastError = true)]
- [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- internal static extern bool DeleteService(IntPtr hService);
-
+ SystemStart = 1U,
+ ///
+ /// A service started automatically by the Service
+ /// Control Manager during system startup.
+ ///
+ AutoStart = 2U,
///
- /// Closes an handle to a service control manager or service.
+ /// A service started by the Service Control Manager when a
+ /// process calls the StartService function.
+ ///
+ DemandStart = 3U,
+ ///
+ /// A service that is disabled.
///
///
- /// See the MSDN documentation for more info:
- ///
+ /// Disabled services cannot be started.
///
- ///
- /// true if the function succeeds, otherwise false.
- /// To get error information, call .
- ///
- [DllImport("advapi32.dll",
- ExactSpelling = true, SetLastError = true)]
- [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- internal static extern bool CloseServiceHandle(IntPtr hSCObject);
-
- [StructLayout(LayoutKind.Sequential)]
- internal struct ServiceStatus
- {
- internal ServiceType dwServiceType;
- internal ServiceState dwCurrentState;
- internal uint dwControlsAccepted;
- internal uint dwWin32ExitCode;
- internal uint dwServiceSpecificExitCode;
- internal uint dwCheckPoint;
- internal uint dwWaitHint;
- }
-
- internal enum ServiceControlCode : uint
- {
- Stop = 0x01,
- Pause = 0x02,
- Continue = 0x03,
- Interrogate = 0x04,
- ParamChange = 0x06,
- NetBindAdd = 0x07,
- NetBindRemove = 0x08,
- NetBindEnable = 0x09,
- NetBindDisable = 0x0A,
- }
-
- [Flags]
- internal enum SCMAccess : uint
- {
- Connect = 0x0001,
- CreateService = 0x0002,
- EnumerateService = 0x0004,
- Lock = 0x0008,
- QueryLockStatus = 0x0010,
- ModifyBootConfig = 0x0020,
- All = 0xF003F,
- }
-
- [Flags]
- internal enum ServiceAccess : uint
- {
- QueryConfig = 0x0001,
- ChangeConfig = 0x0002,
- QueryStatus = 0x0004,
- EnumerateDependents = 0x0008,
- Start = 0x0010,
- Stop = 0x0020,
- PauseContinue = 0x0040,
- Interrogate = 0x0080,
- UserDefinedControl = 0x0100,
- Delete = 0x10000,
- ReadControl = 0x20000,
- WriteDac = 0x40000,
- WriteOwner = 0x80000,
- All = 0xF01FF,
- }
-
- [Flags]
- internal enum ServiceType : uint
- {
- ///
- /// A kernel-mode driver service.
- ///
- KernelDriver = 0x00000001,
- ///
- /// A file system driver service.
- ///
- FileSystemDriver = 0x00000002,
- ///
- /// A service that runs in its own process.
- ///
- Win32OwnProcess = 0x00000010,
- ///
- /// A service that shares a process with one or more other
- /// services.
- ///
- ///
- /// An example of an executable that spawns multiple services
- /// is Windows' svchost.exe, which hosts many internal
- /// Windows services.
- ///
- Win32ShareProcess = 0x00000020,
- }
-
- internal enum ServiceState : uint
- {
- Stopped = 1U,
- StartPending = 2U,
- StopPending = 3U,
- Running = 4U,
- ContinuePending = 5U,
- PausePending = 6U,
- Paused = 7U,
- }
-
- internal enum ServiceStartType : uint
- {
- ///
- /// A device driver started by the system loader.
- ///
- ///
- /// Valid only for driver services.
- ///
- BootStart = 0U,
- ///
- /// A device driver started by the IoInitSystem function.
- ///
- ///
- /// Valid only for driver services.
- ///
- SystemStart = 1U,
- ///
- /// A service started automatically by the Service
- /// Control Manager during system startup.
- ///
- AutoStart = 2U,
- ///
- /// A service started by the Service Control Manager when a
- /// process calls the StartService function.
- ///
- DemandStart = 3U,
- ///
- /// A service that is disabled.
- ///
- ///
- /// Disabled services cannot be started.
- ///
- Disabled = 4U,
- }
+ Disabled = 4U,
+ }
+ ///
+ /// The action to take if a service fails to start.
+ ///
+ internal enum ServiceError : uint
+ {
+ ///
+ /// The error is ignored and the service continues to
+ /// start up.
+ ///
+ Ignore = 0U,
+ ///
+ /// The error is logged to the event log, but the
+ /// service continues to start up.
+ ///
+ Normal = 1U,
+ ///
+ /// The error is logged to the event log. If the last-known-good
+ /// configuration is being started, the service continues to start
+ /// up. Otherwise, the service is restarted with the last-known-good
+ /// configuration.
+ ///
+ Severe = 2U,
///
- /// The action to take if a service fails to start.
+ /// The error is logged to the event log. If the last-known-good
+ /// configuration is being started, the service fails to start.
+ /// Otherwise, the service is restarted with the last-known-good
+ /// configuration.
///
- internal enum ServiceError : uint
- {
- ///
- /// The error is ignored and the service continues to
- /// start up.
- ///
- Ignore = 0U,
- ///
- /// The error is logged to the event log, but the
- /// service continues to start up.
- ///
- Normal = 1U,
- ///
- /// The error is logged to the event log. If the last-known-good
- /// configuration is being started, the service continues to start
- /// up. Otherwise, the service is restarted with the last-known-good
- /// configuration.
- ///
- Severe = 2U,
- ///
- /// The error is logged to the event log. If the last-known-good
- /// configuration is being started, the service fails to start.
- /// Otherwise, the service is restarted with the last-known-good
- /// configuration.
- ///
- Critical = 3U,
- }
+ Critical = 3U,
}
}
diff --git a/YAMDCC.ECAccess/Win32/Kernel32.cs b/YAMDCC.ECAccess/Win32/Kernel32.cs
index f181405..70f8407 100644
--- a/YAMDCC.ECAccess/Win32/Kernel32.cs
+++ b/YAMDCC.ECAccess/Win32/Kernel32.cs
@@ -19,93 +19,92 @@
using System.Runtime.InteropServices;
using System.Threading;
-namespace YAMDCC.ECAccess.Win32
+namespace YAMDCC.ECAccess.Win32;
+
+///
+/// Wraps native Win32 functions from kernel32.dll.
+///
+internal static class Kernel32
{
///
- /// Wraps native Win32 functions from kernel32.dll.
+ /// Closes an open handle.
///
- internal static class Kernel32
- {
- ///
- /// Closes an open handle.
- ///
- ///
- /// See the MSDN documentation for more info:
- ///
- ///
- ///
- /// An handle to close.
- ///
- ///
- /// true if the function succeeds, otherwise false.
- /// To get error information, call .
- ///
- [DllImport("kernel32.dll",
- ExactSpelling = true, SetLastError = true)]
- [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- internal static extern bool CloseHandle(IntPtr hObject);
+ ///
+ /// See the MSDN documentation for more info:
+ ///
+ ///
+ ///
+ /// An handle to close.
+ ///
+ ///
+ /// true if the function succeeds, otherwise false.
+ /// To get error information, call .
+ ///
+ [DllImport("kernel32.dll",
+ ExactSpelling = true, SetLastError = true)]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
+ internal static extern bool CloseHandle(IntPtr hObject);
- ///
- /// Open an installed device driver for direct communication.
- ///
- ///
- /// See the MSDN documentation for more info:
- ///
- ///
- ///
- ///
- /// An open handle (as an ) to the specified
- /// device driver if the function succeeds.
- ///
- ///
- /// if the function fails. Call
- /// for error information.
- ///
- ///
- [DllImport("kernel32.dll",
- CharSet = CharSet.Unicode, ExactSpelling = true,
- EntryPoint = "CreateFileW", SetLastError = true)]
- [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- internal static extern IntPtr CreateFile(
- string lpFileName,
- [MarshalAs(UnmanagedType.U4)] GenericAccessRights dwDesiredAccess,
- [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode,
- [Optional] IntPtr lpSecurityAttributes,
- [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition,
- [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes,
- [Optional] IntPtr hTemplateFile);
+ ///
+ /// Open an installed device driver for direct communication.
+ ///
+ ///
+ /// See the MSDN documentation for more info:
+ ///
+ ///
+ ///
+ ///
+ /// An open handle (as an ) to the specified
+ /// device driver if the function succeeds.
+ ///
+ ///
+ /// if the function fails. Call
+ /// for error information.
+ ///
+ ///
+ [DllImport("kernel32.dll",
+ CharSet = CharSet.Unicode, ExactSpelling = true,
+ EntryPoint = "CreateFileW", SetLastError = true)]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
+ internal static extern IntPtr CreateFile(
+ string lpFileName,
+ [MarshalAs(UnmanagedType.U4)] GenericAccessRights dwDesiredAccess,
+ [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode,
+ [Optional] IntPtr lpSecurityAttributes,
+ [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition,
+ [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes,
+ [Optional] IntPtr hTemplateFile);
- ///
- /// Sends an IO control code directly to a specified device driver.
- ///
- ///
- /// See the MSDN documentation for more info:
- ///
- ///
- ///
- /// true if the operation was successful, otherwise false.
- ///
- [DllImport("kernel32.dll",
- ExactSpelling = true, SetLastError = true)]
- [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- [return: MarshalAs(UnmanagedType.Bool)]
- internal static extern unsafe bool DeviceIoControl(
- IntPtr hDevice,
- uint dwIoControlCode,
- [Optional] void* lpInBuffer,
- uint nInBufferSize,
- [Optional] void* lpOutBuffer,
- uint nOutBufferSize,
- [Optional] out uint lpBytesReturned,
- [Optional] NativeOverlapped* lpOverlapped);
+ ///
+ /// Sends an IO control code directly to a specified device driver.
+ ///
+ ///
+ /// See the MSDN documentation for more info:
+ ///
+ ///
+ ///
+ /// true if the operation was successful, otherwise false.
+ ///
+ [DllImport("kernel32.dll",
+ ExactSpelling = true, SetLastError = true)]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern unsafe bool DeviceIoControl(
+ IntPtr hDevice,
+ uint dwIoControlCode,
+ [Optional] void* lpInBuffer,
+ uint nInBufferSize,
+ [Optional] void* lpOutBuffer,
+ uint nOutBufferSize,
+ [Optional] out uint lpBytesReturned,
+ [Optional] NativeOverlapped* lpOverlapped);
- internal enum GenericAccessRights : uint
- {
- None = 0,
- All = 0x10000000,
- Execute = 0x20000000,
- Write = 0x40000000,
- Read = 0x80000000,
- }
+ internal enum GenericAccessRights : uint
+ {
+ None = 0,
+ All = 0x10000000,
+ Execute = 0x20000000,
+ Write = 0x40000000,
+ Read = 0x80000000,
}
}
diff --git a/YAMDCC.ECInspector/ECValue.cs b/YAMDCC.ECInspector/ECValue.cs
index be43196..3f8f3d8 100644
--- a/YAMDCC.ECInspector/ECValue.cs
+++ b/YAMDCC.ECInspector/ECValue.cs
@@ -14,18 +14,17 @@
// You should have received a copy of the GNU General Public License along with
// YAMDCC. If not, see .
-namespace YAMDCC.ECInspector
+namespace YAMDCC.ECInspector;
+
+internal struct ECValue
{
- internal struct ECValue
- {
- ///
- /// The EC value itself.
- ///
- public int Value;
+ ///
+ /// The EC value itself.
+ ///
+ public int Value;
- ///
- /// How many EC polls it's been since was last updated.
- ///
- public int Age;
- }
+ ///
+ /// How many EC polls it's been since was last updated.
+ ///
+ public int Age;
}
diff --git a/YAMDCC.ECInspector/Program.cs b/YAMDCC.ECInspector/Program.cs
index d0c13a9..5a30b4a 100644
--- a/YAMDCC.ECInspector/Program.cs
+++ b/YAMDCC.ECInspector/Program.cs
@@ -22,251 +22,250 @@
using YAMDCC.Common;
using YAMDCC.IPC;
-namespace YAMDCC.ECInspector
+namespace YAMDCC.ECInspector;
+
+internal sealed class Program
{
- internal sealed class Program
- {
- private static readonly string ExeName =
- Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location);
+ private static readonly string ExeName =
+ Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location);
- private static readonly NamedPipeClient IPCClient =
- new("YAMDCC-Server");
+ private static readonly NamedPipeClient IPCClient =
+ new("YAMDCC-Server");
- private static readonly Mutex LogMutex = new(false);
+ private static readonly Mutex LogMutex = new(false);
- private static readonly ECValue[] ECValues = new ECValue[256];
+ private static readonly ECValue[] ECValues = new ECValue[256];
- private static int Main(string[] args)
+ private static int Main(string[] args)
+ {
+ if (!Utils.IsAdmin())
{
- if (!Utils.IsAdmin())
- {
- Console.WriteLine("ERROR: please re-run this program as admin.");
- return 255;
- }
+ Console.WriteLine("ERROR: please re-run this program as admin.");
+ return 255;
+ }
- // check that YAMDCC service is running
- ServiceController yamdccSvc = new("yamdccsvc");
- try
- {
- if (yamdccSvc.Status == ServiceControllerStatus.Stopped)
- {
- Console.WriteLine(
- "ERROR: the YAMDCC service is not running.\n" +
- "Please run the YAMDCC config editor to start the service.");
- return 1;
- }
- }
- catch
+ // check that YAMDCC service is running
+ ServiceController yamdccSvc = new("yamdccsvc");
+ try
+ {
+ if (yamdccSvc.Status == ServiceControllerStatus.Stopped)
{
Console.WriteLine(
- "ERROR: the YAMDCC service is not installed.\n" +
- "Please run the YAMDCC config editor to install the service.");
+ "ERROR: the YAMDCC service is not running.\n" +
+ "Please run the YAMDCC config editor to start the service.");
return 1;
}
- finally
- {
- yamdccSvc?.Close();
- }
+ }
+ catch
+ {
+ Console.WriteLine(
+ "ERROR: the YAMDCC service is not installed.\n" +
+ "Please run the YAMDCC config editor to install the service.");
+ return 1;
+ }
+ finally
+ {
+ yamdccSvc?.Close();
+ }
- if (args.Length == 0)
- {
- Console.WriteLine("ERROR: no command specified\n");
+ if (args.Length == 0)
+ {
+ Console.WriteLine("ERROR: no command specified\n");
+ PrintHelp();
+ return 2;
+ }
+ switch (args[0])
+ {
+ case "--version":
+ case "-v":
+ Console.WriteLine(Utils.GetVerString());
+ return 0;
+ case "--help":
+ case "-h":
PrintHelp();
- return 2;
- }
- switch (args[0])
- {
- case "--version":
- case "-v":
- Console.WriteLine(Utils.GetVerString());
+ return 0;
+ case "--dump":
+ case "-d":
+ if (ConnectService())
+ {
+ DumpEC(1000, 1);
return 0;
- case "--help":
- case "-h":
- PrintHelp();
+ }
+ return 3;
+ case "--monitor":
+ case "-m":
+ if (ConnectService())
+ {
+ DumpEC(1000, -1);
return 0;
- case "--dump":
- case "-d":
- if (ConnectService())
- {
- DumpEC(1000, 1);
- return 0;
- }
- return 3;
- case "--monitor":
- case "-m":
- if (ConnectService())
- {
- DumpEC(1000, -1);
- return 0;
- }
- return 3;
- case "":
- Console.WriteLine("ERROR: no command specified\n");
- PrintHelp();
- return 2;
- default:
- Console.WriteLine($"ERROR: unknown command: {args[0]}\n");
- PrintHelp();
- return 2;
- }
+ }
+ return 3;
+ case "":
+ Console.WriteLine("ERROR: no command specified\n");
+ PrintHelp();
+ return 2;
+ default:
+ Console.WriteLine($"ERROR: unknown command: {args[0]}\n");
+ PrintHelp();
+ return 2;
}
+ }
+
+ private static void PrintHelp()
+ {
+ Console.WriteLine(
+ "YAMDCC EC inspection utility\n\n" +
+ $"OS version: {Environment.OSVersion}\n" +
+ $"App version: {Utils.GetVerString()}\n" +
+ $"Revision (git): {Utils.GetRevision()}\n\n" +
+ $"Usage: {ExeName} []\n\n" +
+ "Commands:\n\n" +
+ " --help, -h Print this help screen\n" +
+ " --version, -v Print the program version\n" +
+ " --dump, -d Dump all EC registers\n" +
+ " --monitor, -m Dump EC and monitor for changes\n" +
+ " --interval, -i EC polling interval");
+ }
- private static void PrintHelp()
+ private static bool ConnectService()
+ {
+ IPCClient.ServerMessage += IPCClient_ServerMessage;
+ IPCClient.Error += IPCClient_Error;
+
+ IPCClient.Start();
+ if (!IPCClient.WaitForConnection(5000))
{
- Console.WriteLine(
- "YAMDCC EC inspection utility\n\n" +
- $"OS version: {Environment.OSVersion}\n" +
- $"App version: {Utils.GetVerString()}\n" +
- $"Revision (git): {Utils.GetRevision()}\n\n" +
- $"Usage: {ExeName} []\n\n" +
- "Commands:\n\n" +
- " --help, -h Print this help screen\n" +
- " --version, -v Print the program version\n" +
- " --dump, -d Dump all EC registers\n" +
- " --monitor, -m Dump EC and monitor for changes\n" +
- " --interval, -i EC polling interval");
+ Console.WriteLine("ERROR: failed to connect to YAMDCC service!");
+ return false;
}
+ return true;
+ }
- private static bool ConnectService()
+ private static void DumpEC(int interval, int loops)
+ {
+ for (int i = 0; i <= byte.MaxValue; i++)
{
- IPCClient.ServerMessage += IPCClient_ServerMessage;
- IPCClient.Error += IPCClient_Error;
-
- IPCClient.Start();
- if (!IPCClient.WaitForConnection(5000))
- {
- Console.WriteLine("ERROR: failed to connect to YAMDCC service!");
- return false;
- }
- return true;
+ ECValues[i] = new ECValue();
}
+ Console.Clear();
- private static void DumpEC(int interval, int loops)
+ Console.SetCursorPosition(0, 0);
+
+ // write heading
+ Console.Write("YAMDCC EC inspector\n\n 0x |");
+ for (int i = 0; i < 16; i++)
{
- for (int i = 0; i <= byte.MaxValue; i++)
- {
- ECValues[i] = new ECValue();
- }
- Console.Clear();
+ Console.Write($" 0{i:X}");
+ }
+ Console.WriteLine();
+ Console.WriteLine("----|------------------------------------------------");
- Console.SetCursorPosition(0, 0);
+ for (int i = 0; i < 16; i++)
+ {
+ Console.WriteLine($" {i:X}0 |");
+ }
- // write heading
- Console.Write("YAMDCC EC inspector\n\n 0x |");
- for (int i = 0; i < 16; i++)
- {
- Console.Write($" 0{i:X}");
- }
- Console.WriteLine();
- Console.WriteLine("----|------------------------------------------------");
+ Console.WriteLine("\nPress Ctrl+C to exit");
+ Console.CursorVisible = false;
+ Console.CancelKeyPress += Console_CancelKeyPress;
- for (int i = 0; i < 16; i++)
+ int j = 0;
+ while (true)
+ {
+ if (loops != -1 && j >= loops)
{
- Console.WriteLine($" {i:X}0 |");
+ break;
}
-
- Console.WriteLine("\nPress Ctrl+C to exit");
- Console.CursorVisible = false;
- Console.CancelKeyPress += Console_CancelKeyPress;
-
- int j = 0;
- while (true)
+ for (int i = 0; i <= byte.MaxValue; i++)
{
- if (loops != -1 && j >= loops)
- {
- break;
- }
- for (int i = 0; i <= byte.MaxValue; i++)
- {
- IPCClient.PushMessage(new ServiceCommand(Command.ReadECByte, $"{i}"));
- }
- Thread.Sleep(interval);
- j++;
+ IPCClient.PushMessage(new ServiceCommand(Command.ReadECByte, $"{i}"));
}
-
- Console.CursorVisible = true;
- IPCClient.Stop();
+ Thread.Sleep(interval);
+ j++;
}
- private static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
- {
- Console.CursorVisible = true;
- IPCClient.Stop();
- }
+ Console.CursorVisible = true;
+ IPCClient.Stop();
+ }
- private static void IPCClient_ServerMessage(object sender, PipeMessageEventArgs e)
+ private static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
+ {
+ Console.CursorVisible = true;
+ IPCClient.Stop();
+ }
+
+ private static void IPCClient_ServerMessage(object sender, PipeMessageEventArgs e)
+ {
+ if (LogMutex.WaitOne())
{
- if (LogMutex.WaitOne())
+ try
{
- try
+ switch (e.Message.Response)
{
- switch (e.Message.Response)
- {
- case Response.ReadResult:
- if (ParseArgs(e.Message.Value, out int[] args) && args.Length == 2)
- {
- int lowBits = args[0] & 0x0F,
- hiBits = (args[0] & 0xF0) >> 4;
- Console.SetCursorPosition(6 + lowBits * 3, 4 + hiBits);
+ case Response.ReadResult:
+ if (ParseArgs(e.Message.Value, out int[] args) && args.Length == 2)
+ {
+ int lowBits = args[0] & 0x0F,
+ hiBits = (args[0] & 0xF0) >> 4;
+ Console.SetCursorPosition(6 + lowBits * 3, 4 + hiBits);
- ConsoleColor original = Console.ForegroundColor;
+ ConsoleColor original = Console.ForegroundColor;
- if (ECValues[args[0]].Value == args[1])
- {
- ECValues[args[0]].Age++;
- Console.ForegroundColor = ConsoleColor.DarkRed;
- }
- else
- {
- ECValues[args[0]].Value = args[1];
- ECValues[args[0]].Age = 0;
- Console.ForegroundColor = ConsoleColor.Green;
- }
+ if (ECValues[args[0]].Value == args[1])
+ {
+ ECValues[args[0]].Age++;
+ Console.ForegroundColor = ConsoleColor.DarkRed;
+ }
+ else
+ {
+ ECValues[args[0]].Value = args[1];
+ ECValues[args[0]].Age = 0;
+ Console.ForegroundColor = ConsoleColor.Green;
+ }
- if (args[1] == 0)
- {
- Console.ForegroundColor = ConsoleColor.DarkGray;
- }
- Console.Write($"{args[1]:X2}");
- Console.ForegroundColor = original;
- Console.SetCursorPosition(0, 20);
+ if (args[1] == 0)
+ {
+ Console.ForegroundColor = ConsoleColor.DarkGray;
}
- break;
- }
- }
- finally
- {
- LogMutex.ReleaseMutex();
+ Console.Write($"{args[1]:X2}");
+ Console.ForegroundColor = original;
+ Console.SetCursorPosition(0, 20);
+ }
+ break;
}
}
+ finally
+ {
+ LogMutex.ReleaseMutex();
+ }
}
+ }
+
+ private static void IPCClient_Error(object sender, PipeErrorEventArgs e)
+ {
+ throw e.Exception;
+ }
- private static void IPCClient_Error(object sender, PipeErrorEventArgs e)
+ private static bool ParseArgs(string argsIn, out int[] argsOut)
+ {
+ if (string.IsNullOrEmpty(argsIn))
{
- throw e.Exception;
+ argsOut = [];
}
-
- private static bool ParseArgs(string argsIn, out int[] argsOut)
+ else
{
- if (string.IsNullOrEmpty(argsIn))
- {
- argsOut = [];
- }
- else
- {
- string[] args_str = argsIn.Split(' ');
- argsOut = new int[args_str.Length];
+ string[] args_str = argsIn.Split(' ');
+ argsOut = new int[args_str.Length];
- for (int i = 0; i < args_str.Length; i++)
+ for (int i = 0; i < args_str.Length; i++)
+ {
+ if (!int.TryParse(args_str[i], out argsOut[i]))
{
- if (!int.TryParse(args_str[i], out argsOut[i]))
- {
- return false;
- }
+ return false;
}
}
- return true;
}
+ return true;
}
}
diff --git a/YAMDCC.IPC/ConnectionFactory.cs b/YAMDCC.IPC/ConnectionFactory.cs
index 2338fd3..68f602e 100644
--- a/YAMDCC.IPC/ConnectionFactory.cs
+++ b/YAMDCC.IPC/ConnectionFactory.cs
@@ -1,16 +1,15 @@
using System.IO.Pipes;
-namespace YAMDCC.IPC
+namespace YAMDCC.IPC;
+
+internal static class ConnectionFactory
{
- internal static class ConnectionFactory
- {
- private static int _lastId;
+ private static int _lastId;
- internal static NamedPipeConnection CreateConnection(PipeStream pipeStream)
- where TRead : class
- where TWrite : class
- {
- return new NamedPipeConnection(++_lastId, $"Client {_lastId}", pipeStream);
- }
+ internal static NamedPipeConnection CreateConnection(PipeStream pipeStream)
+ where TRead : class
+ where TWrite : class
+ {
+ return new NamedPipeConnection(++_lastId, $"Client {_lastId}", pipeStream);
}
}
diff --git a/YAMDCC.IPC/Constants.cs b/YAMDCC.IPC/Constants.cs
index 847b2b9..7cac2af 100644
--- a/YAMDCC.IPC/Constants.cs
+++ b/YAMDCC.IPC/Constants.cs
@@ -1,10 +1,9 @@
using MessagePack;
-namespace YAMDCC.IPC
+namespace YAMDCC.IPC;
+
+internal static class Constants
{
- internal static class Constants
- {
- public static readonly MessagePackSerializerOptions SerializerOptions =
- MessagePackSerializerOptions.Standard.WithSecurity(MessagePackSecurity.TrustedData);
- }
+ public static readonly MessagePackSerializerOptions SerializerOptions =
+ MessagePackSerializerOptions.Standard.WithSecurity(MessagePackSecurity.TrustedData);
}
diff --git a/YAMDCC.IPC/IO/PipeStreamReader.cs b/YAMDCC.IPC/IO/PipeStreamReader.cs
index ac2d624..021e1df 100644
--- a/YAMDCC.IPC/IO/PipeStreamReader.cs
+++ b/YAMDCC.IPC/IO/PipeStreamReader.cs
@@ -4,87 +4,86 @@
using System.IO.Pipes;
using System.Net;
-namespace YAMDCC.IPC.IO
+namespace YAMDCC.IPC.IO;
+
+///
+/// Wraps a object and reads from it.
+///
+///
+/// Deserializes binary data sent by a
+/// into a .NET CLR object specified by .
+///
+///
+/// The reference type to deserialize data to.
+///
+internal sealed class PipeStreamReader where T : class
{
///
- /// Wraps a object and reads from it.
+ /// Gets the underlying object.
///
- ///
- /// Deserializes binary data sent by a
- /// into a .NET CLR object specified by .
- ///
- ///
- /// The reference type to deserialize data to.
- ///
- internal sealed class PipeStreamReader where T : class
- {
- ///
- /// Gets the underlying object.
- ///
- internal PipeStream BaseStream { get; private set; }
+ internal PipeStream BaseStream { get; private set; }
- ///
- /// Gets a value indicating whether the pipe is connected or not.
- ///
- internal bool IsConnected => BaseStream.IsConnected;
+ ///
+ /// Gets a value indicating whether the pipe is connected or not.
+ ///
+ internal bool IsConnected => BaseStream.IsConnected;
- private const int SIZE_INT = sizeof(int);
+ private const int SIZE_INT = sizeof(int);
- ///
- /// Constructs a new object
- /// that reads data from the given .
- ///
- ///
- /// The pipe stream to read from.
- ///
- internal PipeStreamReader(PipeStream stream)
- {
- BaseStream = stream;
- }
+ ///
+ /// Constructs a new object
+ /// that reads data from the given .
+ ///
+ ///
+ /// The pipe stream to read from.
+ ///
+ internal PipeStreamReader(PipeStream stream)
+ {
+ BaseStream = stream;
+ }
- ///
- /// Reads the next object from the pipe.
- ///
- ///
- /// This method blocks until an object is
- /// sent or the pipe is disconnected.
- ///
- ///
- /// The next object read from the pipe, or
- /// null if the pipe disconnected.
- ///
- ///
- internal T ReadObject()
- {
- int len = ReadLength();
- return len == 0 ? default : ReadObject(len);
- }
+ ///
+ /// Reads the next object from the pipe.
+ ///
+ ///
+ /// This method blocks until an object is
+ /// sent or the pipe is disconnected.
+ ///
+ ///
+ /// The next object read from the pipe, or
+ /// null if the pipe disconnected.
+ ///
+ ///
+ internal T ReadObject()
+ {
+ int len = ReadLength();
+ return len == 0 ? default : ReadObject(len);
+ }
- ///
- /// Reads the length of the next message (in bytes) from the client.
- ///
- /// Number of bytes of data the client will be sending.
- ///
- ///
- private int ReadLength()
- {
- byte[] lenbuf = new byte[SIZE_INT];
- int bytesRead = BaseStream.Read(lenbuf, 0, SIZE_INT);
- return bytesRead == 0
- ? 0
- : bytesRead != SIZE_INT
- ? throw new IOException($"Expected {SIZE_INT} bytes, but read {bytesRead}.")
- : IPAddress.NetworkToHostOrder(BitConverter.ToInt32(lenbuf, 0));
- }
+ ///
+ /// Reads the length of the next message (in bytes) from the client.
+ ///
+ /// Number of bytes of data the client will be sending.
+ ///
+ ///
+ private int ReadLength()
+ {
+ byte[] lenbuf = new byte[SIZE_INT];
+ int bytesRead = BaseStream.Read(lenbuf, 0, SIZE_INT);
+ return bytesRead == 0
+ ? 0
+ : bytesRead != SIZE_INT
+ ? throw new IOException($"Expected {SIZE_INT} bytes, but read {bytesRead}.")
+ : IPAddress.NetworkToHostOrder(BitConverter.ToInt32(lenbuf, 0));
+ }
- ///
- private T ReadObject(int len)
- {
- byte[] data = new byte[len];
- int bytesRead = BaseStream.Read(data, 0, data.Length);
- return bytesRead == len
- ? MessagePackSerializer.Deserialize(data, Constants.SerializerOptions)
- : throw new IOException($"Expected {len} bytes, but read {bytesRead}.");
- }
+ ///
+ private T ReadObject(int len)
+ {
+ byte[] data = new byte[len];
+ int bytesRead = BaseStream.Read(data, 0, data.Length);
+ return bytesRead == len
+ ? MessagePackSerializer.Deserialize(data, Constants.SerializerOptions)
+ : throw new IOException($"Expected {len} bytes, but read {bytesRead}.");
}
}
diff --git a/YAMDCC.IPC/IO/PipeStreamWrapper.cs b/YAMDCC.IPC/IO/PipeStreamWrapper.cs
index a6e822e..aa54218 100644
--- a/YAMDCC.IPC/IO/PipeStreamWrapper.cs
+++ b/YAMDCC.IPC/IO/PipeStreamWrapper.cs
@@ -2,151 +2,150 @@
using System.IO;
using System.IO.Pipes;
-namespace YAMDCC.IPC.IO
+namespace YAMDCC.IPC.IO;
+
+///
+/// Wraps a object
+/// to read and write .NET CLR objects.
+///
+///
+/// The reference type to read from and write to the pipe.
+///
+internal sealed class PipeStreamWrapper : PipeStreamWrapper
+ where TReadWrite : class
{
///
- /// Wraps a object
- /// to read and write .NET CLR objects.
+ /// Constructs a new object
+ /// that reads from and writes to the given .
///
- ///
- /// The reference type to read from and write to the pipe.
- ///
- internal sealed class PipeStreamWrapper : PipeStreamWrapper
- where TReadWrite : class
- {
- ///
- /// Constructs a new object
- /// that reads from and writes to the given .
- ///
- ///
- /// The pipe stream to read from and write to.
- ///
- public PipeStreamWrapper(PipeStream stream)
- : base(stream) { }
- }
+ ///
+ /// The pipe stream to read from and write to.
+ ///
+ public PipeStreamWrapper(PipeStream stream)
+ : base(stream) { }
+}
+///
+/// Wraps a object
+/// to read and write .NET CLR objects.
+///
+///
+/// The reference type to read from the pipe.
+///
+///
+/// The reference type to write to the pipe.
+///
+internal class PipeStreamWrapper
+ where TRead : class
+ where TWrite : class
+{
///
- /// Wraps a object
- /// to read and write .NET CLR objects.
+ /// Gets the underlying object.
///
- ///
- /// The reference type to read from the pipe.
- ///
- ///
- /// The reference type to write to the pipe.
- ///
- internal class PipeStreamWrapper
- where TRead : class
- where TWrite : class
- {
- ///
- /// Gets the underlying object.
- ///
- internal PipeStream BaseStream { get; private set; }
+ internal PipeStream BaseStream { get; private set; }
- ///
- /// Gets a value indicating whether the
- /// object is connected or not.
- ///
- ///
- /// true if the
- /// object is connected, otherwise false.
- ///
- internal bool IsConnected => BaseStream.IsConnected && _reader.IsConnected;
+ ///
+ /// Gets a value indicating whether the
+ /// object is connected or not.
+ ///
+ ///
+ /// true if the
+ /// object is connected, otherwise false.
+ ///
+ internal bool IsConnected => BaseStream.IsConnected && _reader.IsConnected;
- ///
- /// Gets a value indicating whether the
- /// current stream supports read operations.
- ///
- ///
- /// true if the stream supports read
- /// operations, otherwise false.
- ///
- internal bool CanRead => BaseStream.CanRead;
+ ///
+ /// Gets a value indicating whether the
+ /// current stream supports read operations.
+ ///
+ ///
+ /// true if the stream supports read
+ /// operations, otherwise false.
+ ///
+ internal bool CanRead => BaseStream.CanRead;
- ///
- /// Gets a value indicating whether the current
- /// stream supports write operations.
- ///
- ///
- /// true if the stream supports write
- /// operation, otherwise false.
- ///
- internal bool CanWrite => BaseStream.CanWrite;
+ ///
+ /// Gets a value indicating whether the current
+ /// stream supports write operations.
+ ///
+ ///
+ /// true if the stream supports write
+ /// operation, otherwise false.
+ ///
+ internal bool CanWrite => BaseStream.CanWrite;
- private readonly PipeStreamReader _reader;
- private readonly PipeStreamWriter _writer;
+ private readonly PipeStreamReader _reader;
+ private readonly PipeStreamWriter _writer;
- ///
- /// Constructs a new
- /// object that reads from and writes to the given
- /// .
- ///
- ///
- /// The stream to read from and write to.
- ///
- internal PipeStreamWrapper(PipeStream stream)
- {
- BaseStream = stream;
- _reader = new PipeStreamReader(BaseStream);
- _writer = new PipeStreamWriter(BaseStream);
- }
+ ///
+ /// Constructs a new
+ /// object that reads from and writes to the given
+ /// .
+ ///
+ ///
+ /// The stream to read from and write to.
+ ///
+ internal PipeStreamWrapper(PipeStream stream)
+ {
+ BaseStream = stream;
+ _reader = new PipeStreamReader(BaseStream);
+ _writer = new PipeStreamWriter(BaseStream);
+ }
- ///
- /// Reads the next object from the pipe.
- ///
- ///
- /// This method blocks until an object
- /// is sent or the pipe is disconnected.
- ///
- ///
- /// The next object read from the pipe, or
- /// null if the pipe disconnected.
- ///
- internal TRead ReadObject()
- {
- return _reader.ReadObject();
- }
+ ///
+ /// Reads the next object from the pipe.
+ ///
+ ///
+ /// This method blocks until an object
+ /// is sent or the pipe is disconnected.
+ ///
+ ///
+ /// The next object read from the pipe, or
+ /// null if the pipe disconnected.
+ ///
+ internal TRead ReadObject()
+ {
+ return _reader.ReadObject();
+ }
- ///
- /// Writes an object to the pipe.
- ///
- ///
- /// This method blocks until all data is sent.
- ///
- ///
- /// Tne object to write to the pipe.
- ///
- internal void WriteObject(TWrite obj)
- {
- _writer.WriteObject(obj);
- }
+ ///
+ /// Writes an object to the pipe.
+ ///
+ ///
+ /// This method blocks until all data is sent.
+ ///
+ ///
+ /// Tne object to write to the pipe.
+ ///
+ internal void WriteObject(TWrite obj)
+ {
+ _writer.WriteObject(obj);
+ }
- ///
- /// Waits for the other end of the pipe to read all sent bytes.
- ///
- ///
- /// The pipe is closed.
- ///
- ///
- /// The pipe does not support write operations.
- ///
- ///
- /// The pipe is broken or another I/O error occurred.
- ///
- internal void WaitForPipeDrain()
- {
- _writer.WaitForPipeDrain();
- }
+ ///
+ /// Waits for the other end of the pipe to read all sent bytes.
+ ///
+ ///
+ /// The pipe is closed.
+ ///
+ ///
+ /// The pipe does not support write operations.
+ ///
+ ///
+ /// The pipe is broken or another I/O error occurred.
+ ///
+ internal void WaitForPipeDrain()
+ {
+ _writer.WaitForPipeDrain();
+ }
- ///
- /// Closes the current stream and releases any
- /// resources (such as sockets and file handles)
- /// associated with the current stream.
- ///
- internal void Close()
- {
- BaseStream.Close();
- }
+ ///
+ /// Closes the current stream and releases any
+ /// resources (such as sockets and file handles)
+ /// associated with the current stream.
+ ///
+ internal void Close()
+ {
+ BaseStream.Close();
}
}
diff --git a/YAMDCC.IPC/IO/PipeStreamWriter.cs b/YAMDCC.IPC/IO/PipeStreamWriter.cs
index 1a02469..9af56a2 100644
--- a/YAMDCC.IPC/IO/PipeStreamWriter.cs
+++ b/YAMDCC.IPC/IO/PipeStreamWriter.cs
@@ -3,65 +3,64 @@
using System.IO.Pipes;
using System.Net;
-namespace YAMDCC.IPC.IO
+namespace YAMDCC.IPC.IO;
+
+///
+/// Wraps a object and writes to it.
+///
+///
+/// Serializes .NET CLR objects specified by
+/// into binary form and sends them over the named pipe for a
+/// to read and deserialize.
+///
+///
+/// The reference type to serialize.
+///
+internal sealed class PipeStreamWriter where T : class
{
///
- /// Wraps a object and writes to it.
+ /// Gets the underlying object.
+ ///
+ internal PipeStream BaseStream { get; private set; }
+
+ ///
+ /// Constructs a new
+ /// object that writes to given .
+ ///
+ ///
+ /// The named pipe to write to.
+ ///
+ internal PipeStreamWriter(PipeStream stream)
+ {
+ BaseStream = stream;
+ }
+
+ ///
+ /// Writes an object to the pipe.
///
///
- /// Serializes .NET CLR objects specified by
- /// into binary form and sends them over the named pipe for a
- /// to read and deserialize.
+ /// This method blocks until all data is sent.
///
- ///
- /// The reference type to serialize.
- ///
- internal sealed class PipeStreamWriter where T : class
+ ///
+ /// The object to write to the pipe.
+ ///
+ ///
+ internal void WriteObject(T obj)
{
- ///
- /// Gets the underlying object.
- ///
- internal PipeStream BaseStream { get; private set; }
-
- ///
- /// Constructs a new
- /// object that writes to given .
- ///
- ///
- /// The named pipe to write to.
- ///
- internal PipeStreamWriter(PipeStream stream)
- {
- BaseStream = stream;
- }
-
- ///
- /// Writes an object to the pipe.
- ///
- ///
- /// This method blocks until all data is sent.
- ///
- ///
- /// The object to write to the pipe.
- ///
- ///
- internal void WriteObject(T obj)
+ if (obj is not null)
{
- if (obj is not null)
- {
- byte[] data = MessagePackSerializer.Serialize(obj, Constants.SerializerOptions);
- byte[] lenBuf = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(data.Length));
+ byte[] data = MessagePackSerializer.Serialize(obj, Constants.SerializerOptions);
+ byte[] lenBuf = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(data.Length));
- BaseStream.Write(lenBuf, 0, lenBuf.Length);
- BaseStream.Write(data, 0, data.Length);
- BaseStream.Flush();
- }
+ BaseStream.Write(lenBuf, 0, lenBuf.Length);
+ BaseStream.Write(data, 0, data.Length);
+ BaseStream.Flush();
}
+ }
- ///
- internal void WaitForPipeDrain()
- {
- BaseStream.WaitForPipeDrain();
- }
+ ///
+ internal void WaitForPipeDrain()
+ {
+ BaseStream.WaitForPipeDrain();
}
}
diff --git a/YAMDCC.IPC/NamedPipeClient.cs b/YAMDCC.IPC/NamedPipeClient.cs
index 79dd535..15a95fa 100644
--- a/YAMDCC.IPC/NamedPipeClient.cs
+++ b/YAMDCC.IPC/NamedPipeClient.cs
@@ -4,313 +4,312 @@
using YAMDCC.IPC.IO;
using YAMDCC.IPC.Threading;
-namespace YAMDCC.IPC
+namespace YAMDCC.IPC;
+
+///
+/// Wraps a .
+///
+///
+/// The reference type to read from and write to the named pipe.
+///
+public class NamedPipeClient : NamedPipeClient
+ where TReadWrite : class
{
///
- /// Wraps a .
+ /// Constructs a new to
+ /// connect to the specified
+ /// by .
///
- ///
- /// The reference type to read from and write to the named pipe.
- ///
- public class NamedPipeClient : NamedPipeClient
- where TReadWrite : class
+ ///
+ /// The name of the named pipe server.
+ ///
+ public NamedPipeClient(string pipeName) : base(pipeName) { }
+}
+
+///
+/// Wraps a .
+///
+///
+/// The reference type to read from the named pipe.
+///
+///
+/// The reference type to write to the named pipe.
+///
+public class NamedPipeClient : IDisposable
+ where TRead : class
+ where TWrite : class
+{
+ ///
+ /// Gets or sets whether the client should attempt to reconnect when
+ /// the pipe breaks due to an error or the other end terminating the
+ /// connection.
+ ///
+ ///
+ /// The default value is true.
+ ///
+ public bool AutoReconnect { get; set; } = true;
+
+ ///
+ /// Gets or sets how long the client
+ /// waits between a reconnection attempt.
+ ///
+ ///
+ /// The default value is 0.
+ ///
+ public int AutoReconnectDelay { get; set; }
+
+ ///
+ /// Invoked whenever a message is received from the server.
+ ///
+ public event EventHandler> ServerMessage;
+
+ ///
+ /// Invoked when the client connects to a server.
+ ///
+ public event EventHandler> Connected;
+
+ ///
+ /// Invoked when the client disconnects from the server
+ /// (e.g. when the pipe is closed or broken).
+ ///
+ public event EventHandler> Disconnected;
+
+ ///
+ /// Invoked whenever an exception is thrown during
+ /// a read or write operation on the named pipe.
+ ///
+ public event EventHandler> Error;
+
+ private readonly string _pipeName;
+ private NamedPipeConnection _connection;
+
+ private readonly AutoResetEvent _connected = new(false);
+ private readonly AutoResetEvent _disconnected = new(false);
+
+ private volatile bool _closedExplicitly;
+
+ private bool _disposed;
+
+ ///
+ /// Constructs a new to
+ /// connect to the
+ /// specified by .
+ ///
+ ///
+ /// The name of the named pipe server.
+ ///
+ public NamedPipeClient(string pipeName)
{
- ///
- /// Constructs a new to
- /// connect to the specified
- /// by .
- ///
- ///
- /// The name of the named pipe server.
- ///
- public NamedPipeClient(string pipeName) : base(pipeName) { }
+ _pipeName = pipeName;
+ AutoReconnect = true;
}
///
- /// Wraps a .
+ /// Connects to the named pipe server asynchronously.
///
- ///
- /// The reference type to read from the named pipe.
- ///
- ///
- /// The reference type to write to the named pipe.
- ///
- public class NamedPipeClient : IDisposable
- where TRead : class
- where TWrite : class
+ ///
+ /// This method returns immediately, possibly before the connection
+ /// has been established. Use to
+ /// wait until the connection to the server is established.
+ ///
+ public void Start()
{
- ///
- /// Gets or sets whether the client should attempt to reconnect when
- /// the pipe breaks due to an error or the other end terminating the
- /// connection.
- ///
- ///
- /// The default value is true.
- ///
- public bool AutoReconnect { get; set; } = true;
-
- ///
- /// Gets or sets how long the client
- /// waits between a reconnection attempt.
- ///
- ///
- /// The default value is 0.
- ///
- public int AutoReconnectDelay { get; set; }
-
- ///
- /// Invoked whenever a message is received from the server.
- ///
- public event EventHandler> ServerMessage;
-
- ///
- /// Invoked when the client connects to a server.
- ///
- public event EventHandler> Connected;
-
- ///
- /// Invoked when the client disconnects from the server
- /// (e.g. when the pipe is closed or broken).
- ///
- public event EventHandler> Disconnected;
-
- ///
- /// Invoked whenever an exception is thrown during
- /// a read or write operation on the named pipe.
- ///
- public event EventHandler> Error;
-
- private readonly string _pipeName;
- private NamedPipeConnection _connection;
-
- private readonly AutoResetEvent _connected = new(false);
- private readonly AutoResetEvent _disconnected = new(false);
-
- private volatile bool _closedExplicitly;
-
- private bool _disposed;
-
- ///
- /// Constructs a new to
- /// connect to the
- /// specified by .
- ///
- ///
- /// The name of the named pipe server.
- ///
- public NamedPipeClient(string pipeName)
- {
- _pipeName = pipeName;
- AutoReconnect = true;
- }
+ _closedExplicitly = false;
+ Worker worker = new();
+ worker.Error += WorkerOnError;
+ worker.DoWork(ListenSync);
+ }
- ///
- /// Connects to the named pipe server asynchronously.
- ///
- ///
- /// This method returns immediately, possibly before the connection
- /// has been established. Use to
- /// wait until the connection to the server is established.
- ///
- public void Start()
- {
- _closedExplicitly = false;
- Worker worker = new();
- worker.Error += WorkerOnError;
- worker.DoWork(ListenSync);
- }
+ ///
+ /// Closes the named pipe.
+ ///
+ public void Stop()
+ {
+ _closedExplicitly = true;
+ _connection?.Close();
+ }
- ///
- /// Closes the named pipe.
- ///
- public void Stop()
- {
- _closedExplicitly = true;
- _connection?.Close();
- }
+ ///
+ /// Sends a message to the server over a named pipe.
+ ///
+ ///
+ /// The message to send to the server.
+ ///
+ public void PushMessage(TWrite message)
+ {
+ _connection?.PushMessage(message);
+ }
- ///
- /// Sends a message to the server over a named pipe.
- ///
- ///
- /// The message to send to the server.
- ///
- public void PushMessage(TWrite message)
- {
- _connection?.PushMessage(message);
- }
+ #region Wait for connection/disconnection
- #region Wait for connection/disconnection
+ ///
+ /// Blocks the current thread until a connection
+ /// to the named pipe server is established.
+ ///
+ public bool WaitForConnection()
+ {
+ return _connected.WaitOne();
+ }
- ///
- /// Blocks the current thread until a connection
- /// to the named pipe server is established.
- ///
- public bool WaitForConnection()
- {
- return _connected.WaitOne();
- }
+ ///
+ /// Blocks the current thread until a connection to the
+ /// named pipe server is established, waiting until at
+ /// most before returning.
+ ///
+ ///
+ /// The timeout, in milliseconds, to wait for the server connection.
+ ///
+ ///
+ /// true if the server connection was established
+ /// before the timeout, otherwise false.
+ ///
+ public bool WaitForConnection(int timeout)
+ {
+ return _connected.WaitOne(timeout);
+ }
- ///
- /// Blocks the current thread until a connection to the
- /// named pipe server is established, waiting until at
- /// most before returning.
- ///
- ///
- /// The timeout, in milliseconds, to wait for the server connection.
- ///
- ///
- /// true if the server connection was established
- /// before the timeout, otherwise false.
- ///
- public bool WaitForConnection(int timeout)
- {
- return _connected.WaitOne(timeout);
- }
+ ///
+ /// Blocks the current thread until a connection to the
+ /// named pipe server is established, waiting until at
+ /// most before returning.
+ ///
+ ///
+ /// A representing the time
+ /// (in milliseconds) to wait for the server connection.
+ ///
+ ///
+ /// true if the server connection was established
+ /// before the timeout, otherwise false.
+ ///
+ public bool WaitForConnection(TimeSpan timeout)
+ {
+ return _connected.WaitOne(timeout);
+ }
- ///
- /// Blocks the current thread until a connection to the
- /// named pipe server is established, waiting until at
- /// most before returning.
- ///
- ///
- /// A representing the time
- /// (in milliseconds) to wait for the server connection.
- ///
- ///
- /// true if the server connection was established
- /// before the timeout, otherwise false.
- ///
- public bool WaitForConnection(TimeSpan timeout)
- {
- return _connected.WaitOne(timeout);
- }
+ ///
+ /// Blocks the current thread until the client
+ /// disconnects from the named pipe server.
+ ///
+ public bool WaitForDisconnection()
+ {
+ return _disconnected.WaitOne();
+ }
- ///
- /// Blocks the current thread until the client
- /// disconnects from the named pipe server.
- ///
- public bool WaitForDisconnection()
- {
- return _disconnected.WaitOne();
- }
+ ///
+ /// Blocks the current thread until the client disconnects
+ /// from the named pipe server, waiting until at most
+ /// before returning.
+ ///
+ ///
+ /// The timeout, in milliseconds, to wait for the server to disconnect.
+ ///
+ ///
+ /// true if the client disconnected
+ /// before the timeout, otherwise false.
+ ///
+ public bool WaitForDisconnection(int timeout)
+ {
+ return _disconnected.WaitOne(timeout);
+ }
- ///
- /// Blocks the current thread until the client disconnects
- /// from the named pipe server, waiting until at most
- /// before returning.
- ///
- ///
- /// The timeout, in milliseconds, to wait for the server to disconnect.
- ///
- ///
- /// true if the client disconnected
- /// before the timeout, otherwise false.
- ///
- public bool WaitForDisconnection(int timeout)
- {
- return _disconnected.WaitOne(timeout);
- }
+ ///
+ /// Blocks the current thread until the client disconnects
+ /// from the named pipe server, waiting until at most
+ /// before returning.
+ ///
+ ///
+ /// A representing the time
+ /// (in milliseconds) to wait for the server to disconnect.
+ ///
+ ///
+ /// true if the client disconnected
+ /// before the timeout, otherwise false.
+ ///
+ public bool WaitForDisconnection(TimeSpan timeout)
+ {
+ return _disconnected.WaitOne(timeout);
+ }
- ///
- /// Blocks the current thread until the client disconnects
- /// from the named pipe server, waiting until at most
- /// before returning.
- ///
- ///
- /// A representing the time
- /// (in milliseconds) to wait for the server to disconnect.
- ///
- ///
- /// true if the client disconnected
- /// before the timeout, otherwise false.
- ///
- public bool WaitForDisconnection(TimeSpan timeout)
- {
- return _disconnected.WaitOne(timeout);
- }
+ #endregion
+
+ #region Private methods
+ private void ListenSync()
+ {
+ // Get the name of the data pipe that should be used from now on by this NamedPipeClient
+ PipeStreamWrapper handshake = PipeClientFactory.Connect(_pipeName);
+ string dataPipeName = handshake.ReadObject();
+ handshake.Close();
+
+ // Connect to the actual data pipe
+ NamedPipeClientStream dataPipe = PipeClientFactory.CreateAndConnectPipe(dataPipeName);
+
+ // Create a Connection object for the data pipe
+ _connection = ConnectionFactory.CreateConnection(dataPipe);
+ _connection.Disconnected += OnDisconnected;
+ _connection.ReceiveMessage += OnReceiveMessage;
+ _connection.Error += ConnectionOnError;
+ _connection.Open();
+
+ _connected.Set();
+ Connected?.Invoke(this, new PipeConnectionEventArgs(_connection));
+ }
+
+ private void OnDisconnected(object sender, PipeConnectionEventArgs e)
+ {
+ Disconnected?.Invoke(sender, e);
- #endregion
+ _disconnected.Set();
- #region Private methods
- private void ListenSync()
+ // Reconnect
+ if (AutoReconnect && !_closedExplicitly)
{
- // Get the name of the data pipe that should be used from now on by this NamedPipeClient
- PipeStreamWrapper handshake = PipeClientFactory.Connect(_pipeName);
- string dataPipeName = handshake.ReadObject();
- handshake.Close();
-
- // Connect to the actual data pipe
- NamedPipeClientStream dataPipe = PipeClientFactory.CreateAndConnectPipe(dataPipeName);
-
- // Create a Connection object for the data pipe
- _connection = ConnectionFactory.CreateConnection(dataPipe);
- _connection.Disconnected += OnDisconnected;
- _connection.ReceiveMessage += OnReceiveMessage;
- _connection.Error += ConnectionOnError;
- _connection.Open();
-
- _connected.Set();
- Connected?.Invoke(this, new PipeConnectionEventArgs(_connection));
+ Thread.Sleep(AutoReconnectDelay);
+ Start();
}
+ }
- private void OnDisconnected(object sender, PipeConnectionEventArgs e)
- {
- Disconnected?.Invoke(sender, e);
+ private void OnReceiveMessage(object sender, PipeMessageEventArgs e)
+ {
+ ServerMessage?.Invoke(sender, e);
+ }
- _disconnected.Set();
+ ///
+ /// Invoked on the UI thread.
+ ///
+ private void ConnectionOnError(object sender, PipeErrorEventArgs e)
+ {
+ Error?.Invoke(sender, e);
+ }
- // Reconnect
- if (AutoReconnect && !_closedExplicitly)
- {
- Thread.Sleep(AutoReconnectDelay);
- Start();
- }
- }
- private void OnReceiveMessage(object sender, PipeMessageEventArgs e)
- {
- ServerMessage?.Invoke(sender, e);
- }
-
- ///
- /// Invoked on the UI thread.
- ///
- private void ConnectionOnError(object sender, PipeErrorEventArgs e)
- {
- Error?.Invoke(sender, e);
- }
+ ///
+ /// Invoked on the UI thread.
+ ///
+ private void WorkerOnError(object sender, WorkerErrorEventArgs e)
+ {
+ Error?.Invoke(sender, new PipeErrorEventArgs(_connection, e.Exception));
+ }
+ #endregion
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
- ///
- /// Invoked on the UI thread.
- ///
- private void WorkerOnError(object sender, WorkerErrorEventArgs e)
+ private void Dispose(bool disposing)
+ {
+ if (_disposed)
{
- Error?.Invoke(sender, new PipeErrorEventArgs(_connection, e.Exception));
+ return;
}
- #endregion
- public void Dispose()
+ if (disposing)
{
- Dispose(true);
- GC.SuppressFinalize(this);
+ _connected.Dispose();
+ _disconnected.Dispose();
}
- private void Dispose(bool disposing)
- {
- if (_disposed)
- {
- return;
- }
-
- if (disposing)
- {
- _connected.Dispose();
- _disconnected.Dispose();
- }
-
- _disposed = true;
- }
+ _disposed = true;
}
}
diff --git a/YAMDCC.IPC/NamedPipeConnection.cs b/YAMDCC.IPC/NamedPipeConnection.cs
index dd5d3c6..20733f4 100644
--- a/YAMDCC.IPC/NamedPipeConnection.cs
+++ b/YAMDCC.IPC/NamedPipeConnection.cs
@@ -6,211 +6,210 @@
using YAMDCC.IPC.IO;
using YAMDCC.IPC.Threading;
-namespace YAMDCC.IPC
+namespace YAMDCC.IPC;
+
+///
+/// Represents a connection between a named pipe client and server.
+///
+///
+/// The reference type to read from the named pipe.
+///
+///
+/// The reference type to write to the named pipe.
+///
+public class NamedPipeConnection : IDisposable
+ where TRead : class
+ where TWrite : class
{
///
- /// Represents a connection between a named pipe client and server.
+ /// Gets the connection's unique identifier.
///
- ///
- /// The reference type to read from the named pipe.
- ///
- ///
- /// The reference type to write to the named pipe.
- ///
- public class NamedPipeConnection : IDisposable
- where TRead : class
- where TWrite : class
- {
- ///
- /// Gets the connection's unique identifier.
- ///
- public int ID { get; }
+ public int ID { get; }
- ///
- /// Gets the connection's name.
- ///
- public string Name { get; }
+ ///
+ /// Gets the connection's name.
+ ///
+ public string Name { get; }
- ///
- /// Gets the connection's handle.
- ///
- public SafeHandle Handle => _streamWrapper.BaseStream.SafePipeHandle;
+ ///
+ /// Gets the connection's handle.
+ ///
+ public SafeHandle Handle => _streamWrapper.BaseStream.SafePipeHandle;
- ///
- /// Gets a value indicating whether the pipe is connected or not.
- ///
- public bool IsConnected => _streamWrapper.IsConnected;
+ ///
+ /// Gets a value indicating whether the pipe is connected or not.
+ ///
+ public bool IsConnected => _streamWrapper.IsConnected;
- ///
- /// Invoked when the named pipe connection terminates.
- ///
- public event EventHandler> Disconnected;
+ ///
+ /// Invoked when the named pipe connection terminates.
+ ///
+ public event EventHandler> Disconnected;
- ///
- /// Invoked whenever a message is received from the other end of the pipe.
- ///
- public event EventHandler> ReceiveMessage;
+ ///
+ /// Invoked whenever a message is received from the other end of the pipe.
+ ///
+ public event EventHandler> ReceiveMessage;
- ///
- /// Invoked when an exception is thrown during any read/write operation over the named pipe.
- ///
- public event EventHandler> Error;
+ ///
+ /// Invoked when an exception is thrown during any read/write operation over the named pipe.
+ ///
+ public event EventHandler> Error;
- private readonly PipeStreamWrapper _streamWrapper;
+ private readonly PipeStreamWrapper _streamWrapper;
- private readonly AutoResetEvent _writeSignal = new(false);
- private readonly BlockingCollection _writeQueue = new();
+ private readonly AutoResetEvent _writeSignal = new(false);
+ private readonly BlockingCollection _writeQueue = [];
- private bool _notifiedSucceeded;
+ private bool _notifiedSucceeded;
- private bool _disposed;
+ private bool _disposed;
- internal NamedPipeConnection(int id, string name, PipeStream serverStream)
- {
- ID = id;
- Name = name;
- _streamWrapper = new PipeStreamWrapper(serverStream);
- }
+ internal NamedPipeConnection(int id, string name, PipeStream serverStream)
+ {
+ ID = id;
+ Name = name;
+ _streamWrapper = new PipeStreamWrapper(serverStream);
+ }
- ///
- /// Adds the specified message to the write queue.
- ///
- ///
- /// The message will be written to the named pipe by the
- /// background thread at the next available opportunity.
- ///
- ///
- /// The message to write to the named pipe.
- ///
- public bool PushMessage(TWrite message)
+ ///
+ /// Adds the specified message to the write queue.
+ ///
+ ///
+ /// The message will be written to the named pipe by the
+ /// background thread at the next available opportunity.
+ ///
+ ///
+ /// The message to write to the named pipe.
+ ///
+ public bool PushMessage(TWrite message)
+ {
+ try
{
- try
- {
- return _writeQueue.TryAdd(message) && _writeSignal.Set();
- }
- // catch the exception that occurs when trying to add an item to
- // the write queue when the named pipe connection has been stopped
- catch (InvalidOperationException)
- {
- return false;
- }
+ return _writeQueue.TryAdd(message) && _writeSignal.Set();
}
-
- ///
- /// Begins reading from and writing to the
- /// named pipe on a background thread.
- ///
- ///
- /// This method returns immediately.
- ///
- internal void Open()
+ // catch the exception that occurs when trying to add an item to
+ // the write queue when the named pipe connection has been stopped
+ catch (InvalidOperationException)
{
- Worker readWorker = new();
- readWorker.Succeeded += OnSucceeded;
- readWorker.Error += OnError;
- readWorker.DoWork(ReadPipe);
-
- Worker writeWorker = new();
- writeWorker.Succeeded += OnSucceeded;
- writeWorker.Error += OnError;
- writeWorker.DoWork(WritePipe);
+ return false;
}
+ }
- ///
- /// Closes the named pipe connection and
- /// underlying .
- ///
- ///
- /// Invoked on the background thread.
- ///
- internal void Close()
- {
- _streamWrapper.Close();
- _writeQueue.CompleteAdding();
- _writeSignal.Set();
- }
+ ///
+ /// Begins reading from and writing to the
+ /// named pipe on a background thread.
+ ///
+ ///
+ /// This method returns immediately.
+ ///
+ internal void Open()
+ {
+ Worker readWorker = new();
+ readWorker.Succeeded += OnSucceeded;
+ readWorker.Error += OnError;
+ readWorker.DoWork(ReadPipe);
+
+ Worker writeWorker = new();
+ writeWorker.Succeeded += OnSucceeded;
+ writeWorker.Error += OnError;
+ writeWorker.DoWork(WritePipe);
+ }
- ///
- /// Invoked on the UI thread.
- ///
- private void OnSucceeded(object sender, EventArgs e)
+ ///
+ /// Closes the named pipe connection and
+ /// underlying .
+ ///
+ ///
+ /// Invoked on the background thread.
+ ///
+ internal void Close()
+ {
+ _streamWrapper.Close();
+ _writeQueue.CompleteAdding();
+ _writeSignal.Set();
+ }
+
+ ///
+ /// Invoked on the UI thread.
+ ///
+ private void OnSucceeded(object sender, EventArgs e)
+ {
+ // Only notify observers once
+ if (_notifiedSucceeded)
{
- // Only notify observers once
- if (_notifiedSucceeded)
- {
- return;
- }
+ return;
+ }
- _notifiedSucceeded = true;
+ _notifiedSucceeded = true;
- PipeConnectionEventArgs e2 = new(this);
- Disconnected?.Invoke(sender, e2);
- }
+ PipeConnectionEventArgs e2 = new(this);
+ Disconnected?.Invoke(sender, e2);
+ }
- ///
- /// Invoked on the UI thread.
- ///
- private void OnError(object sender, WorkerErrorEventArgs e)
- {
- Error?.Invoke(sender, new PipeErrorEventArgs(this, e.Exception));
- }
+ ///
+ /// Invoked on the UI thread.
+ ///
+ private void OnError(object sender, WorkerErrorEventArgs e)
+ {
+ Error?.Invoke(sender, new PipeErrorEventArgs(this, e.Exception));
+ }
- ///
- /// Invoked on the background thread.
- ///
- private void ReadPipe()
+ ///
+ /// Invoked on the background thread.
+ ///
+ private void ReadPipe()
+ {
+ while (IsConnected && _streamWrapper.CanRead)
{
- while (IsConnected && _streamWrapper.CanRead)
+ TRead obj = _streamWrapper.ReadObject();
+ if (obj is null)
{
- TRead obj = _streamWrapper.ReadObject();
- if (obj is null)
- {
- Close();
- return;
- }
-
- ReceiveMessage?.Invoke(this,
- new PipeMessageEventArgs(this, obj));
+ Close();
+ return;
}
+
+ ReceiveMessage?.Invoke(this,
+ new PipeMessageEventArgs(this, obj));
}
+ }
- ///
- /// Invoked on the background thread.
- ///
- private void WritePipe()
+ ///
+ /// Invoked on the background thread.
+ ///
+ private void WritePipe()
+ {
+ while (IsConnected && _streamWrapper.CanWrite)
{
- while (IsConnected && _streamWrapper.CanWrite)
+ _writeSignal.WaitOne();
+ while (_writeQueue.TryTake(out TWrite obj) || _writeQueue.Count > 0)
{
- _writeSignal.WaitOne();
- while (_writeQueue.TryTake(out TWrite obj) || _writeQueue.Count > 0)
- {
- _streamWrapper.WriteObject(obj);
- _streamWrapper.WaitForPipeDrain();
- }
+ _streamWrapper.WriteObject(obj);
+ _streamWrapper.WaitForPipeDrain();
}
}
+ }
- public void Dispose()
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ if (_disposed)
{
- Dispose(true);
- GC.SuppressFinalize(this);
+ return;
}
- private void Dispose(bool disposing)
+ if (disposing)
{
- if (_disposed)
- {
- return;
- }
-
- if (disposing)
- {
- Close();
- _writeSignal.Dispose();
- _writeQueue.Dispose();
- }
-
- _disposed = true;
+ Close();
+ _writeSignal.Dispose();
+ _writeQueue.Dispose();
}
+
+ _disposed = true;
}
}
diff --git a/YAMDCC.IPC/NamedPipeServer.cs b/YAMDCC.IPC/NamedPipeServer.cs
index 0ab7977..ef74245 100644
--- a/YAMDCC.IPC/NamedPipeServer.cs
+++ b/YAMDCC.IPC/NamedPipeServer.cs
@@ -5,402 +5,401 @@
using YAMDCC.IPC.IO;
using YAMDCC.IPC.Threading;
-namespace YAMDCC.IPC
+namespace YAMDCC.IPC;
+
+///
+/// Wraps a and provides
+/// multiple simultaneous client connection handling.
+///
+///
+/// The reference type to read from and write to the named pipe.
+///
+public class NamedPipeServer : NamedPipeServer
+ where TReadWrite : class
{
///
- /// Wraps a and provides
- /// multiple simultaneous client connection handling.
+ /// Constructs a new
+ /// object that listens for client connections on the given
+ /// .
///
- ///
- /// The reference type to read from and write to the named pipe.
- ///
- public class NamedPipeServer : NamedPipeServer
- where TReadWrite : class
- {
- ///
- /// Constructs a new
- /// object that listens for client connections on the given
- /// .
- ///
- ///
- public NamedPipeServer(string pipeName)
- : base(pipeName) { }
-
- ///
- /// Constructs a new
- /// object that listens for client connections on the given
- /// .
- ///
- ///
- public NamedPipeServer(string pipeName, PipeSecurity security, int bufferSize = 0)
- : base(pipeName, security, bufferSize) { }
- }
+ ///
+ public NamedPipeServer(string pipeName)
+ : base(pipeName) { }
///
- /// Wraps a and provides
- /// multiple simultaneous client connection handling.
+ /// Constructs a new
+ /// object that listens for client connections on the given
+ /// .
///
- ///
- /// The reference type to read from the named pipe.
- ///
- ///
- /// The reference type to write to the named pipe.
- ///
- public class NamedPipeServer
- where TRead : class
- where TWrite : class
+ ///
+ public NamedPipeServer(string pipeName, PipeSecurity security, int bufferSize = 0)
+ : base(pipeName, security, bufferSize) { }
+}
+
+///
+/// Wraps a and provides
+/// multiple simultaneous client connection handling.
+///
+///
+/// The reference type to read from the named pipe.
+///
+///
+/// The reference type to write to the named pipe.
+///
+public class NamedPipeServer
+ where TRead : class
+ where TWrite : class
+{
+ ///
+ /// Invoked whenever a client connects to the server.
+ ///
+ public event EventHandler> ClientConnected;
+
+ ///
+ /// Invoked whenever a client disconnects from the server.
+ ///
+ public event EventHandler> ClientDisconnected;
+
+ ///
+ /// Invoked whenever a client sends a message to the server.
+ ///
+ public event EventHandler> ClientMessage;
+
+ ///
+ /// Invoked whenever an exception is thrown
+ /// during a read or write operation.
+ ///
+ public event EventHandler> Error;
+
+ private readonly string _pipeName;
+ private readonly int _bufferSize;
+ private readonly PipeSecurity _security;
+ private readonly List> _connections = [];
+
+ private int _nextPipeId;
+
+ private volatile bool _shouldKeepRunning;
+
+ ///
+ /// Constructs a new
+ /// object that listens for client connections on the given
+ /// .
+ ///
+ ///
+ /// The name of the pipe to listen on.
+ ///
+ public NamedPipeServer(string pipeName)
{
- ///
- /// Invoked whenever a client connects to the server.
- ///
- public event EventHandler> ClientConnected;
-
- ///
- /// Invoked whenever a client disconnects from the server.
- ///
- public event EventHandler> ClientDisconnected;
-
- ///
- /// Invoked whenever a client sends a message to the server.
- ///
- public event EventHandler> ClientMessage;
-
- ///
- /// Invoked whenever an exception is thrown
- /// during a read or write operation.
- ///
- public event EventHandler> Error;
-
- private readonly string _pipeName;
- private readonly int _bufferSize;
- private readonly PipeSecurity _security;
- private readonly List> _connections = [];
-
- private int _nextPipeId;
-
- private volatile bool _shouldKeepRunning;
-
- ///
- /// Constructs a new
- /// object that listens for client connections on the given
- /// .
- ///
- ///
- /// The name of the pipe to listen on.
- ///
- public NamedPipeServer(string pipeName)
- {
- _pipeName = pipeName;
- }
+ _pipeName = pipeName;
+ }
- ///
- /// An object that determine the access control
- /// and audit security for the pipe.
- ///
- ///
- /// The size of the input and output buffer.
- /// Use 0 for the default buffer size.
- ///
- ///
- public NamedPipeServer(string pipeName, PipeSecurity security, int bufferSize = 0)
- {
- _pipeName = pipeName;
- _security = security;
- _bufferSize = bufferSize;
- }
+ ///
+ /// An object that determine the access control
+ /// and audit security for the pipe.
+ ///
+ ///
+ /// The size of the input and output buffer.
+ /// Use 0 for the default buffer size.
+ ///
+ ///
+ public NamedPipeServer(string pipeName, PipeSecurity security, int bufferSize = 0)
+ {
+ _pipeName = pipeName;
+ _security = security;
+ _bufferSize = bufferSize;
+ }
- ///
- /// Begins listening for client connections
- /// in a separate background thread.
- ///
- ///
- /// This method returns immediately.
- ///
- public void Start()
- {
- _shouldKeepRunning = true;
- Worker worker = new();
- worker.Error += WorkerOnError;
- worker.DoWork(ListenSync);
- }
+ ///
+ /// Begins listening for client connections
+ /// in a separate background thread.
+ ///
+ ///
+ /// This method returns immediately.
+ ///
+ public void Start()
+ {
+ _shouldKeepRunning = true;
+ Worker worker = new();
+ worker.Error += WorkerOnError;
+ worker.DoWork(ListenSync);
+ }
- ///
- /// Sends a message to all connected clients asynchronously.
- ///
- ///
- /// This method returns immediately, possibly before
- /// the message has been sent to all clients.
- ///
- ///
- /// The message to send to the clients.
- ///
- public void PushMessage(TWrite message)
+ ///
+ /// Sends a message to all connected clients asynchronously.
+ ///
+ ///
+ /// This method returns immediately, possibly before
+ /// the message has been sent to all clients.
+ ///
+ ///
+ /// The message to send to the clients.
+ ///
+ public void PushMessage(TWrite message)
+ {
+ lock (_connections)
{
- lock (_connections)
+ foreach (NamedPipeConnection client in _connections)
{
- foreach (NamedPipeConnection client in _connections)
- {
- client.PushMessage(message);
- }
+ client.PushMessage(message);
}
}
+ }
- ///
- /// Sends a message to a specified client asynchronously.
- ///
- ///
- /// The message to send to the client.
- ///
- ///
- /// The client ID to send the message to.
- ///
- ///
- public void PushMessage(TWrite message, int targetId)
+ ///
+ /// Sends a message to a specified client asynchronously.
+ ///
+ ///
+ /// The message to send to the client.
+ ///
+ ///
+ /// The client ID to send the message to.
+ ///
+ ///
+ public void PushMessage(TWrite message, int targetId)
+ {
+ lock (_connections)
{
- lock (_connections)
+ // Can we speed this up with Linq or does that add overhead?
+ foreach (NamedPipeConnection client in _connections)
{
- // Can we speed this up with Linq or does that add overhead?
- foreach (NamedPipeConnection client in _connections)
+ if (client.ID == targetId)
{
- if (client.ID == targetId)
- {
- client.PushMessage(message);
- break;
- }
+ client.PushMessage(message);
+ break;
}
}
}
+ }
- ///
- /// Sends a message to the specified clients asynchronously.
- ///
- ///
- /// An array of client IDs to send the message to.
- ///
- ///
- public void PushMessage(TWrite message, int[] targetIds)
- {
- PushMessage(message, targetIds.ToList());
- }
+ ///
+ /// Sends a message to the specified clients asynchronously.
+ ///
+ ///
+ /// An array of client IDs to send the message to.
+ ///
+ ///
+ public void PushMessage(TWrite message, int[] targetIds)
+ {
+ PushMessage(message, targetIds.ToList());
+ }
- ///
- /// A list of client IDs to send the message to.
- ///
- ///
- public void PushMessage(TWrite message, List targetIds)
+ ///
+ /// A list of client IDs to send the message to.
+ ///
+ ///
+ public void PushMessage(TWrite message, List targetIds)
+ {
+ lock (_connections)
{
- lock (_connections)
+ // Can we speed this up with Linq or does that add overhead?
+ foreach (NamedPipeConnection client in _connections)
{
- // Can we speed this up with Linq or does that add overhead?
- foreach (NamedPipeConnection client in _connections)
+ if (targetIds.Contains(client.ID))
{
- if (targetIds.Contains(client.ID))
- {
- client.PushMessage(message);
- }
+ client.PushMessage(message);
}
}
}
+ }
- ///
- /// The client name to send the message to.
- ///
- ///
- public void PushMessage(TWrite message, string targetName)
+ ///
+ /// The client name to send the message to.
+ ///
+ ///
+ public void PushMessage(TWrite message, string targetName)
+ {
+ lock (_connections)
{
- lock (_connections)
+ // Can we speed this up with Linq or does that add overhead?
+ foreach (NamedPipeConnection client in _connections)
{
- // Can we speed this up with Linq or does that add overhead?
- foreach (NamedPipeConnection client in _connections)
+ if (client.Name == targetName)
{
- if (client.Name == targetName)
- {
- client.PushMessage(message);
- break;
- }
+ client.PushMessage(message);
+ break;
}
}
}
+ }
- ///
- /// A list of client names to send the message to.
- ///
- ///
- public void PushMessage(TWrite message, List targetNames)
+ ///
+ /// A list of client names to send the message to.
+ ///
+ ///
+ public void PushMessage(TWrite message, List targetNames)
+ {
+ lock (_connections)
{
- lock (_connections)
+ foreach (NamedPipeConnection client in _connections)
{
- foreach (NamedPipeConnection client in _connections)
+ if (targetNames.Contains(client.Name))
{
- if (targetNames.Contains(client.Name))
- {
- client.PushMessage(message);
- }
+ client.PushMessage(message);
}
}
}
+ }
- ///
- /// Closes all open client connections and stops listening for new ones.
- ///
- public void Stop()
- {
- _shouldKeepRunning = false;
+ ///
+ /// Closes all open client connections and stops listening for new ones.
+ ///
+ public void Stop()
+ {
+ _shouldKeepRunning = false;
- lock (_connections)
+ lock (_connections)
+ {
+ foreach (NamedPipeConnection client in _connections.ToArray())
{
- foreach (NamedPipeConnection client in _connections.ToArray())
- {
- client.Close();
- }
+ client.Close();
}
-
- // If background thread is still listening for a client to connect,
- // initiate a dummy connection that will allow the thread to exit.
- NamedPipeClient dummyClient = new(_pipeName);
- dummyClient.Start();
- dummyClient.WaitForConnection(TimeSpan.FromSeconds(2));
- dummyClient.Stop();
- dummyClient.WaitForDisconnection(TimeSpan.FromSeconds(2));
}
- #region Private methods
+ // If background thread is still listening for a client to connect,
+ // initiate a dummy connection that will allow the thread to exit.
+ NamedPipeClient dummyClient = new(_pipeName);
+ dummyClient.Start();
+ dummyClient.WaitForConnection(TimeSpan.FromSeconds(2));
+ dummyClient.Stop();
+ dummyClient.WaitForDisconnection(TimeSpan.FromSeconds(2));
+ }
- private void ListenSync()
+ #region Private methods
+
+ private void ListenSync()
+ {
+ while (_shouldKeepRunning)
{
- while (_shouldKeepRunning)
- {
- WaitForConnection();
- }
+ WaitForConnection();
}
+ }
- private void WaitForConnection()
- {
- NamedPipeServerStream handshakePipe = null;
- NamedPipeServerStream dataPipe = null;
- NamedPipeConnection connection = null;
+ private void WaitForConnection()
+ {
+ NamedPipeServerStream handshakePipe = null;
+ NamedPipeServerStream dataPipe = null;
+ NamedPipeConnection connection = null;
- string connectionPipeName = GetNextConnectionPipeName();
+ string connectionPipeName = GetNextConnectionPipeName();
- try
- {
- dataPipe = CreatePipe(connectionPipeName);
+ try
+ {
+ dataPipe = CreatePipe(connectionPipeName);
- // Send the client the name of the data pipe to use
- handshakePipe = CreateAndConnectPipe();
+ // Send the client the name of the data pipe to use
+ handshakePipe = CreateAndConnectPipe();
- PipeStreamWrapper handshakeWrapper = new(handshakePipe);
+ PipeStreamWrapper handshakeWrapper = new(handshakePipe);
- handshakeWrapper.WriteObject(connectionPipeName);
- handshakeWrapper.WaitForPipeDrain();
- handshakeWrapper.Close();
+ handshakeWrapper.WriteObject(connectionPipeName);
+ handshakeWrapper.WaitForPipeDrain();
+ handshakeWrapper.Close();
- // Wait for the client to connect to the data pipe
- dataPipe.WaitForConnection();
+ // Wait for the client to connect to the data pipe
+ dataPipe.WaitForConnection();
- // Add the client's connection to the list of connections
- connection = ConnectionFactory.CreateConnection(dataPipe);
- connection.ReceiveMessage += ClientOnReceiveMessage;
- connection.Disconnected += ClientOnDisconnected;
- connection.Error += ConnectionOnError;
- connection.Open();
+ // Add the client's connection to the list of connections
+ connection = ConnectionFactory.CreateConnection(dataPipe);
+ connection.ReceiveMessage += ClientOnReceiveMessage;
+ connection.Disconnected += ClientOnDisconnected;
+ connection.Error += ConnectionOnError;
+ connection.Open();
- lock (_connections) { _connections.Add(connection); }
+ lock (_connections) { _connections.Add(connection); }
- PipeConnectionEventArgs e = new(connection);
+ PipeConnectionEventArgs e = new(connection);
- ClientOnConnected(this, e);
- }
- // Catch the IOException that is raised if the pipe is broken or disconnected.
- catch (Exception ex)
- {
- Console.Error.WriteLine($"Named pipe is broken or disconnected: {ex}");
+ ClientOnConnected(this, e);
+ }
+ // Catch the IOException that is raised if the pipe is broken or disconnected.
+ catch (Exception ex)
+ {
+ Console.Error.WriteLine($"Named pipe is broken or disconnected: {ex}");
- Cleanup(handshakePipe);
- Cleanup(dataPipe);
+ Cleanup(handshakePipe);
+ Cleanup(dataPipe);
- PipeConnectionEventArgs e = new(connection);
+ PipeConnectionEventArgs e = new(connection);
- ClientOnDisconnected(this, e);
- }
+ ClientOnDisconnected(this, e);
}
+ }
- private NamedPipeServerStream CreateAndConnectPipe()
- {
- return _security == null
- ? PipeServerFactory.CreateAndConnectPipe(_pipeName)
- : PipeServerFactory.CreateAndConnectPipe(_pipeName, _bufferSize, _security);
- }
+ private NamedPipeServerStream CreateAndConnectPipe()
+ {
+ return _security == null
+ ? PipeServerFactory.CreateAndConnectPipe(_pipeName)
+ : PipeServerFactory.CreateAndConnectPipe(_pipeName, _bufferSize, _security);
+ }
- private NamedPipeServerStream CreatePipe(string connectionPipeName)
- {
- return _security == null
- ? PipeServerFactory.CreatePipe(connectionPipeName)
- : PipeServerFactory.CreatePipe(connectionPipeName, _bufferSize, _security);
- }
+ private NamedPipeServerStream CreatePipe(string connectionPipeName)
+ {
+ return _security == null
+ ? PipeServerFactory.CreatePipe(connectionPipeName)
+ : PipeServerFactory.CreatePipe(connectionPipeName, _bufferSize, _security);
+ }
- private void ClientOnConnected(object sender, PipeConnectionEventArgs e)
- {
- ClientConnected?.Invoke(sender, e);
- }
+ private void ClientOnConnected(object sender, PipeConnectionEventArgs e)
+ {
+ ClientConnected?.Invoke(sender, e);
+ }
- private void ClientOnReceiveMessage(object sender, PipeMessageEventArgs e)
+ private void ClientOnReceiveMessage(object sender, PipeMessageEventArgs e)
+ {
+ ClientMessage?.Invoke(sender, e);
+ }
+
+ private void ClientOnDisconnected(object sender, PipeConnectionEventArgs e)
+ {
+ if (e.Connection == null)
{
- ClientMessage?.Invoke(sender, e);
+ return;
}
- private void ClientOnDisconnected(object sender, PipeConnectionEventArgs e)
+ lock (_connections)
{
- if (e.Connection == null)
- {
- return;
- }
+ _connections.Remove(e.Connection);
+ }
- lock (_connections)
- {
- _connections.Remove(e.Connection);
- }
+ ClientDisconnected?.Invoke(sender, e);
+ }
- ClientDisconnected?.Invoke(sender, e);
- }
+ ///
+ /// Invoked on the UI thread.
+ ///
+ private void ConnectionOnError(object sender, PipeErrorEventArgs e)
+ {
+ Error?.Invoke(sender, e);
+ }
- ///
- /// Invoked on the UI thread.
- ///
- private void ConnectionOnError(object sender, PipeErrorEventArgs e)
- {
- Error?.Invoke(sender, e);
- }
+ ///
+ /// Invoked on the UI thread.
+ ///
+ ///
+ private void WorkerOnError(object sender, WorkerErrorEventArgs e)
+ {
+ PipeErrorEventArgs e2 = new(null, e.Exception);
+ Error?.Invoke(sender, e2);
+ }
- ///
- /// Invoked on the UI thread.
- ///
- ///
- private void WorkerOnError(object sender, WorkerErrorEventArgs e)
- {
- PipeErrorEventArgs e2 = new(null, e.Exception);
- Error?.Invoke(sender, e2);
- }
+ private string GetNextConnectionPipeName()
+ {
+ return $"{_pipeName}_{++_nextPipeId}";
+ }
- private string GetNextConnectionPipeName()
+ private static void Cleanup(NamedPipeServerStream pipe)
+ {
+ if (pipe is null)
{
- return $"{_pipeName}_{++_nextPipeId}";
+ return;
}
- private static void Cleanup(NamedPipeServerStream pipe)
+ using (NamedPipeServerStream x = pipe)
{
- if (pipe is null)
- {
- return;
- }
-
- using (NamedPipeServerStream x = pipe)
- {
- x.Close();
- }
+ x.Close();
}
-
- #endregion
}
+
+ #endregion
}
diff --git a/YAMDCC.IPC/PipeClientFactory.cs b/YAMDCC.IPC/PipeClientFactory.cs
index 9398021..4a6c30c 100644
--- a/YAMDCC.IPC/PipeClientFactory.cs
+++ b/YAMDCC.IPC/PipeClientFactory.cs
@@ -5,56 +5,55 @@
using System.Threading;
using YAMDCC.IPC.IO;
-namespace YAMDCC.IPC
+namespace YAMDCC.IPC;
+
+internal static class PipeClientFactory
{
- internal static class PipeClientFactory
+ internal static PipeStreamWrapper Connect(string pipeName)
+ where TRead : class
+ where TWrite : class
{
- internal static PipeStreamWrapper Connect(string pipeName)
- where TRead : class
- where TWrite : class
- {
- return new PipeStreamWrapper(CreateAndConnectPipe(pipeName));
- }
+ return new PipeStreamWrapper(CreateAndConnectPipe(pipeName));
+ }
- internal static NamedPipeClientStream CreateAndConnectPipe(string pipeName, int timeout = 10)
+ internal static NamedPipeClientStream CreateAndConnectPipe(string pipeName, int timeout = 10)
+ {
+ string normalizedPath = Path.GetFullPath($"\\\\.\\pipe\\{pipeName}");
+ while (!NamedPipeExists(normalizedPath))
{
- string normalizedPath = Path.GetFullPath($"\\\\.\\pipe\\{pipeName}");
- while (!NamedPipeExists(normalizedPath))
- {
- Thread.Sleep(timeout);
- }
- NamedPipeClientStream pipe = new(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous | PipeOptions.WriteThrough);
- pipe.Connect(1000);
- return pipe;
+ Thread.Sleep(timeout);
}
+ NamedPipeClientStream pipe = new(".", pipeName, PipeDirection.InOut, PipeOptions.Asynchronous | PipeOptions.WriteThrough);
+ pipe.Connect(1000);
+ return pipe;
+ }
- private static bool NamedPipeExists(string pipeName)
+ private static bool NamedPipeExists(string pipeName)
+ {
+ try
{
- try
+ bool exists = WaitNamedPipe(pipeName, -1);
+ if (!exists)
{
- bool exists = WaitNamedPipe(pipeName, -1);
- if (!exists)
+ int error = Marshal.GetLastWin32Error();
+ if (error is 0 or 2)
{
- int error = Marshal.GetLastWin32Error();
- if (error is 0 or 2)
- {
- return false;
- }
+ return false;
}
- return true;
- }
- catch (Exception)
- {
- return false;
}
+ return true;
+ }
+ catch (Exception)
+ {
+ return false;
}
-
- [DllImport("kernel32.dll",
- CharSet = CharSet.Unicode,
- EntryPoint = "WaitNamedPipeW",
- SetLastError = true)]
- [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static extern bool WaitNamedPipe(string name, int timeout);
}
+
+ [DllImport("kernel32.dll",
+ CharSet = CharSet.Unicode,
+ EntryPoint = "WaitNamedPipeW",
+ SetLastError = true)]
+ [DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool WaitNamedPipe(string name, int timeout);
}
diff --git a/YAMDCC.IPC/PipeConnectionEventArgs.cs b/YAMDCC.IPC/PipeConnectionEventArgs.cs
index cff3844..4c00eb9 100644
--- a/YAMDCC.IPC/PipeConnectionEventArgs.cs
+++ b/YAMDCC.IPC/PipeConnectionEventArgs.cs
@@ -1,38 +1,37 @@
using System;
-namespace YAMDCC.IPC
+namespace YAMDCC.IPC;
+
+///
+/// Provides data for the
+/// ,
+/// , and
+/// events.
+///
+///
+/// The reference type used when reading from the named pipe.
+///
+///
+/// The reference type used when writing to the named pipe.
+///
+public class PipeConnectionEventArgs : EventArgs
+ where TRead : class
+ where TWrite : class
{
///
- /// Provides data for the
- /// ,
- /// , and
- /// events.
+ /// The connection that caused the (dis)connection event.
///
- ///
- /// The reference type used when reading from the named pipe.
- ///
- ///
- /// The reference type used when writing to the named pipe.
- ///
- public class PipeConnectionEventArgs : EventArgs
- where TRead : class
- where TWrite : class
- {
- ///
- /// The connection that caused the (dis)connection event.
- ///
- public NamedPipeConnection Connection { get; }
+ public NamedPipeConnection Connection { get; }
- ///
- /// Initialises a new instance of the
- /// class.
- ///
- ///
- /// The connection that should be associated with the event.
- ///
- internal PipeConnectionEventArgs(NamedPipeConnection connection)
- {
- Connection = connection;
- }
+ ///
+ /// Initialises a new instance of the
+ /// class.
+ ///
+ ///
+ /// The connection that should be associated with the event.
+ ///
+ internal PipeConnectionEventArgs(NamedPipeConnection connection)
+ {
+ Connection = connection;
}
}
diff --git a/YAMDCC.IPC/PipeErrorEventArgs.cs b/YAMDCC.IPC/PipeErrorEventArgs.cs
index 4840097..0f36dd0 100644
--- a/YAMDCC.IPC/PipeErrorEventArgs.cs
+++ b/YAMDCC.IPC/PipeErrorEventArgs.cs
@@ -1,43 +1,42 @@
using System;
-namespace YAMDCC.IPC
+namespace YAMDCC.IPC;
+
+///
+/// Provides data for the
+/// and
+/// events.
+///
+public class PipeErrorEventArgs : EventArgs
+ where TRead : class
+ where TWrite : class
{
+ public NamedPipeConnection Connection { get; }
+
///
- /// Provides data for the
- /// and
- /// events.
+ /// The that caused the error.
///
- public class PipeErrorEventArgs : EventArgs
- where TRead : class
- where TWrite : class
- {
- public NamedPipeConnection Connection { get; }
-
- ///
- /// The that caused the error.
- ///
- public Exception Exception { get; }
+ public Exception Exception { get; }
- ///
- /// Initialises a new instance of the
- /// class.
- ///
- ///
- /// The connection that caused the error.
- ///
- /// The only time this should be null is if the error was caused
- /// by .
- ///
- ///
- ///
- /// The exception that caused the error.
- ///
- internal PipeErrorEventArgs(
- NamedPipeConnection connection,
- Exception exception)
- {
- Connection = connection;
- Exception = exception;
- }
+ ///
+ /// Initialises a new instance of the
+ /// class.
+ ///
+ ///
+ /// The connection that caused the error.
+ ///
+ /// The only time this should be null is if the error was caused
+ /// by .
+ ///
+ ///
+ ///
+ /// The exception that caused the error.
+ ///
+ internal PipeErrorEventArgs(
+ NamedPipeConnection connection,
+ Exception exception)
+ {
+ Connection = connection;
+ Exception = exception;
}
}
diff --git a/YAMDCC.IPC/PipeMessageEventArgs.cs b/YAMDCC.IPC/PipeMessageEventArgs.cs
index 9715647..1376517 100644
--- a/YAMDCC.IPC/PipeMessageEventArgs.cs
+++ b/YAMDCC.IPC/PipeMessageEventArgs.cs
@@ -1,39 +1,38 @@
-namespace YAMDCC.IPC
+namespace YAMDCC.IPC;
+
+///
+/// Provides data for the
+/// and
+/// events.
+///
+///
+/// The reference type used when reading from the named pipe.
+///
+///
+/// The reference type used when writing to the named pipe.
+///
+public class PipeMessageEventArgs : PipeConnectionEventArgs
+ where TRead : class
+ where TWrite : class
{
///
- /// Provides data for the
- /// and
- /// events.
+ /// The message sent by the other end of the pipe.
///
- ///
- /// The reference type used when reading from the named pipe.
- ///
- ///
- /// The reference type used when writing to the named pipe.
- ///
- public class PipeMessageEventArgs : PipeConnectionEventArgs
- where TRead : class
- where TWrite : class
- {
- ///
- /// The message sent by the other end of the pipe.
- ///
- public TRead Message { get; }
+ public TRead Message { get; }
- ///
- /// Initialises a new instance of the
- /// class.
- ///
- ///
- /// The connection that sent the message.
- ///
- ///
- /// The message sent by the other end of the pipe.
- ///
- internal PipeMessageEventArgs(NamedPipeConnection connection, TRead message)
- : base(connection)
- {
- Message = message;
- }
+ ///
+ /// Initialises a new instance of the
+ /// class.
+ ///
+ ///
+ /// The connection that sent the message.
+ ///
+ ///
+ /// The message sent by the other end of the pipe.
+ ///
+ internal PipeMessageEventArgs(NamedPipeConnection connection, TRead message)
+ : base(connection)
+ {
+ Message = message;
}
}
diff --git a/YAMDCC.IPC/PipeServerFactory.cs b/YAMDCC.IPC/PipeServerFactory.cs
index 100f2cf..a5b9428 100644
--- a/YAMDCC.IPC/PipeServerFactory.cs
+++ b/YAMDCC.IPC/PipeServerFactory.cs
@@ -1,35 +1,34 @@
using System.IO.Pipes;
-namespace YAMDCC.IPC
+namespace YAMDCC.IPC;
+
+internal static class PipeServerFactory
{
- internal static class PipeServerFactory
+ internal static NamedPipeServerStream CreateAndConnectPipe(string pipeName)
{
- internal static NamedPipeServerStream CreateAndConnectPipe(string pipeName)
- {
- NamedPipeServerStream pipe = CreatePipe(pipeName);
- pipe.WaitForConnection();
+ NamedPipeServerStream pipe = CreatePipe(pipeName);
+ pipe.WaitForConnection();
- return pipe;
- }
+ return pipe;
+ }
- internal static NamedPipeServerStream CreatePipe(string pipeName)
- {
- return new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Message,
- PipeOptions.Asynchronous);
- }
+ internal static NamedPipeServerStream CreatePipe(string pipeName)
+ {
+ return new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Message,
+ PipeOptions.Asynchronous);
+ }
- internal static NamedPipeServerStream CreateAndConnectPipe(string pipeName, int bufferSize, PipeSecurity security)
- {
- NamedPipeServerStream pipe = CreatePipe(pipeName, bufferSize, security);
- pipe.WaitForConnection();
+ internal static NamedPipeServerStream CreateAndConnectPipe(string pipeName, int bufferSize, PipeSecurity security)
+ {
+ NamedPipeServerStream pipe = CreatePipe(pipeName, bufferSize, security);
+ pipe.WaitForConnection();
- return pipe;
- }
+ return pipe;
+ }
- internal static NamedPipeServerStream CreatePipe(string pipeName, int bufferSize, PipeSecurity security)
- {
- return new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Message,
- PipeOptions.Asynchronous, bufferSize, bufferSize, security);
- }
+ internal static NamedPipeServerStream CreatePipe(string pipeName, int bufferSize, PipeSecurity security)
+ {
+ return new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Message,
+ PipeOptions.Asynchronous, bufferSize, bufferSize, security);
}
}
diff --git a/YAMDCC.IPC/ServiceCommand.cs b/YAMDCC.IPC/ServiceCommand.cs
index 70e039f..c324180 100644
--- a/YAMDCC.IPC/ServiceCommand.cs
+++ b/YAMDCC.IPC/ServiceCommand.cs
@@ -1,159 +1,158 @@
using MessagePack;
-namespace YAMDCC.IPC
+namespace YAMDCC.IPC;
+
+///
+/// Represents a list of possible commands that can
+/// be sent to the YAMDCC Service.
+///
+public enum Command
{
///
- /// Represents a list of possible commands that can
- /// be sent to the YAMDCC Service.
+ /// Fallback value if empty (zero-length) message received by server.
///
- public enum Command
- {
- ///
- /// Fallback value if empty (zero-length) message received by server.
- ///
- Nothing = 0,
- ///
- /// Get the YAMDCC Service version, as a Git revision hash.
- ///
- ///
- ///
- /// The result is sent to the caller as a
- /// message.
- ///
- ///
- /// This command expects no arguments.
- ///
- ///
- GetVersion,
- ///
- /// Read a byte from the EC.
- ///
- ///
- /// The result is sent to the caller as a
- /// message.
- ///
- ///
- /// This command expects the following arguments as
- /// a space-seperated string:
- /// • Register: The EC register to read.
- ///
- ///
- ReadECByte,
- ///
- /// Write a byte to the EC.
- ///
- ///
- ///
- /// This command expects the following arguments as
- /// a space-seperated string:
- /// • Register: The EC register to write to.
- /// • Value: The value to write.
- ///
- ///
- WriteECByte,
- ///
- /// Get the target speed of a specified system fan in the
- /// currently loaded YAMDCC config.
- ///
- ///
- ///
- /// This command expects the following arguments as
- /// a space-seperated string:
- /// • Fan: The index of the fan to read the target speed from.
- ///
- ///
- /// The result is sent to the caller as a
- /// message.
- ///
- ///
- GetFanSpeed,
- ///
- /// Get the RPM of a specified system fan in the
- /// currently loaded YAMDCC config.
- ///
- ///
- ///
- /// This command expects the following arguments as
- /// a space-seperated string:
- /// • Fan: The index of the fan to read the RPM from.
- ///
- ///
- /// The result is sent to the caller as a
- /// message.
- ///
- ///
- GetFanRPM,
- ///
- /// Get the temperature of the component (CPU, GPU...) associated
- /// with a specified system fan in the currently loaded YAMDCC config.
- ///
- ///
- ///
- /// This command expects the following arguments as
- /// a space-seperated string:
- /// • Fan: The index of the fan to read the associated component's temperature from.
- ///
- ///
- /// The result is sent to the caller as a
- /// message.
- ///
- ///
- GetTemp,
- ///
- /// Reload and apply a YAMDCC config.
- ///
- ApplyConfig,
- ///
- /// Enable or disable Full Blast on the system.
- ///
- ///
- /// This command expects the following arguments as
- /// a space-seperated string:
- /// • Enable: 1 to enable Full Blast, 0 to disable.
- ///
- FullBlast,
- ///
- /// Gets the brightness of the keyboard backlight,
- /// and sends a
- /// response with the result.
- ///
- GetKeyLightBright,
- ///
- /// Sets the keyboard backlight to the specified value.
- ///
- ///
- /// This command expects the following arguments as
- /// a space-seperated string:
- /// • Brightness: A value between the minimum and
- /// maximum brightness value (minus offset).
- ///
- SetKeyLightBright,
- }
+ Nothing = 0,
+ ///
+ /// Get the YAMDCC Service version, as a Git revision hash.
+ ///
+ ///
+ ///
+ /// The result is sent to the caller as a
+ /// message.
+ ///
+ ///
+ /// This command expects no arguments.
+ ///
+ ///
+ GetVersion,
+ ///
+ /// Read a byte from the EC.
+ ///
+ ///
+ /// The result is sent to the caller as a
+ /// message.
+ ///
+ ///
+ /// This command expects the following arguments as
+ /// a space-seperated string:
+ /// • Register: The EC register to read.
+ ///
+ ///
+ ReadECByte,
+ ///
+ /// Write a byte to the EC.
+ ///
+ ///
+ ///
+ /// This command expects the following arguments as
+ /// a space-seperated string:
+ /// • Register: The EC register to write to.
+ /// • Value: The value to write.
+ ///
+ ///
+ WriteECByte,
+ ///
+ /// Get the target speed of a specified system fan in the
+ /// currently loaded YAMDCC config.
+ ///
+ ///
+ ///
+ /// This command expects the following arguments as
+ /// a space-seperated string:
+ /// • Fan: The index of the fan to read the target speed from.
+ ///
+ ///
+ /// The result is sent to the caller as a
+ /// message.
+ ///
+ ///
+ GetFanSpeed,
+ ///
+ /// Get the RPM of a specified system fan in the
+ /// currently loaded YAMDCC config.
+ ///
+ ///
+ ///
+ /// This command expects the following arguments as
+ /// a space-seperated string:
+ /// • Fan: The index of the fan to read the RPM from.
+ ///
+ ///
+ /// The result is sent to the caller as a
+ /// message.
+ ///
+ ///
+ GetFanRPM,
+ ///
+ /// Get the temperature of the component (CPU, GPU...) associated
+ /// with a specified system fan in the currently loaded YAMDCC config.
+ ///
+ ///
+ ///
+ /// This command expects the following arguments as
+ /// a space-seperated string:
+ /// • Fan: The index of the fan to read the associated component's temperature from.
+ ///
+ ///
+ /// The result is sent to the caller as a
+ /// message.
+ ///
+ ///
+ GetTemp,
+ ///
+ /// Reload and apply a YAMDCC config.
+ ///
+ ApplyConfig,
+ ///
+ /// Enable or disable Full Blast on the system.
+ ///
+ ///
+ /// This command expects the following arguments as
+ /// a space-seperated string:
+ /// • Enable: 1 to enable Full Blast, 0 to disable.
+ ///
+ FullBlast,
+ ///
+ /// Gets the brightness of the keyboard backlight,
+ /// and sends a
+ /// response with the result.
+ ///
+ GetKeyLightBright,
+ ///
+ /// Sets the keyboard backlight to the specified value.
+ ///
+ ///
+ /// This command expects the following arguments as
+ /// a space-seperated string:
+ /// • Brightness: A value between the minimum and
+ /// maximum brightness value (minus offset).
+ ///
+ SetKeyLightBright,
+}
+///
+/// Represents a command to send to the YAMDCC Service.
+///
+[MessagePackObject]
+public class ServiceCommand
+{
///
- /// Represents a command to send to the YAMDCC Service.
+ /// The to send to the service.
///
- [MessagePackObject]
- public class ServiceCommand
- {
- ///
- /// The to send to the service.
- ///
- [Key(0)]
- public Command Command { get; set; } = Command.Nothing;
+ [Key(0)]
+ public Command Command { get; set; } = Command.Nothing;
- ///
- /// The argument(s) to send to the service with the command.
- /// The number of parameters for a service command vary depending on the
- /// specific command sent to the service.
- ///
- [Key(1)]
- public string Arguments { get; set; } = string.Empty;
+ ///
+ /// The argument(s) to send to the service with the command.
+ /// The number of parameters for a service command vary depending on the
+ /// specific command sent to the service.
+ ///
+ [Key(1)]
+ public string Arguments { get; set; } = string.Empty;
- public ServiceCommand(Command command, string args)
- {
- Command = command;
- Arguments = args;
- }
+ public ServiceCommand(Command command, string args)
+ {
+ Command = command;
+ Arguments = args;
}
}
diff --git a/YAMDCC.IPC/ServiceResponse.cs b/YAMDCC.IPC/ServiceResponse.cs
index 5591bb3..475cafc 100644
--- a/YAMDCC.IPC/ServiceResponse.cs
+++ b/YAMDCC.IPC/ServiceResponse.cs
@@ -1,78 +1,77 @@
using MessagePack;
-namespace YAMDCC.IPC
+namespace YAMDCC.IPC;
+
+///
+/// Represents a list of possible responses to a .
+///
+public enum Response
{
///
- /// Represents a list of possible responses to a .
+ /// Fallback value if empty (zero-length) message received by client.
///
- public enum Response
- {
- ///
- /// Fallback value if empty (zero-length) message received by client.
- ///
- Nothing = 0,
- ///
- /// Sent when any command that doesn't return data finishes successfully.
- ///
- Success,
- ///
- /// Sent when any command encounters an error.
- ///
- Error,
- ///
- /// The result of a command.
- ///
- Version,
- ///
- /// The result of a command.
- ///
- Temp,
- ///
- /// The result of a command.
- ///
- FanSpeed,
- ///
- /// The result of a command.
- ///
- FanRPM,
- ///
- /// The result of a command.
- ///
- ReadResult,
- ///
- /// The result of a command.
- ///
- KeyLightBright,
- }
+ Nothing = 0,
+ ///
+ /// Sent when any command that doesn't return data finishes successfully.
+ ///
+ Success,
+ ///
+ /// Sent when any command encounters an error.
+ ///
+ Error,
+ ///
+ /// The result of a command.
+ ///
+ Version,
+ ///
+ /// The result of a command.
+ ///
+ Temp,
+ ///
+ /// The result of a command.
+ ///
+ FanSpeed,
+ ///
+ /// The result of a command.
+ ///
+ FanRPM,
+ ///
+ /// The result of a command.
+ ///
+ ReadResult,
+ ///
+ /// The result of a command.
+ ///
+ KeyLightBright,
+}
+///
+/// Represents a response to a .
+///
+[MessagePackObject]
+public class ServiceResponse
+{
///
- /// Represents a response to a .
+ /// The to send to the service.
///
- [MessagePackObject]
- public class ServiceResponse
- {
- ///
- /// The to send to the service.
- ///
- [Key(0)]
- public Response Response { get; set; } = Response.Nothing;
+ [Key(0)]
+ public Response Response { get; set; } = Response.Nothing;
- ///
- /// The value associated with the .
- ///
- [Key(1)]
- public string Value { get; set; } = string.Empty;
+ ///
+ /// The value associated with the .
+ ///
+ [Key(1)]
+ public string Value { get; set; } = string.Empty;
- ///
- /// Initialises a new instance of the
- /// struct with the specified message and return value.
- ///
- ///
- ///
- public ServiceResponse(Response response, string value)
- {
- Response = response;
- Value = value;
- }
+ ///
+ /// Initialises a new instance of the
+ /// struct with the specified message and return value.
+ ///
+ ///
+ ///
+ public ServiceResponse(Response response, string value)
+ {
+ Response = response;
+ Value = value;
}
}
diff --git a/YAMDCC.IPC/Threading/Worker.cs b/YAMDCC.IPC/Threading/Worker.cs
index 16b3010..d896692 100644
--- a/YAMDCC.IPC/Threading/Worker.cs
+++ b/YAMDCC.IPC/Threading/Worker.cs
@@ -2,59 +2,58 @@
using System.Threading;
using System.Threading.Tasks;
-namespace YAMDCC.IPC.Threading
+namespace YAMDCC.IPC.Threading;
+
+internal sealed class Worker
{
- internal sealed class Worker
- {
- private readonly TaskScheduler _callbackThread;
+ private readonly TaskScheduler _callbackThread;
- private static TaskScheduler CurrentTaskScheduler =>
- SynchronizationContext.Current != null
- ? TaskScheduler.FromCurrentSynchronizationContext()
- : TaskScheduler.Default;
+ private static TaskScheduler CurrentTaskScheduler =>
+ SynchronizationContext.Current != null
+ ? TaskScheduler.FromCurrentSynchronizationContext()
+ : TaskScheduler.Default;
- internal event EventHandler Succeeded;
- internal event EventHandler Error;
+ internal event EventHandler Succeeded;
+ internal event EventHandler Error;
- internal Worker() : this(CurrentTaskScheduler) { }
+ internal Worker() : this(CurrentTaskScheduler) { }
- internal Worker(TaskScheduler callbackThread)
- {
- _callbackThread = callbackThread;
- }
+ internal Worker(TaskScheduler callbackThread)
+ {
+ _callbackThread = callbackThread;
+ }
- internal void DoWork(Action action)
- {
- new Task(DoWorkImpl, action, CancellationToken.None, TaskCreationOptions.LongRunning).Start();
- }
+ internal void DoWork(Action action)
+ {
+ new Task(DoWorkImpl, action, CancellationToken.None, TaskCreationOptions.LongRunning).Start();
+ }
- internal void DoWorkImpl(object oAction)
+ internal void DoWorkImpl(object oAction)
+ {
+ Action action = (Action)oAction;
+ try
{
- Action action = (Action)oAction;
- try
- {
- action();
- Callback(Succeed);
- }
- catch (Exception e)
- {
- Callback(() => Fail(e));
- }
+ action();
+ Callback(Succeed);
}
-
- private void Succeed()
+ catch (Exception e)
{
- Succeeded?.Invoke(this, EventArgs.Empty);
+ Callback(() => Fail(e));
}
+ }
- private void Fail(Exception exception)
- {
- Error?.Invoke(this, new WorkerErrorEventArgs(exception));
- }
+ private void Succeed()
+ {
+ Succeeded?.Invoke(this, EventArgs.Empty);
+ }
- private void Callback(Action action)
- {
- Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, _callbackThread);
- }
+ private void Fail(Exception exception)
+ {
+ Error?.Invoke(this, new WorkerErrorEventArgs(exception));
+ }
+
+ private void Callback(Action action)
+ {
+ Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, _callbackThread);
}
}
diff --git a/YAMDCC.IPC/Threading/WorkerErrorEventArgs.cs b/YAMDCC.IPC/Threading/WorkerErrorEventArgs.cs
index 55b8c7b..a28fbcc 100644
--- a/YAMDCC.IPC/Threading/WorkerErrorEventArgs.cs
+++ b/YAMDCC.IPC/Threading/WorkerErrorEventArgs.cs
@@ -1,29 +1,28 @@
using System;
-namespace YAMDCC.IPC.Threading
+namespace YAMDCC.IPC.Threading;
+
+///
+/// Provides data for the
+/// and
+/// events.
+///
+public class WorkerErrorEventArgs : EventArgs
{
///
- /// Provides data for the
- /// and
- /// events.
+ /// The that caused the error.
///
- public class WorkerErrorEventArgs : EventArgs
- {
- ///
- /// The that caused the error.
- ///
- public Exception Exception { get; }
+ public Exception Exception { get; }
- ///
- /// Initialises a new instance of the
- /// class.
- ///
- ///
- /// The exception that caused the error.
- ///
- internal WorkerErrorEventArgs(Exception exception)
- {
- Exception = exception;
- }
+ ///
+ /// Initialises a new instance of the
+ /// class.
+ ///
+ ///
+ /// The exception that caused the error.
+ ///
+ internal WorkerErrorEventArgs(Exception exception)
+ {
+ Exception = exception;
}
}
diff --git a/YAMDCC.Logs/LogLevel.cs b/YAMDCC.Logs/LogLevel.cs
index b036681..81dae73 100644
--- a/YAMDCC.Logs/LogLevel.cs
+++ b/YAMDCC.Logs/LogLevel.cs
@@ -14,41 +14,40 @@
// You should have received a copy of the GNU General Public License along with
// YAMDCC. If not, see .
-namespace YAMDCC.Logs
+namespace YAMDCC.Logs;
+
+///
+/// The verbosity of logs
+///
+public enum LogLevel
{
///
- /// The verbosity of logs
+ /// Do not log anything.
///
- public enum LogLevel
- {
- ///
- /// Do not log anything.
- ///
- None = 0,
+ None = 0,
- ///
- /// Only log Fatal events.
- ///
- Fatal = 1,
+ ///
+ /// Only log Fatal events.
+ ///
+ Fatal = 1,
- ///
- /// Log Errors and Fatal events.
- ///
- Error = 2,
+ ///
+ /// Log Errors and Fatal events.
+ ///
+ Error = 2,
- ///
- /// Log Warnings, Errors, and Fatal events.
- ///
- Warn = 3,
+ ///
+ /// Log Warnings, Errors, and Fatal events.
+ ///
+ Warn = 3,
- ///
- /// Log all events, except for Debug events.
- ///
- Info = 4,
+ ///
+ /// Log all events, except for Debug events.
+ ///
+ Info = 4,
- ///
- /// Log all events.
- ///
- Debug = 5,
- }
+ ///
+ /// Log all events.
+ ///
+ Debug = 5,
}
diff --git a/YAMDCC.Logs/Logger.cs b/YAMDCC.Logs/Logger.cs
index b90123c..62be92f 100644
--- a/YAMDCC.Logs/Logger.cs
+++ b/YAMDCC.Logs/Logger.cs
@@ -20,377 +20,376 @@
using System.IO.Compression;
using System.Reflection;
-namespace YAMDCC.Logs
+namespace YAMDCC.Logs;
+
+///
+/// A simple logger class for writing logs to
+/// the console or a configurable file path.
+///
+public sealed class Logger : IDisposable
{
///
- /// A simple logger class for writing logs to
- /// the console or a configurable file path.
+ /// The to write log files to.
+ ///
+ private StreamWriter LogWriter;
+
+ ///
+ /// Used with to prevent more
+ /// than one thread writing to the console at once.
+ ///
+ private readonly object consoleLock = new();
+
+ ///
+ /// The newline characters to split provided log message lines by.
+ ///
+ private static readonly char[] NewlineChars = ['\r', '\n'];
+
+ private static string LogString(string text, LogLevel level, bool showDate) =>
+ (showDate ? $"[{DateTime.Now:dd/MM/yyyy @ HH:mm:ss.fff}] " : "") + $"[{level}]".PadRight(8).ToUpper(CultureInfo.InvariantCulture) + text;
+
+ ///
+ /// The directory in which log files are saved.
+ ///
+ public string LogDir { get; set; } = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
+
+ ///
+ /// The base name of the log file.
+ ///
+ ///
+ ///
+ /// Log files will have the .log extension appended.
+ ///
+ ///
+ /// Archives will have a number appended before the .log
+ /// extension, with higher numbers indicating older logs.
+ ///
+ ///
+ public string LogName { get; set; } = Path.GetFileName(Assembly.GetEntryAssembly().Location);
+
+ private string LogPath => Path.Combine(LogDir, LogName);
+
+ ///
+ /// The maximum number of logs to archive.
+ ///
+ public int MaxArchivedLogs { get; set; } = 9;
+
+ ///
+ /// How verbose should console logs be?
+ ///
+ public LogLevel ConsoleLogLevel { get; set; } = LogLevel.Info;
+
+ ///
+ /// How verbose should logs written to disk be?
+ ///
+ public LogLevel FileLogLevel { get; set; } = LogLevel.Info;
+
+ ///
+ /// Should the log time be shown in console logs?
+ ///
+ public bool LogTimeToConsole { get; set; }
+
+ ///
+ /// Should the log time be shown in logs written to disk?
+ ///
+ public bool LogTimeToFile { get; set; } = true;
+
+ ///
+ /// Writes a Debug event to the .
///
- public sealed class Logger : IDisposable
+ ///
+ /// The event to write to the log.
+ ///
+ public void Debug(string message)
{
- ///
- /// The to write log files to.
- ///
- private StreamWriter LogWriter;
-
- ///
- /// Used with to prevent more
- /// than one thread writing to the console at once.
- ///
- private readonly object consoleLock = new();
-
- ///
- /// The newline characters to split provided log message lines by.
- ///
- private static readonly char[] NewlineChars = ['\r', '\n'];
-
- private static string LogString(string text, LogLevel level, bool showDate) =>
- (showDate ? $"[{DateTime.Now:dd/MM/yyyy @ HH:mm:ss.fff}] " : "") + $"[{level}]".PadRight(8).ToUpper(CultureInfo.InvariantCulture) + text;
-
- ///
- /// The directory in which log files are saved.
- ///
- public string LogDir { get; set; } = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
-
- ///
- /// The base name of the log file.
- ///
- ///
- ///
- /// Log files will have the .log extension appended.
- ///
- ///
- /// Archives will have a number appended before the .log
- /// extension, with higher numbers indicating older logs.
- ///
- ///
- public string LogName { get; set; } = Path.GetFileName(Assembly.GetEntryAssembly().Location);
-
- private string LogPath => Path.Combine(LogDir, LogName);
-
- ///
- /// The maximum number of logs to archive.
- ///
- public int MaxArchivedLogs { get; set; } = 9;
-
- ///
- /// How verbose should console logs be?
- ///
- public LogLevel ConsoleLogLevel { get; set; } = LogLevel.Info;
-
- ///
- /// How verbose should logs written to disk be?
- ///
- public LogLevel FileLogLevel { get; set; } = LogLevel.Info;
-
- ///
- /// Should the log time be shown in console logs?
- ///
- public bool LogTimeToConsole { get; set; }
-
- ///
- /// Should the log time be shown in logs written to disk?
- ///
- public bool LogTimeToFile { get; set; } = true;
-
- ///
- /// Writes a Debug event to the .
- ///
- ///
- /// The event to write to the log.
- ///
- public void Debug(string message)
+ if (FileLogLevel >= LogLevel.Debug)
{
- if (FileLogLevel >= LogLevel.Debug)
- {
- WriteFile(message, LogLevel.Debug);
- }
-
- if (ConsoleLogLevel >= LogLevel.Debug)
- {
- WriteConsole(message, LogLevel.Debug);
- }
+ WriteFile(message, LogLevel.Debug);
}
- ///
- /// Writes a Debug event to the ,
- /// replacing format items with the objects in .
- ///
- ///
- /// Equivalent to passing a
- /// to the argument.
- ///
- /// The event to write to the log.
- /// The objects to format.
- public void Debug(string message, params object[] args)
+ if (ConsoleLogLevel >= LogLevel.Debug)
{
- Debug(string.Format(CultureInfo.InvariantCulture, message, args));
+ WriteConsole(message, LogLevel.Debug);
}
+ }
- ///
- /// Writes an Info event to the .
- ///
- /// The event to write to the log.
- public void Info(string message)
- {
- if (FileLogLevel >= LogLevel.Info)
- {
- WriteFile(message, LogLevel.Info);
- }
+ ///
+ /// Writes a Debug event to the ,
+ /// replacing format items with the objects in .
+ ///
+ ///
+ /// Equivalent to passing a
+ /// to the argument.
+ ///
+ /// The event to write to the log.
+ /// The objects to format.
+ public void Debug(string message, params object[] args)
+ {
+ Debug(string.Format(CultureInfo.InvariantCulture, message, args));
+ }
- if (ConsoleLogLevel >= LogLevel.Info)
- {
- WriteConsole(message, LogLevel.Info);
- }
+ ///
+ /// Writes an Info event to the .
+ ///
+ /// The event to write to the log.
+ public void Info(string message)
+ {
+ if (FileLogLevel >= LogLevel.Info)
+ {
+ WriteFile(message, LogLevel.Info);
}
- ///
- /// Writes an Info event to the ,
- /// replacing format items with the objects in .
- ///
- ///
- /// Equivalent to passing a
- /// to the argument.
- ///
- /// The event to write to the log.
- /// The objects to format.
- public void Info(string message, params object[] args)
+ if (ConsoleLogLevel >= LogLevel.Info)
{
- Info(string.Format(CultureInfo.InvariantCulture, message, args));
+ WriteConsole(message, LogLevel.Info);
}
+ }
- ///
- /// Writes a Warning to the .
- ///
- /// The event to write to the log.
- public void Warn(string message)
- {
- if (FileLogLevel >= LogLevel.Warn)
- {
- WriteFile(message, LogLevel.Warn);
- }
+ ///
+ /// Writes an Info event to the ,
+ /// replacing format items with the objects in .
+ ///
+ ///
+ /// Equivalent to passing a
+ /// to the argument.
+ ///
+ /// The event to write to the log.
+ /// The objects to format.
+ public void Info(string message, params object[] args)
+ {
+ Info(string.Format(CultureInfo.InvariantCulture, message, args));
+ }
- if (ConsoleLogLevel >= LogLevel.Warn)
- {
- WriteConsole(message, LogLevel.Warn);
- }
+ ///
+ /// Writes a Warning to the .
+ ///
+ /// The event to write to the log.
+ public void Warn(string message)
+ {
+ if (FileLogLevel >= LogLevel.Warn)
+ {
+ WriteFile(message, LogLevel.Warn);
}
- ///
- /// Writes a Warning to the ,
- /// replacing format items with the objects in .
- ///
- ///
- /// Equivalent to passing a
- /// to the argument.
- ///
- /// The event to write to the log.
- /// The objects to format.
- public void Warn(string message, params object[] args)
+ if (ConsoleLogLevel >= LogLevel.Warn)
{
- Warn(string.Format(CultureInfo.InvariantCulture, message, args));
+ WriteConsole(message, LogLevel.Warn);
}
+ }
- ///
- /// Writes an Error to the .
- ///
- /// The event to write to the log.
- public void Error(string message)
+ ///
+ /// Writes a Warning to the ,
+ /// replacing format items with the objects in .
+ ///
+ ///
+ /// Equivalent to passing a
+ /// to the argument.
+ ///
+ /// The event to write to the log.
+ /// The objects to format.
+ public void Warn(string message, params object[] args)
+ {
+ Warn(string.Format(CultureInfo.InvariantCulture, message, args));
+ }
+
+ ///
+ /// Writes an Error to the .
+ ///
+ /// The event to write to the log.
+ public void Error(string message)
+ {
+ if (FileLogLevel >= LogLevel.Error)
{
- if (FileLogLevel >= LogLevel.Error)
- {
- WriteFile(message, LogLevel.Error);
- }
+ WriteFile(message, LogLevel.Error);
+ }
- if (ConsoleLogLevel >= LogLevel.Error)
- {
- WriteConsole(message, LogLevel.Error);
- }
+ if (ConsoleLogLevel >= LogLevel.Error)
+ {
+ WriteConsole(message, LogLevel.Error);
}
+ }
- ///
- /// Writes an Error to the ,
- /// replacing format items with the objects in .
- ///
- ///
- /// Equivalent to passing a
- /// to the argument.
- ///
- /// The event to write to the log.
- /// The objects to format.
- public void Error(string message, params object[] args)
+ ///
+ /// Writes an Error to the ,
+ /// replacing format items with the objects in .
+ ///
+ ///
+ /// Equivalent to passing a
+ /// to the argument.
+ ///
+ /// The event to write to the log.
+ /// The objects to format.
+ public void Error(string message, params object[] args)
+ {
+ Error(string.Format(CultureInfo.InvariantCulture, message, args));
+ }
+
+ ///
+ /// Writes a Fatal Error to the . Use when an
+ /// application is about to terminate due to a fatal error.
+ ///
+ /// The event to write to the log.
+ public void Fatal(string message)
+ {
+ if (FileLogLevel >= LogLevel.Fatal)
{
- Error(string.Format(CultureInfo.InvariantCulture, message, args));
+ WriteFile(message, LogLevel.Fatal);
}
- ///
- /// Writes a Fatal Error to the . Use when an
- /// application is about to terminate due to a fatal error.
- ///
- /// The event to write to the log.
- public void Fatal(string message)
+ if (ConsoleLogLevel >= LogLevel.Fatal)
{
- if (FileLogLevel >= LogLevel.Fatal)
- {
- WriteFile(message, LogLevel.Fatal);
- }
+ WriteConsole(message, LogLevel.Fatal);
+ }
+ }
- if (ConsoleLogLevel >= LogLevel.Fatal)
+ ///
+ /// Writes a Fatal Error to the ,
+ /// replacing format items with the objects in .
+ /// Use when an application is about to terminate due to a fatal error.
+ ///
+ ///
+ /// Equivalent to passing a
+ /// to the argument.
+ ///
+ /// The event to write to the log.
+ /// The objects to format.
+ public void Fatal(string message, params object[] args)
+ {
+ Fatal(string.Format(CultureInfo.InvariantCulture, message, args));
+ }
+
+ ///
+ /// Deletes all archived logs (files ending with .[number].log.gz).
+ ///
+ public void DeleteArchivedLogs()
+ {
+ for (int i = 1; i <= MaxArchivedLogs; i++)
+ {
+ try
{
- WriteConsole(message, LogLevel.Fatal);
+ File.Delete($"{LogPath}.{i}.log.gz");
}
+ catch (FileNotFoundException) { }
}
+ }
- ///
- /// Writes a Fatal Error to the ,
- /// replacing format items with the objects in .
- /// Use when an application is about to terminate due to a fatal error.
- ///
- ///
- /// Equivalent to passing a
- /// to the argument.
- ///
- /// The event to write to the log.
- /// The objects to format.
- public void Fatal(string message, params object[] args)
+ private void WriteFile(string message, LogLevel level)
+ {
+ if (LogWriter is null)
{
- Fatal(string.Format(CultureInfo.InvariantCulture, message, args));
+ InitLogFile();
}
- ///
- /// Deletes all archived logs (files ending with .[number].log.gz).
- ///
- public void DeleteArchivedLogs()
+ lock (LogWriter)
{
- for (int i = 1; i <= MaxArchivedLogs; i++)
+ foreach (string str in message.Split(NewlineChars, StringSplitOptions.RemoveEmptyEntries))
{
- try
- {
- File.Delete($"{LogPath}.{i}.log.gz");
- }
- catch (FileNotFoundException) { }
+ LogWriter.WriteLine(LogString(str, level, LogTimeToFile));
}
}
+ }
- private void WriteFile(string message, LogLevel level)
+ private void WriteConsole(string message, LogLevel level)
+ {
+ lock (consoleLock)
{
- if (LogWriter is null)
+ ConsoleColor bgColour = Console.BackgroundColor;
+ ConsoleColor fgColour = Console.ForegroundColor;
+
+ switch (level)
{
- InitLogFile();
+ case LogLevel.Fatal:
+ Console.BackgroundColor = ConsoleColor.Yellow;
+ Console.ForegroundColor = ConsoleColor.DarkRed;
+ break;
+ case LogLevel.Error:
+ Console.ForegroundColor = ConsoleColor.Red;
+ break;
+ case LogLevel.Warn:
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ break;
+ case LogLevel.Info:
+ Console.ForegroundColor = ConsoleColor.White;
+ break;
+ case LogLevel.Debug:
+ Console.ForegroundColor = ConsoleColor.DarkGray;
+ break;
}
- lock (LogWriter)
+ foreach (string str in message.Split(NewlineChars, StringSplitOptions.RemoveEmptyEntries))
{
- foreach (string str in message.Split(NewlineChars, StringSplitOptions.RemoveEmptyEntries))
- {
- LogWriter.WriteLine(LogString(str, level, LogTimeToFile));
- }
+ Console.WriteLine(LogString(str, level, LogTimeToConsole));
}
+
+ Console.BackgroundColor = bgColour;
+ Console.ForegroundColor = fgColour;
}
+ }
- private void WriteConsole(string message, LogLevel level)
+ ///
+ /// Initialises the log file.
+ /// Call before any attempts to write a log file.
+ ///
+ private void InitLogFile()
+ {
+ // Rename old log files, and delete the oldest file if
+ // there's too many log files
+ for (int i = MaxArchivedLogs; i >= 0; i--)
{
- lock (consoleLock)
+ try
{
- ConsoleColor bgColour = Console.BackgroundColor;
- ConsoleColor fgColour = Console.ForegroundColor;
-
- switch (level)
+ if (i == MaxArchivedLogs)
{
- case LogLevel.Fatal:
- Console.BackgroundColor = ConsoleColor.Yellow;
- Console.ForegroundColor = ConsoleColor.DarkRed;
- break;
- case LogLevel.Error:
- Console.ForegroundColor = ConsoleColor.Red;
- break;
- case LogLevel.Warn:
- Console.ForegroundColor = ConsoleColor.Yellow;
- break;
- case LogLevel.Info:
- Console.ForegroundColor = ConsoleColor.White;
- break;
- case LogLevel.Debug:
- Console.ForegroundColor = ConsoleColor.DarkGray;
- break;
+ File.Delete($"{LogPath}.{i}.log.gz");
}
-
- foreach (string str in message.Split(NewlineChars, StringSplitOptions.RemoveEmptyEntries))
+ else
{
- Console.WriteLine(LogString(str, level, LogTimeToConsole));
+ File.Move($"{LogPath}.{i}.log.gz", $"{LogPath}.{i + 1}.log.gz");
}
-
- Console.BackgroundColor = bgColour;
- Console.ForegroundColor = fgColour;
}
+ catch (FileNotFoundException) { }
+ catch (DirectoryNotFoundException) { }
}
- ///
- /// Initialises the log file.
- /// Call before any attempts to write a log file.
- ///
- private void InitLogFile()
+ try
{
- // Rename old log files, and delete the oldest file if
- // there's too many log files
- for (int i = MaxArchivedLogs; i >= 0; i--)
- {
- try
- {
- if (i == MaxArchivedLogs)
- {
- File.Delete($"{LogPath}.{i}.log.gz");
- }
- else
- {
- File.Move($"{LogPath}.{i}.log.gz", $"{LogPath}.{i + 1}.log.gz");
- }
- }
- catch (FileNotFoundException) { }
- catch (DirectoryNotFoundException) { }
- }
-
- try
- {
- FileInfo fi = new($"{LogPath}.log");
-
- // Set up file streams
- FileStream original = fi.OpenRead();
- FileStream compressed = File.Create($"{LogPath}.{1}.log.gz");
- GZipStream gzStream = new(compressed, CompressionLevel.Optimal);
+ FileInfo fi = new($"{LogPath}.log");
- // Compress the file
- original.CopyTo(gzStream);
+ // Set up file streams
+ FileStream original = fi.OpenRead();
+ FileStream compressed = File.Create($"{LogPath}.{1}.log.gz");
+ GZipStream gzStream = new(compressed, CompressionLevel.Optimal);
- // Close file streams
- gzStream.Close();
- compressed.Close();
- original.Close();
-
- // Delete the unarchived copy of the log
- fi.Delete();
- }
- catch (FileNotFoundException)
- {
- // Log files probably don't exist yet,
- // do nothing to avoid crash
- }
+ // Compress the file
+ original.CopyTo(gzStream);
- // if anyone knows why the fuck Directory.CreateDirectory
- // is doing nothing when running from a windows service and
- // pretending everything is ok i would LOVE to know
- // (workaround in YAMDCC.GUI/Program.cs)
- Directory.CreateDirectory(LogDir);
+ // Close file streams
+ gzStream.Close();
+ compressed.Close();
+ original.Close();
- LogWriter = new StreamWriter($"{LogPath}.log")
- {
- AutoFlush = true
- };
+ // Delete the unarchived copy of the log
+ fi.Delete();
}
-
- public void Dispose()
+ catch (FileNotFoundException)
{
- LogWriter.Dispose();
+ // Log files probably don't exist yet,
+ // do nothing to avoid crash
}
+
+ // if anyone knows why the fuck Directory.CreateDirectory
+ // is doing nothing when running from a windows service and
+ // pretending everything is ok i would LOVE to know
+ // (workaround in YAMDCC.GUI/Program.cs)
+ Directory.CreateDirectory(LogDir);
+
+ LogWriter = new StreamWriter($"{LogPath}.log")
+ {
+ AutoFlush = true
+ };
+ }
+
+ public void Dispose()
+ {
+ LogWriter.Dispose();
}
}
diff --git a/YAMDCC.Service/FanControlService.cs b/YAMDCC.Service/FanControlService.cs
index c9cadb8..0e44cb4 100644
--- a/YAMDCC.Service/FanControlService.cs
+++ b/YAMDCC.Service/FanControlService.cs
@@ -29,830 +29,829 @@
using YAMDCC.IPC;
using YAMDCC.Logs;
-namespace YAMDCC.Service
+namespace YAMDCC.Service;
+
+internal sealed class FanControlService : ServiceBase
{
- internal sealed class FanControlService : ServiceBase
- {
- #region Fields
+ #region Fields
- ///
- /// The currently loaded YAMDCC config.
- ///
- private YAMDCC_Config Config;
+ ///
+ /// The currently loaded YAMDCC config.
+ ///
+ private YAMDCC_Config Config;
- ///
- /// The named message pipe server that YAMDCC connects to.
- ///
- private readonly NamedPipeServer IPCServer;
+ ///
+ /// The named message pipe server that YAMDCC connects to.
+ ///
+ private readonly NamedPipeServer IPCServer;
- private readonly Logger Log;
+ private readonly Logger Log;
- private readonly EC _EC;
+ private readonly EC _EC;
- private volatile bool Cooldown;
- private readonly Timer CooldownTimer = new()
- {
- AutoReset = false,
- Interval = 1000,
- };
- #endregion
+ private volatile bool Cooldown;
+ private readonly Timer CooldownTimer = new()
+ {
+ AutoReset = false,
+ Interval = 1000,
+ };
+ #endregion
+
+ ///
+ /// Initialises a new instance of the class.
+ ///
+ ///
+ /// The instance to write logs to.
+ ///
+ public FanControlService(Logger logger)
+ {
+ CanHandlePowerEvent = true;
+ CanShutdown = true;
- ///
- /// Initialises a new instance of the class.
- ///
- ///
- /// The instance to write logs to.
- ///
- public FanControlService(Logger logger)
- {
- CanHandlePowerEvent = true;
- CanShutdown = true;
+ Log = logger;
+ _EC = new EC();
- Log = logger;
- _EC = new EC();
+ PipeSecurity security = new();
+ // use SDDL descriptor since not everyone uses english Windows.
+ // the SDDL descriptor should be roughly equivalent to the old
+ // behaviour (commented out below):
+ // security.AddAccessRule(new PipeAccessRule(
+ // "Administrators", PipeAccessRights.ReadWrite, AccessControlType.Allow));
+ security.SetSecurityDescriptorSddlForm("O:BAG:SYD:(A;;GA;;;SY)(A;;GRGW;;;BA)");
- PipeSecurity security = new();
- // use SDDL descriptor since not everyone uses english Windows.
- // the SDDL descriptor should be roughly equivalent to the old
- // behaviour (commented out below):
- // security.AddAccessRule(new PipeAccessRule(
- // "Administrators", PipeAccessRights.ReadWrite, AccessControlType.Allow));
- security.SetSecurityDescriptorSddlForm("O:BAG:SYD:(A;;GA;;;SY)(A;;GRGW;;;BA)");
+ IPCServer = new NamedPipeServer("YAMDCC-Server", security);
+ }
- IPCServer = new NamedPipeServer("YAMDCC-Server", security);
- }
+ #region Events
+ protected override void OnStart(string[] args)
+ {
+ Log.Info(Strings.GetString("svcStarting"));
+
+ // Load the service config.
+ bool confLoaded = LoadConf();
- #region Events
- protected override void OnStart(string[] args)
+ // Install WinRing0 to get EC access
+ try
{
- Log.Info(Strings.GetString("svcStarting"));
+ Log.Info(Strings.GetString("drvLoad"));
+ if (!_EC.LoadDriver())
+ {
+ throw new Win32Exception(_EC.GetDriverError());
+ }
+ }
+ catch (Win32Exception)
+ {
+ Log.Fatal(Strings.GetString("drvLoadFail"));
+ _EC.UnloadDriver();
+ ExitCode = 1;
+ throw;
+ }
+ Log.Info(Strings.GetString("drvLoadSuccess"));
- // Load the service config.
- bool confLoaded = LoadConf();
+ CooldownTimer.Elapsed += CooldownElapsed;
- // Install WinRing0 to get EC access
- try
+ // Set up IPC server
+ Log.Info("Starting IPC server...");
+ IPCServer.ClientConnected += IPCClientConnect;
+ IPCServer.ClientDisconnected += IPCClientDisconnect;
+ IPCServer.Error += IPCServerError;
+ IPCServer.Start();
+
+ Log.Info(Strings.GetString("svcStarted"));
+
+ // Attempt to read default fan curve if it's pending:
+ int rebootFlag = -1;
+ try
+ {
+ StreamReader sr = new(Paths.ECToConfPending);
+ if (int.TryParse(sr.ReadToEnd(), NumberStyles.Integer, CultureInfo.InvariantCulture, out int value))
{
- Log.Info(Strings.GetString("drvLoad"));
- if (!_EC.LoadDriver())
- {
- throw new Win32Exception(_EC.GetDriverError());
- }
+ rebootFlag = value;
}
- catch (Win32Exception)
+ sr.Close();
+
+ if (rebootFlag == 0)
{
- Log.Fatal(Strings.GetString("drvLoadFail"));
- _EC.UnloadDriver();
- ExitCode = 1;
- throw;
+ ECToConf();
+ File.Delete(Paths.ECToConfPending);
}
- Log.Info(Strings.GetString("drvLoadSuccess"));
+ }
+ catch (FileNotFoundException) { }
+ catch (DirectoryNotFoundException) { }
- CooldownTimer.Elapsed += CooldownElapsed;
+ // Apply the fan curve and charging threshold:
+ if (confLoaded)
+ {
+ ApplySettings();
+ }
+ }
- // Set up IPC server
- Log.Info("Starting IPC server...");
- IPCServer.ClientConnected += IPCClientConnect;
- IPCServer.ClientDisconnected += IPCClientDisconnect;
- IPCServer.Error += IPCServerError;
- IPCServer.Start();
+ private void CooldownElapsed(object sender, ElapsedEventArgs e)
+ {
+ CooldownTimer.Stop();
+ Cooldown = false;
+ }
- Log.Info(Strings.GetString("svcStarted"));
+ protected override void OnStop()
+ {
+ StopSvc();
+ }
- // Attempt to read default fan curve if it's pending:
- int rebootFlag = -1;
+ protected override void OnShutdown()
+ {
+ int rebootFlag = -1;
+ try
+ {
+ StreamReader sr = new(Paths.ECToConfPending);
try
{
- StreamReader sr = new(Paths.ECToConfPending);
if (int.TryParse(sr.ReadToEnd(), NumberStyles.Integer, CultureInfo.InvariantCulture, out int value))
{
rebootFlag = value;
}
- sr.Close();
-
- if (rebootFlag == 0)
- {
- ECToConf();
- File.Delete(Paths.ECToConfPending);
- }
}
- catch (FileNotFoundException) { }
- catch (DirectoryNotFoundException) { }
-
- // Apply the fan curve and charging threshold:
- if (confLoaded)
+ finally
{
- ApplySettings();
+ sr.Close();
}
- }
-
- private void CooldownElapsed(object sender, ElapsedEventArgs e)
- {
- CooldownTimer.Stop();
- Cooldown = false;
- }
-
- protected override void OnStop()
- {
- StopSvc();
- }
- protected override void OnShutdown()
- {
- int rebootFlag = -1;
- try
+ if (rebootFlag == 1)
{
- StreamReader sr = new(Paths.ECToConfPending);
+ StreamWriter sw = new(Paths.ECToConfPending);
try
{
- if (int.TryParse(sr.ReadToEnd(), NumberStyles.Integer, CultureInfo.InvariantCulture, out int value))
- {
- rebootFlag = value;
- }
+ sw.Write(0);
}
finally
{
- sr.Close();
- }
-
- if (rebootFlag == 1)
- {
- StreamWriter sw = new(Paths.ECToConfPending);
- try
- {
- sw.Write(0);
- }
- finally
- {
- sw.Close();
- }
+ sw.Close();
}
}
- catch (FileNotFoundException) { }
- catch (DirectoryNotFoundException) { }
- StopSvc();
}
+ catch (FileNotFoundException) { }
+ catch (DirectoryNotFoundException) { }
+ StopSvc();
+ }
- private void StopSvc()
+ private void StopSvc()
+ {
+ if (ExitCode == 0)
{
- if (ExitCode == 0)
- {
- Log.Info(Strings.GetString("svcStopping"));
+ Log.Info(Strings.GetString("svcStopping"));
- // Stop the IPC server:
- Log.Info("Stopping IPC server...");
- IPCServer.Stop();
- IPCServer.ClientConnected -= IPCClientConnect;
- IPCServer.ClientDisconnected -= IPCClientDisconnect;
- IPCServer.Error -= IPCServerError;
+ // Stop the IPC server:
+ Log.Info("Stopping IPC server...");
+ IPCServer.Stop();
+ IPCServer.ClientConnected -= IPCClientConnect;
+ IPCServer.ClientDisconnected -= IPCClientDisconnect;
+ IPCServer.Error -= IPCServerError;
- CooldownTimer.Elapsed -= CooldownElapsed;
+ CooldownTimer.Elapsed -= CooldownElapsed;
- // Uninstall WinRing0 to keep things clean
- Log.Info(Strings.GetString("drvUnload"));
- _EC.UnloadDriver();
+ // Uninstall WinRing0 to keep things clean
+ Log.Info(Strings.GetString("drvUnload"));
+ _EC.UnloadDriver();
- Log.Info(Strings.GetString("svcStopped"));
- }
+ Log.Info(Strings.GetString("svcStopped"));
}
+ }
- protected override bool OnPowerEvent(PowerBroadcastStatus powerStatus)
+ protected override bool OnPowerEvent(PowerBroadcastStatus powerStatus)
+ {
+ switch (powerStatus)
{
- switch (powerStatus)
- {
- case PowerBroadcastStatus.ResumeCritical:
- case PowerBroadcastStatus.ResumeSuspend:
- case PowerBroadcastStatus.ResumeAutomatic:
- if (!Cooldown)
- {
- // Re-apply the fan curve after waking up from sleep:
- Log.Info(Strings.GetString("svcWake"));
- ApplySettings();
- Cooldown = true;
- CooldownTimer.Start();
- }
- break;
- }
- return true;
+ case PowerBroadcastStatus.ResumeCritical:
+ case PowerBroadcastStatus.ResumeSuspend:
+ case PowerBroadcastStatus.ResumeAutomatic:
+ if (!Cooldown)
+ {
+ // Re-apply the fan curve after waking up from sleep:
+ Log.Info(Strings.GetString("svcWake"));
+ ApplySettings();
+ Cooldown = true;
+ CooldownTimer.Start();
+ }
+ break;
}
+ return true;
+ }
- private void IPCClientConnect(object sender, PipeConnectionEventArgs e)
- {
- e.Connection.ReceiveMessage += IPCClientMessage;
- Log.Info(Strings.GetString("ipcConnect", e.Connection.ID));
- }
+ private void IPCClientConnect(object sender, PipeConnectionEventArgs e)
+ {
+ e.Connection.ReceiveMessage += IPCClientMessage;
+ Log.Info(Strings.GetString("ipcConnect", e.Connection.ID));
+ }
- private void IPCClientDisconnect(object sender, PipeConnectionEventArgs e)
- {
- e.Connection.ReceiveMessage -= IPCClientMessage;
- Log.Info(Strings.GetString("ipcDC", e.Connection.ID));
- }
+ private void IPCClientDisconnect(object sender, PipeConnectionEventArgs e)
+ {
+ e.Connection.ReceiveMessage -= IPCClientMessage;
+ Log.Info(Strings.GetString("ipcDC", e.Connection.ID));
+ }
- private void IPCServerError(object sender, PipeErrorEventArgs e)
- {
- Log.Error(Strings.GetString("ipcError", e.Connection.ID, e.Exception));
- }
+ private void IPCServerError(object sender, PipeErrorEventArgs e)
+ {
+ Log.Error(Strings.GetString("ipcError", e.Connection.ID, e.Exception));
+ }
- private void IPCClientMessage(object sender, PipeMessageEventArgs e)
- {
- bool parseSuccess = false,
- cmdSuccess = false,
- sendSuccessMsg = true;
+ private void IPCClientMessage(object sender, PipeMessageEventArgs e)
+ {
+ bool parseSuccess = false,
+ cmdSuccess = false,
+ sendSuccessMsg = true;
- if (ParseArgs(e.Message.Arguments, out int[] args))
- {
- switch (e.Message.Command)
- {
- case Command.Nothing:
- Log.Warn("Empty command received!");
- return;
- case Command.GetVersion:
- IPCServer.PushMessage(new ServiceResponse(
- Response.Version, Utils.GetRevision()), e.Connection.ID);
- return;
- case Command.ReadECByte:
- if (args.Length == 1)
- {
- parseSuccess = true;
- sendSuccessMsg = false;
- cmdSuccess = LogECReadByte((byte)args[0], out byte value);
- if (cmdSuccess)
- {
- IPCServer.PushMessage(new ServiceResponse(
- Response.ReadResult, $"{args[0]} {value}"), e.Connection.ID);
- }
- }
- break;
- case Command.WriteECByte:
- if (args.Length == 2)
- {
- parseSuccess = true;
- cmdSuccess = LogECWriteByte((byte)args[0], (byte)args[1]);
- }
- break;
- case Command.GetFanSpeed:
- if (args.Length == 1)
- {
- parseSuccess = true;
- sendSuccessMsg = false;
- cmdSuccess = GetFanSpeed(e.Connection.ID, args[0]);
- }
- break;
- case Command.GetFanRPM:
- if (args.Length == 1)
- {
- parseSuccess = true;
- sendSuccessMsg = false;
- cmdSuccess = GetFanRPM(e.Connection.ID, args[0]);
- }
- break;
- case Command.GetTemp:
- if (args.Length == 1)
- {
- parseSuccess = true;
- sendSuccessMsg = false;
- cmdSuccess = GetTemp(e.Connection.ID, args[0]);
- }
- break;
- case Command.ApplyConfig:
+ if (ParseArgs(e.Message.Arguments, out int[] args))
+ {
+ switch (e.Message.Command)
+ {
+ case Command.Nothing:
+ Log.Warn("Empty command received!");
+ return;
+ case Command.GetVersion:
+ IPCServer.PushMessage(new ServiceResponse(
+ Response.Version, Utils.GetRevision()), e.Connection.ID);
+ return;
+ case Command.ReadECByte:
+ if (args.Length == 1)
+ {
parseSuccess = true;
- cmdSuccess = LoadConf() && ApplySettings();
- break;
- case Command.FullBlast:
- if (args.Length == 1)
+ sendSuccessMsg = false;
+ cmdSuccess = LogECReadByte((byte)args[0], out byte value);
+ if (cmdSuccess)
{
- parseSuccess = true;
- cmdSuccess = SetFullBlast(args[0] == 1);
+ IPCServer.PushMessage(new ServiceResponse(
+ Response.ReadResult, $"{args[0]} {value}"), e.Connection.ID);
}
- break;
- case Command.GetKeyLightBright:
+ }
+ break;
+ case Command.WriteECByte:
+ if (args.Length == 2)
+ {
+ parseSuccess = true;
+ cmdSuccess = LogECWriteByte((byte)args[0], (byte)args[1]);
+ }
+ break;
+ case Command.GetFanSpeed:
+ if (args.Length == 1)
+ {
parseSuccess = true;
sendSuccessMsg = false;
- cmdSuccess = GetKeyLightBright(e.Connection.ID);
- break;
- case Command.SetKeyLightBright:
- if (args.Length == 1)
- {
- parseSuccess = true;
- cmdSuccess = SetKeyLightBright((byte)args[0]);
- }
- break;
- default: // Unknown command
- Log.Error(Strings.GetString("errBadCmd", e.Message));
- return;
- }
+ cmdSuccess = GetFanSpeed(e.Connection.ID, args[0]);
+ }
+ break;
+ case Command.GetFanRPM:
+ if (args.Length == 1)
+ {
+ parseSuccess = true;
+ sendSuccessMsg = false;
+ cmdSuccess = GetFanRPM(e.Connection.ID, args[0]);
+ }
+ break;
+ case Command.GetTemp:
+ if (args.Length == 1)
+ {
+ parseSuccess = true;
+ sendSuccessMsg = false;
+ cmdSuccess = GetTemp(e.Connection.ID, args[0]);
+ }
+ break;
+ case Command.ApplyConfig:
+ parseSuccess = true;
+ cmdSuccess = LoadConf() && ApplySettings();
+ break;
+ case Command.FullBlast:
+ if (args.Length == 1)
+ {
+ parseSuccess = true;
+ cmdSuccess = SetFullBlast(args[0] == 1);
+ }
+ break;
+ case Command.GetKeyLightBright:
+ parseSuccess = true;
+ sendSuccessMsg = false;
+ cmdSuccess = GetKeyLightBright(e.Connection.ID);
+ break;
+ case Command.SetKeyLightBright:
+ if (args.Length == 1)
+ {
+ parseSuccess = true;
+ cmdSuccess = SetKeyLightBright((byte)args[0]);
+ }
+ break;
+ default: // Unknown command
+ Log.Error(Strings.GetString("errBadCmd", e.Message));
+ return;
}
- else
+ }
+ else
+ {
+ Log.Error(Strings.GetString("errArgsBadType"));
+ Log.Error(Strings.GetString("errOffendingCmd", e.Message.Command, e.Message.Arguments));
+ }
+
+ if (!cmdSuccess)
+ {
+ if (!parseSuccess)
{
- Log.Error(Strings.GetString("errArgsBadType"));
+ Log.Error(Strings.GetString("errArgsBadLen"));
Log.Error(Strings.GetString("errOffendingCmd", e.Message.Command, e.Message.Arguments));
}
+ IPCServer.PushMessage(new ServiceResponse(
+ Response.Error, $"{(int)e.Message.Command}"), e.Connection.ID);
+ }
+ else if (sendSuccessMsg)
+ {
+ IPCServer.PushMessage(new ServiceResponse(
+ Response.Success, $"{(int)e.Message.Command}"), e.Connection.ID);
+ }
+ }
+ #endregion
- if (!cmdSuccess)
- {
- if (!parseSuccess)
- {
- Log.Error(Strings.GetString("errArgsBadLen"));
- Log.Error(Strings.GetString("errOffendingCmd", e.Message.Command, e.Message.Arguments));
- }
- IPCServer.PushMessage(new ServiceResponse(
- Response.Error, $"{(int)e.Message.Command}"), e.Connection.ID);
- }
- else if (sendSuccessMsg)
- {
- IPCServer.PushMessage(new ServiceResponse(
- Response.Success, $"{(int)e.Message.Command}"), e.Connection.ID);
- }
+ private bool LogECReadByte(byte reg, out byte value)
+ {
+ bool success = _EC.ReadByte(reg, out value);
+ if (success)
+ {
+ Log.Debug(Strings.GetString("svcECReadSuccess"), reg, value);
+ }
+ else
+ {
+ Log.Error(Strings.GetString("errECRead", reg, GetWin32Error(_EC.GetDriverError())));
}
- #endregion
+ return success;
+ }
- private bool LogECReadByte(byte reg, out byte value)
+ private bool LogECReadWord(byte reg, out ushort value, bool bigEndian)
+ {
+ bool success = _EC.ReadWord(reg, out value, bigEndian);
+ if (success)
{
- bool success = _EC.ReadByte(reg, out value);
- if (success)
- {
- Log.Debug(Strings.GetString("svcECReadSuccess"), reg, value);
- }
- else
- {
- Log.Error(Strings.GetString("errECRead", reg, GetWin32Error(_EC.GetDriverError())));
- }
- return success;
+ Log.Debug(Strings.GetString("svcECReadSuccess"), reg, value);
+ }
+ else
+ {
+ Log.Error(Strings.GetString("errECRead", reg, GetWin32Error(_EC.GetDriverError())));
}
+ return success;
+ }
- private bool LogECReadWord(byte reg, out ushort value, bool bigEndian)
+ private bool LogECWriteByte(byte reg, byte value)
+ {
+ bool success = _EC.WriteByte(reg, value);
+ if (success)
{
- bool success = _EC.ReadWord(reg, out value, bigEndian);
- if (success)
- {
- Log.Debug(Strings.GetString("svcECReadSuccess"), reg, value);
- }
- else
- {
- Log.Error(Strings.GetString("errECRead", reg, GetWin32Error(_EC.GetDriverError())));
- }
- return success;
+ Log.Debug(Strings.GetString("svcECWriteSuccess"), reg);
+ }
+ else
+ {
+ Log.Error(Strings.GetString("errECWrite", reg, GetWin32Error(_EC.GetDriverError())));
}
+ return success;
+ }
+
+ private bool LoadConf()
+ {
+ Log.Info(Strings.GetString("cfgLoading"));
- private bool LogECWriteByte(byte reg, byte value)
+ try
{
- bool success = _EC.WriteByte(reg, value);
- if (success)
+ Config = YAMDCC_Config.Load(Paths.CurrentConfig);
+ }
+ catch (Exception ex)
+ {
+ if (ex is InvalidConfigException or InvalidOperationException)
+ {
+ Log.Error(Strings.GetString("cfgInvalid"));
+ }
+ else if (ex is FileNotFoundException)
{
- Log.Debug(Strings.GetString("svcECWriteSuccess"), reg);
+ Log.Warn(Strings.GetString("cfgNotFound"));
}
else
{
- Log.Error(Strings.GetString("errECWrite", reg, GetWin32Error(_EC.GetDriverError())));
+ throw;
}
- return success;
+ Config = null;
+ return false;
}
- private bool LoadConf()
+ Log.Info(Strings.GetString("cfgLoaded"));
+ return true;
+ }
+
+ private bool ApplySettings()
+ {
+ if (Config is null)
{
- Log.Info(Strings.GetString("cfgLoading"));
+ return false;
+ }
- try
- {
- Config = YAMDCC_Config.Load(Paths.CurrentConfig);
- }
- catch (Exception ex)
+ Log.Info(Strings.GetString("cfgApplying"));
+ bool success = true;
+
+ // Write custom register values, if configured:
+ if (Config.RegConfs?.Length > 0)
+ {
+ for (int i = 0; i < Config.RegConfs.Length; i++)
{
- if (ex is InvalidConfigException or InvalidOperationException)
- {
- Log.Error(Strings.GetString("cfgInvalid"));
- }
- else if (ex is FileNotFoundException)
+ RegConf cfg = Config.RegConfs[i];
+ Log.Info(Strings.GetString("svcWritingCustomRegs", i + 1, Config.RegConfs.Length));
+ if (!LogECWriteByte(cfg.Reg, cfg.Value))
{
- Log.Warn(Strings.GetString("cfgNotFound"));
- }
- else
- {
- throw;
+ success = false;
}
- Config = null;
- return false;
}
-
- Log.Info(Strings.GetString("cfgLoaded"));
- return true;
}
- private bool ApplySettings()
+ // Write the fan curve to the appropriate registers for each fan:
+ for (int i = 0; i < Config.FanConfs.Length; i++)
{
- if (Config is null)
- {
- return false;
- }
+ FanConf cfg = Config.FanConfs[i];
+ Log.Info(Strings.GetString("svcWritingFans", cfg.Name, i + 1, Config.FanConfs.Length));
+ FanCurveConf curveCfg = cfg.FanCurveConfs[cfg.CurveSel];
- Log.Info(Strings.GetString("cfgApplying"));
- bool success = true;
-
- // Write custom register values, if configured:
- if (Config.RegConfs?.Length > 0)
+ for (int j = 0; j < curveCfg.TempThresholds.Length; j++)
{
- for (int i = 0; i < Config.RegConfs.Length; i++)
+ if (!LogECWriteByte(cfg.FanCurveRegs[j], curveCfg.TempThresholds[j].FanSpeed))
{
- RegConf cfg = Config.RegConfs[i];
- Log.Info(Strings.GetString("svcWritingCustomRegs", i + 1, Config.RegConfs.Length));
- if (!LogECWriteByte(cfg.Reg, cfg.Value))
- {
- success = false;
- }
+ success = false;
}
- }
-
- // Write the fan curve to the appropriate registers for each fan:
- for (int i = 0; i < Config.FanConfs.Length; i++)
- {
- FanConf cfg = Config.FanConfs[i];
- Log.Info(Strings.GetString("svcWritingFans", cfg.Name, i + 1, Config.FanConfs.Length));
- FanCurveConf curveCfg = cfg.FanCurveConfs[cfg.CurveSel];
-
- for (int j = 0; j < curveCfg.TempThresholds.Length; j++)
+ if (j > 0)
{
- if (!LogECWriteByte(cfg.FanCurveRegs[j], curveCfg.TempThresholds[j].FanSpeed))
+ if (!LogECWriteByte(cfg.UpThresholdRegs[j - 1], curveCfg.TempThresholds[j].UpThreshold))
{
success = false;
}
- if (j > 0)
+ byte downT = (byte)(curveCfg.TempThresholds[j].UpThreshold - curveCfg.TempThresholds[j].DownThreshold);
+ if (!LogECWriteByte(cfg.DownThresholdRegs[j - 1], downT))
{
- if (!LogECWriteByte(cfg.UpThresholdRegs[j - 1], curveCfg.TempThresholds[j].UpThreshold))
- {
- success = false;
- }
- byte downT = (byte)(curveCfg.TempThresholds[j].UpThreshold - curveCfg.TempThresholds[j].DownThreshold);
- if (!LogECWriteByte(cfg.DownThresholdRegs[j - 1], downT))
- {
- success = false;
- }
+ success = false;
}
}
}
+ }
- // Write the charge threshold:
- if (Config.ChargeLimitConf is not null)
+ // Write the charge threshold:
+ if (Config.ChargeLimitConf is not null)
+ {
+ Log.Info(Strings.GetString("svcWritingChgLim"));
+ byte value = (byte)(Config.ChargeLimitConf.MinVal + Config.ChargeLimitConf.CurVal);
+ if (!LogECWriteByte(Config.ChargeLimitConf.Reg, value))
{
- Log.Info(Strings.GetString("svcWritingChgLim"));
- byte value = (byte)(Config.ChargeLimitConf.MinVal + Config.ChargeLimitConf.CurVal);
- if (!LogECWriteByte(Config.ChargeLimitConf.Reg, value))
- {
- success = false;
- }
+ success = false;
}
+ }
- // Write the performance mode
- if (Config.PerfModeConf is not null)
+ // Write the performance mode
+ if (Config.PerfModeConf is not null)
+ {
+ Log.Info(Strings.GetString("svcWritingPerfMode"));
+ byte value = Config.PerfModeConf.PerfModes[Config.PerfModeConf.ModeSel].Value;
+ if (!LogECWriteByte(Config.PerfModeConf.Reg, value))
{
- Log.Info(Strings.GetString("svcWritingPerfMode"));
- byte value = Config.PerfModeConf.PerfModes[Config.PerfModeConf.ModeSel].Value;
- if (!LogECWriteByte(Config.PerfModeConf.Reg, value))
- {
- success = false;
- }
+ success = false;
}
+ }
- // Write the Win/Fn key swap setting
- if (Config.KeySwapConf is not null)
- {
- Log.Info(Strings.GetString("svcWritingKeySwap"));
- byte value = Config.KeySwapConf.Enabled
- ? Config.KeySwapConf.OnVal
- : Config.KeySwapConf.OffVal;
+ // Write the Win/Fn key swap setting
+ if (Config.KeySwapConf is not null)
+ {
+ Log.Info(Strings.GetString("svcWritingKeySwap"));
+ byte value = Config.KeySwapConf.Enabled
+ ? Config.KeySwapConf.OnVal
+ : Config.KeySwapConf.OffVal;
- if (!LogECWriteByte(Config.KeySwapConf.Reg, value))
- {
- success = false;
- }
- }
- return success;
- }
-
- ///
- /// Parse arguments from a given string.
- ///
- ///
- /// The string containing the space-delimited arguments.
- ///
- ///
- /// The parsed arguments. Will be empty if parsing fails.
- ///
- ///
- /// true if the arguments were parsed successfully,
- /// otherise false.
- ///
- private static bool ParseArgs(string argsIn, out int[] argsOut)
- {
- if (string.IsNullOrEmpty(argsIn))
+ if (!LogECWriteByte(Config.KeySwapConf.Reg, value))
{
- argsOut = [];
+ success = false;
}
- else
- {
- string[] args_str = argsIn.Split(' ');
- argsOut = new int[args_str.Length];
+ }
+ return success;
+ }
+
+ ///
+ /// Parse arguments from a given string.
+ ///
+ ///
+ /// The string containing the space-delimited arguments.
+ ///
+ ///
+ /// The parsed arguments. Will be empty if parsing fails.
+ ///
+ ///
+ /// true if the arguments were parsed successfully,
+ /// otherise false.
+ ///
+ private static bool ParseArgs(string argsIn, out int[] argsOut)
+ {
+ if (string.IsNullOrEmpty(argsIn))
+ {
+ argsOut = [];
+ }
+ else
+ {
+ string[] args_str = argsIn.Split(' ');
+ argsOut = new int[args_str.Length];
- for (int i = 0; i < args_str.Length; i++)
+ for (int i = 0; i < args_str.Length; i++)
+ {
+ if (!int.TryParse(args_str[i], out argsOut[i]))
{
- if (!int.TryParse(args_str[i], out argsOut[i]))
- {
- return false;
- }
+ return false;
}
}
+ }
+ return true;
+ }
+
+ private bool GetFanSpeed(int clientId, int fan)
+ {
+ if (Config is null)
+ {
+ return false;
+ }
+
+ FanConf cfg = Config.FanConfs[fan];
+
+ if (LogECReadByte(cfg.SpeedReadReg, out byte speed))
+ {
+ IPCServer.PushMessage(new ServiceResponse(
+ Response.FanSpeed, $"{speed}"), clientId);
return true;
}
+ return false;
+ }
- private bool GetFanSpeed(int clientId, int fan)
+ private bool GetFanRPM(int clientId, int fan)
+ {
+ if (Config?.FanConfs[fan].RPMConf is null)
{
- if (Config is null)
- {
- return false;
- }
+ return false;
+ }
- FanConf cfg = Config.FanConfs[fan];
+ FanConf cfg = Config.FanConfs[fan];
+
+ bool success;
+ ushort rpmValue;
+ if (cfg.RPMConf.Is16Bit)
+ {
+ success = LogECReadWord(cfg.RPMConf.ReadReg, out rpmValue, cfg.RPMConf.IsBigEndian);
+ }
+ else
+ {
+ success = LogECReadByte(cfg.RPMConf.ReadReg, out byte rpmValByte);
+ rpmValue = rpmValByte;
+ }
- if (LogECReadByte(cfg.SpeedReadReg, out byte speed))
+ if (success)
+ {
+ float rpm = 0;
+ if (rpmValue > 0)
{
- IPCServer.PushMessage(new ServiceResponse(
- Response.FanSpeed, $"{speed}"), clientId);
- return true;
+ rpm = cfg.RPMConf.DivideByMult
+ ? (float)rpmValue / cfg.RPMConf.RPMMult
+ : (float)rpmValue * cfg.RPMConf.RPMMult;
+
+ if (cfg.RPMConf.Invert)
+ {
+ rpm = 1 / rpm;
+ }
}
+ IPCServer.PushMessage(new ServiceResponse(
+ Response.FanRPM, $"{(int)rpm}"), clientId);
+ return true;
+ }
+ return false;
+ }
+
+ private bool GetTemp(int clientId, int fan)
+ {
+ if (Config is null)
+ {
return false;
}
- private bool GetFanRPM(int clientId, int fan)
+ FanConf cfg = Config.FanConfs[fan];
+
+ if (LogECReadByte(cfg.TempReadReg, out byte temp))
{
- if (Config?.FanConfs[fan].RPMConf is null)
- {
- return false;
- }
+ IPCServer.PushMessage(new ServiceResponse(
+ Response.Temp, $"{temp}"), clientId);
+ return true;
+ }
+ return false;
+ }
- FanConf cfg = Config.FanConfs[fan];
+ private bool SetFullBlast(bool enable)
+ {
+ if (Config?.FullBlastConf is null)
+ {
+ return false;
+ }
- bool success;
- ushort rpmValue;
- if (cfg.RPMConf.Is16Bit)
+ if (LogECReadByte(Config.FullBlastConf.Reg, out byte value))
+ {
+ if (enable)
{
- success = LogECReadWord(cfg.RPMConf.ReadReg, out rpmValue, cfg.RPMConf.IsBigEndian);
+ Log.Debug("Enabling Full Blast...");
+ value |= Config.FullBlastConf.Mask;
}
else
{
- success = LogECReadByte(cfg.RPMConf.ReadReg, out byte rpmValByte);
- rpmValue = rpmValByte;
+ Log.Debug("Disabling Full Blast...");
+ value &= (byte)~Config.FullBlastConf.Mask;
}
- if (success)
+ if (LogECWriteByte(Config.FullBlastConf.Reg, value))
{
- float rpm = 0;
- if (rpmValue > 0)
- {
- rpm = cfg.RPMConf.DivideByMult
- ? (float)rpmValue / cfg.RPMConf.RPMMult
- : (float)rpmValue * cfg.RPMConf.RPMMult;
-
- if (cfg.RPMConf.Invert)
- {
- rpm = 1 / rpm;
- }
- }
- IPCServer.PushMessage(new ServiceResponse(
- Response.FanRPM, $"{(int)rpm}"), clientId);
return true;
}
+ }
+ return false;
+ }
+
+ private bool GetKeyLightBright(int clientId)
+ {
+ if (Config?.KeyLightConf is null)
+ {
return false;
}
- private bool GetTemp(int clientId, int fan)
+ Log.Debug(Strings.GetString("svcGetKeyLightBright"));
+
+ if (LogECReadByte(Config.KeyLightConf.Reg, out byte value) &&
+ value >= Config.KeyLightConf.MinVal && value <= Config.KeyLightConf.MaxVal)
{
- if (Config is null)
- {
- return false;
- }
+ int brightness = value - Config.KeyLightConf.MinVal;
- FanConf cfg = Config.FanConfs[fan];
+ IPCServer.PushMessage(new ServiceResponse(
+ Response.KeyLightBright, $"{brightness}"), clientId);
+ return true;
+ }
+ return false;
+ }
- if (LogECReadByte(cfg.TempReadReg, out byte temp))
- {
- IPCServer.PushMessage(new ServiceResponse(
- Response.Temp, $"{temp}"), clientId);
- return true;
- }
+ private bool SetKeyLightBright(byte brightness)
+ {
+ if (Config?.KeyLightConf is null)
+ {
return false;
}
- private bool SetFullBlast(bool enable)
- {
- if (Config?.FullBlastConf is null)
- {
- return false;
- }
+ Log.Debug(Strings.GetString("svcSetKeyLightBright", brightness));
- if (LogECReadByte(Config.FullBlastConf.Reg, out byte value))
- {
- if (enable)
- {
- Log.Debug("Enabling Full Blast...");
- value |= Config.FullBlastConf.Mask;
- }
- else
- {
- Log.Debug("Disabling Full Blast...");
- value &= (byte)~Config.FullBlastConf.Mask;
- }
+ return LogECWriteByte(Config.KeyLightConf.Reg, (byte)(brightness + Config.KeyLightConf.MinVal));
+ }
- if (LogECWriteByte(Config.FullBlastConf.Reg, value))
- {
- return true;
- }
- }
+ private bool ECToConf()
+ {
+ if (Config is null)
+ {
return false;
}
- private bool GetKeyLightBright(int clientId)
+ try
{
- if (Config?.KeyLightConf is null)
- {
- return false;
- }
+ Log.Info(Strings.GetString("svcReadingModel"));
- Log.Debug(Strings.GetString("svcGetKeyLightBright"));
+ string pcManufacturer = GetPCManufacturer(),
+ pcModel = GetPCModel();
- if (LogECReadByte(Config.KeyLightConf.Reg, out byte value) &&
- value >= Config.KeyLightConf.MinVal && value <= Config.KeyLightConf.MaxVal)
+ if (string.IsNullOrEmpty(pcManufacturer))
{
- int brightness = value - Config.KeyLightConf.MinVal;
-
- IPCServer.PushMessage(new ServiceResponse(
- Response.KeyLightBright, $"{brightness}"), clientId);
- return true;
+ Log.Error(Strings.GetString("errReadManufacturer"));
}
- return false;
- }
-
- private bool SetKeyLightBright(byte brightness)
- {
- if (Config?.KeyLightConf is null)
+ else
{
- return false;
+ Config.Manufacturer = pcManufacturer.Trim();
}
- Log.Debug(Strings.GetString("svcSetKeyLightBright", brightness));
-
- return LogECWriteByte(Config.KeyLightConf.Reg, (byte)(brightness + Config.KeyLightConf.MinVal));
- }
-
- private bool ECToConf()
- {
- if (Config is null)
+ if (string.IsNullOrEmpty(pcModel))
+ {
+ Log.Error(Strings.GetString("errReadModel"));
+ }
+ else
{
- return false;
+ Config.Model = pcModel.Trim();
}
- try
+ for (int i = 0; i < Config.FanConfs.Length; i++)
{
- Log.Info(Strings.GetString("svcReadingModel"));
+ Log.Info(Strings.GetString("svcReadingCurves", i + 1, Config.FanConfs.Length));
- string pcManufacturer = GetPCManufacturer(),
- pcModel = GetPCModel();
+ FanConf cfg = Config.FanConfs[i];
- if (string.IsNullOrEmpty(pcManufacturer))
+ FanCurveConf curveCfg = null;
+ for (int j = 0; j < cfg.FanCurveConfs.Length; j++)
{
- Log.Error(Strings.GetString("errReadManufacturer"));
- }
- else
- {
- Config.Manufacturer = pcManufacturer.Trim();
+ if (cfg.FanCurveConfs[j].Name == "Default")
+ {
+ curveCfg = cfg.FanCurveConfs[j];
+ }
}
- if (string.IsNullOrEmpty(pcModel))
+ // there isn't already a Default fan profile in this config,
+ // make one and insert it at the start
+ if (curveCfg is null)
{
- Log.Error(Strings.GetString("errReadModel"));
- }
- else
- {
- Config.Model = pcModel.Trim();
+ curveCfg = new()
+ {
+ TempThresholds = new TempThreshold[cfg.FanCurveRegs.Length]
+ };
+ List curveCfgList = [.. cfg.FanCurveConfs];
+ curveCfgList.Insert(0, curveCfg);
+ cfg.FanCurveConfs = [.. curveCfgList];
+ cfg.CurveSel++;
}
- for (int i = 0; i < Config.FanConfs.Length; i++)
- {
- Log.Info(Strings.GetString("svcReadingCurves", i + 1, Config.FanConfs.Length));
-
- FanConf cfg = Config.FanConfs[i];
+ // reset first fan curve config name and description
+ curveCfg.Name = "Default";
+ curveCfg.Desc = Strings.GetString("confDefaultDesc");
- FanCurveConf curveCfg = null;
- for (int j = 0; j < cfg.FanCurveConfs.Length; j++)
+ for (int j = 0; j < cfg.FanCurveRegs.Length; j++)
+ {
+ if (curveCfg.TempThresholds[j] is null)
{
- if (cfg.FanCurveConfs[j].Name == "Default")
- {
- curveCfg = cfg.FanCurveConfs[j];
- }
+ curveCfg.TempThresholds[j] = new();
}
- // there isn't already a Default fan profile in this config,
- // make one and insert it at the start
- if (curveCfg is null)
+ if (LogECReadByte(cfg.FanCurveRegs[j], out byte value))
{
- curveCfg = new()
- {
- TempThresholds = new TempThreshold[cfg.FanCurveRegs.Length]
- };
- List curveCfgList = [.. cfg.FanCurveConfs];
- curveCfgList.Insert(0, curveCfg);
- cfg.FanCurveConfs = [.. curveCfgList];
- cfg.CurveSel++;
+ curveCfg.TempThresholds[j].FanSpeed = value;
}
- // reset first fan curve config name and description
- curveCfg.Name = "Default";
- curveCfg.Desc = Strings.GetString("confDefaultDesc");
-
- for (int j = 0; j < cfg.FanCurveRegs.Length; j++)
+ if (j == 0)
{
- if (curveCfg.TempThresholds[j] is null)
- {
- curveCfg.TempThresholds[j] = new();
- }
-
- if (LogECReadByte(cfg.FanCurveRegs[j], out byte value))
- {
- curveCfg.TempThresholds[j].FanSpeed = value;
- }
-
- if (j == 0)
+ curveCfg.TempThresholds[j].UpThreshold = 0;
+ curveCfg.TempThresholds[j].DownThreshold = 0;
+ }
+ else
+ {
+ if (LogECReadByte(cfg.UpThresholdRegs[j - 1], out value))
{
- curveCfg.TempThresholds[j].UpThreshold = 0;
- curveCfg.TempThresholds[j].DownThreshold = 0;
+ curveCfg.TempThresholds[j].UpThreshold = value;
}
- else
+ if (LogECReadByte(cfg.DownThresholdRegs[j - 1], out value))
{
- if (LogECReadByte(cfg.UpThresholdRegs[j - 1], out value))
- {
- curveCfg.TempThresholds[j].UpThreshold = value;
- }
- if (LogECReadByte(cfg.DownThresholdRegs[j - 1], out value))
- {
- curveCfg.TempThresholds[j].DownThreshold = (byte)(curveCfg.TempThresholds[j].UpThreshold - value);
- }
+ curveCfg.TempThresholds[j].DownThreshold = (byte)(curveCfg.TempThresholds[j].UpThreshold - value);
}
}
}
+ }
- Log.Info("Saving config...");
- Config.Save(Paths.CurrentConfig);
+ Log.Info("Saving config...");
+ Config.Save(Paths.CurrentConfig);
- FileStream fs = File.Create(Paths.ECToConfSuccess);
- fs.Close();
- return true;
- }
- catch
- {
- FileStream fs = File.Create(Paths.ECToConfFail);
- fs.Close();
- return false;
- }
+ FileStream fs = File.Create(Paths.ECToConfSuccess);
+ fs.Close();
+ return true;
}
-
- ///
- /// Gets the computer model name from registry.
- ///
- ///
- /// The computer model if the function succeeds,
- /// otherwise null.
- ///
- private static string GetPCModel()
+ catch
{
- return GetBIOSRegValue("SystemProductName");
+ FileStream fs = File.Create(Paths.ECToConfFail);
+ fs.Close();
+ return false;
}
+ }
- ///
- /// Gets the computer manufacturer from registry.
- ///
- ///
- /// The computer manufacturer if the function succeeds,
- /// otherwise null.
- ///
- private static string GetPCManufacturer()
- {
- return GetBIOSRegValue("SystemManufacturer");
- }
+ ///
+ /// Gets the computer model name from registry.
+ ///
+ ///
+ /// The computer model if the function succeeds,
+ /// otherwise null.
+ ///
+ private static string GetPCModel()
+ {
+ return GetBIOSRegValue("SystemProductName");
+ }
+
+ ///
+ /// Gets the computer manufacturer from registry.
+ ///
+ ///
+ /// The computer manufacturer if the function succeeds,
+ /// otherwise null.
+ ///
+ private static string GetPCManufacturer()
+ {
+ return GetBIOSRegValue("SystemManufacturer");
+ }
- private static string GetBIOSRegValue(string name)
+ private static string GetBIOSRegValue(string name)
+ {
+ RegistryKey biosKey = Registry.LocalMachine.OpenSubKey(@"HARDWARE\DESCRIPTION\System\BIOS");
+ try
{
- RegistryKey biosKey = Registry.LocalMachine.OpenSubKey(@"HARDWARE\DESCRIPTION\System\BIOS");
- try
- {
- return (string)biosKey?.GetValue(name, null);
- }
- finally
- {
- biosKey?.Close();
- }
+ return (string)biosKey?.GetValue(name, null);
}
-
- private static string GetWin32Error(int error)
+ finally
{
- return new Win32Exception(error).Message;
+ biosKey?.Close();
}
}
+
+ private static string GetWin32Error(int error)
+ {
+ return new Win32Exception(error).Message;
+ }
}
diff --git a/YAMDCC.Service/Program.cs b/YAMDCC.Service/Program.cs
index c4f39ed..5ad8da7 100644
--- a/YAMDCC.Service/Program.cs
+++ b/YAMDCC.Service/Program.cs
@@ -20,48 +20,47 @@
using YAMDCC.Common;
using YAMDCC.Logs;
-namespace YAMDCC.Service
+namespace YAMDCC.Service;
+
+internal static class Program
{
- internal static class Program
+ ///
+ /// The instance to write logs to.
+ ///
+ private static readonly Logger Log = new()
{
- ///
- /// The instance to write logs to.
- ///
- private static readonly Logger Log = new()
- {
- LogDir = Paths.Logs,
- ConsoleLogLevel = LogLevel.None,
- FileLogLevel = LogLevel.Debug,
- };
+ LogDir = Paths.Logs,
+ ConsoleLogLevel = LogLevel.None,
+ FileLogLevel = LogLevel.Debug,
+ };
- ///
- /// The main entry point for the application.
- ///
- private static void Main()
+ ///
+ /// The main entry point for the application.
+ ///
+ private static void Main()
+ {
+ AppDomain.CurrentDomain.UnhandledException += static (sender, e) =>
+ Log.Fatal(Strings.GetString("svcException"), e.ExceptionObject);
+
+ if (Environment.UserInteractive)
{
- AppDomain.CurrentDomain.UnhandledException += static (sender, e) =>
- Log.Fatal(Strings.GetString("svcException"), e.ExceptionObject);
+ MessageBox.Show(Strings.GetString("errDirectRun"),
+ "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ else
+ {
+ CommonConfig cfg = CommonConfig.Load();
+ Log.Info(
+ $"OS version: {Environment.OSVersion}\n" +
+ $"Service version: {Application.ProductVersion}");
- if (Environment.UserInteractive)
+ if (cfg.App == "YAMDCC")
{
- MessageBox.Show(Strings.GetString("errDirectRun"),
- "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ Log.FileLogLevel = cfg.LogLevel;
}
- else
- {
- CommonConfig cfg = CommonConfig.Load();
- Log.Info(
- $"OS version: {Environment.OSVersion}\n" +
- $"Service version: {Application.ProductVersion}");
- if (cfg.App == "YAMDCC")
- {
- Log.FileLogLevel = cfg.LogLevel;
- }
-
- Log.Debug("Log level is set to debug mode.");
- ServiceBase.Run(new FanControlService(Log));
- }
+ Log.Debug("Log level is set to debug mode.");
+ ServiceBase.Run(new FanControlService(Log));
}
}
}
diff --git a/YAMDCC.Service/ProjectInstaller.cs b/YAMDCC.Service/ProjectInstaller.cs
index a0179cc..4cf83d7 100644
--- a/YAMDCC.Service/ProjectInstaller.cs
+++ b/YAMDCC.Service/ProjectInstaller.cs
@@ -18,31 +18,30 @@
using System.Configuration.Install;
using System.ServiceProcess;
-namespace YAMDCC.Service
+namespace YAMDCC.Service;
+
+[RunInstaller(true)]
+public class ProjectInstaller : Installer
{
- [RunInstaller(true)]
- public class ProjectInstaller : Installer
+ public ProjectInstaller()
{
- public ProjectInstaller()
+ ServiceInstaller svcInstaller = new()
{
- ServiceInstaller svcInstaller = new()
- {
- Description = Strings.GetString("svcDesc"),
- DisplayName = "YAMDCC Service",
- ServiceName = "yamdccsvc",
- StartType = ServiceStartMode.Automatic
- };
+ Description = Strings.GetString("svcDesc"),
+ DisplayName = "YAMDCC Service",
+ ServiceName = "yamdccsvc",
+ StartType = ServiceStartMode.Automatic
+ };
- ServiceProcessInstaller svcPInstaller = new()
- {
- Account = ServiceAccount.LocalSystem
- };
+ ServiceProcessInstaller svcPInstaller = new()
+ {
+ Account = ServiceAccount.LocalSystem
+ };
- Installers.AddRange(
- [
- svcPInstaller,
- svcInstaller
- ]);
- }
+ Installers.AddRange(
+ [
+ svcPInstaller,
+ svcInstaller
+ ]);
}
}
diff --git a/YAMDCC.Service/Strings.cs b/YAMDCC.Service/Strings.cs
index ade5758..d39e6b9 100644
--- a/YAMDCC.Service/Strings.cs
+++ b/YAMDCC.Service/Strings.cs
@@ -17,67 +17,66 @@
using System.Globalization;
using System.Resources;
-namespace YAMDCC.Service
+namespace YAMDCC.Service;
+
+///
+/// A resource class for retrieving strings.
+///
+internal static class Strings
{
+ private static ResourceManager resMan;
+
///
- /// A resource class for retrieving strings.
+ /// Gets a string from the underlying resource file.
///
- internal static class Strings
+ ///
+ /// This function internally calls
+ /// to retrieve the string.
+ ///
+ ///
+ /// The name of the string to find.
+ ///
+ ///
+ /// The value of the specified string name, if found.
+ /// null if the string couldn't be found.
+ ///
+ public static string GetString(string name)
{
- private static ResourceManager resMan;
-
- ///
- /// Gets a string from the underlying resource file.
- ///
- ///
- /// This function internally calls
- /// to retrieve the string.
- ///
- ///
- /// The name of the string to find.
- ///
- ///
- /// The value of the specified string name, if found.
- /// null if the string couldn't be found.
- ///
- public static string GetString(string name)
- {
- resMan ??= new ResourceManager(typeof(Strings));
- return resMan.GetString(name, CultureInfo.InvariantCulture);
- }
+ resMan ??= new ResourceManager(typeof(Strings));
+ return resMan.GetString(name, CultureInfo.InvariantCulture);
+ }
- ///
- /// Gets a string from the underlying resource file, and replaces format
- /// items with the specified object's string representation.
- ///
- ///
- /// The name of the string to find.
- ///
- ///
- /// The object to format the string with.
- ///
- ///
- /// The formatted string corresponding to the specified string name, if found.
- /// null if the string couldn't be found.
- ///
- public static string GetString(string name, object arg0)
- {
- string temp = GetString(name);
- return temp is null
- ? null
- : string.Format(CultureInfo.InvariantCulture, temp, arg0);
- }
+ ///
+ /// Gets a string from the underlying resource file, and replaces format
+ /// items with the specified object's string representation.
+ ///
+ ///
+ /// The name of the string to find.
+ ///
+ ///
+ /// The object to format the string with.
+ ///
+ ///
+ /// The formatted string corresponding to the specified string name, if found.
+ /// null if the string couldn't be found.
+ ///
+ public static string GetString(string name, object arg0)
+ {
+ string temp = GetString(name);
+ return temp is null
+ ? null
+ : string.Format(CultureInfo.InvariantCulture, temp, arg0);
+ }
- ///
- ///
- /// The objects to format the string with.
- ///
- public static string GetString(string name, params object[] args)
- {
- string temp = GetString(name);
- return temp is null
- ? null
- : string.Format(CultureInfo.InvariantCulture, temp, args);
- }
+ ///
+ ///
+ /// The objects to format the string with.
+ ///
+ public static string GetString(string name, params object[] args)
+ {
+ string temp = GetString(name);
+ return temp is null
+ ? null
+ : string.Format(CultureInfo.InvariantCulture, temp, args);
}
}