Added support for setting the number threads in the GUI + some improvements application configuration handling.

This commit is contained in:
LoRd_MuldeR 2022-04-03 14:58:59 +02:00
parent 7359ce3673
commit 45829c4317
Signed by: mulder
GPG Key ID: 2B5913365F57E03F
7 changed files with 146 additions and 43 deletions

View File

@ -55,6 +55,11 @@ The following settings can be adjusted in the `slunkcrypt-gui.exe.config` config
- **`DisableBusyIndicator`:** - **`DisableBusyIndicator`:**
If set to `true`, the “busy indicator” animation will be *disabled* on application startup — default value: `false`. If set to `true`, the “busy indicator” animation will be *disabled* on application startup — default value: `false`.
- **`ThreadCount`:**
Specifies the number of worker threads to use — default value: `0` (i.e. detect the number of available processors and create one thread for each processor).
- **`KeepIncompleteFiles`:**
If set to `true`, incomplete or corrupted output files will *not* be deleted — default value: `false`.
Command-line Usage Command-line Usage
================== ==================

View File

@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<startup> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/>
</startup> </startup>
<appSettings> <appSettings>
<add key="DisableBusyIndicator" value="false"/> <add key="DisableBusyIndicator" value="false"/>
<add key="ThreadCount" value="0"/>
<add key="KeepIncompleteFiles" value="false"/>
</appSettings> </appSettings>
</configuration> </configuration>

View File

@ -19,6 +19,17 @@ namespace com.muldersoft.slunkcrypt.gui.process
{ {
public enum Mode { Encrypt, Decrypt } public enum Mode { Encrypt, Decrypt }
public struct SlunkOptions
{
public SlunkOptions(bool keepIncompleteFiles, int threadCount)
{
this.keepIncompleteFiles = keepIncompleteFiles;
this.threadCount = threadCount;
}
public readonly bool keepIncompleteFiles;
public readonly int threadCount;
}
private const string COMMAND_ENCRYPT = "-e"; private const string COMMAND_ENCRYPT = "-e";
private const string COMMAND_DECRYPT = "-d"; private const string COMMAND_DECRYPT = "-d";
@ -39,12 +50,13 @@ namespace com.muldersoft.slunkcrypt.gui.process
// Public methods // Public methods
// ============================================================================= // =============================================================================
public async Task<int> ExecuteAsync(Mode mode, string inputFile, string outputFile, string password) public async Task<int> ExecuteAsync(Mode mode, string inputFile, string outputFile, string password, SlunkOptions? options = null)
{ {
Dictionary<string, string> environmentVariables = new Dictionary<string, string>(); Dictionary<string, string> environmentVariables = new Dictionary<string, string>();
environmentVariables.Add("SLUNK_PASSPHRASE", password); environmentVariables.Add("SLUNK_PASSPHRASE", password);
string[] arguments = new string[] { GetCommandString(mode), inputFile, outputFile }; environmentVariables.Add("SLUNK_KEEP_INCOMPLETE", Convert.ToInt32(options.HasValue ? options.Value.keepIncompleteFiles : false).ToString());
return await ExecAsnyc(m_executableFile.Name, arguments, environmentVariables); environmentVariables.Add("SLUNK_THREADS", Math.Max(0, Math.Min(32, options.HasValue ? options.Value.threadCount : 0)).ToString());
return await ExecAsnyc(m_executableFile.Name, new string[] { GetCommandLineModeString(mode), inputFile, outputFile }, environmentVariables);
} }
public override void Dispose() public override void Dispose()
@ -94,7 +106,7 @@ namespace com.muldersoft.slunkcrypt.gui.process
return false; return false;
} }
private static string GetCommandString(Mode mode) private static string GetCommandLineModeString(Mode mode)
{ {
switch(mode) switch(mode)
{ {

View File

@ -556,8 +556,11 @@ namespace com.muldersoft.slunkcrypt.gui
Button_Decrypt_Toggle.IsChecked = Button_Encrypt_Toggle.IsChecked = m_checksumError = m_processReceived = false; Button_Decrypt_Toggle.IsChecked = Button_Encrypt_Toggle.IsChecked = m_checksumError = m_processReceived = false;
if (!await processor(inputFile, outputFile, password)) if (!await processor(inputFile, outputFile, password))
{ {
if (!m_config.KeepIncompleteFiles)
{
PathUtils.TryRemoveFile(outputFile);
}
SetProgress(double.NaN, true); SetProgress(double.NaN, true);
PathUtils.TryRemoveFile(outputFile);
} }
await Task.Yield(); await Task.Yield();
} }
@ -624,12 +627,13 @@ namespace com.muldersoft.slunkcrypt.gui
} }
try try
{ {
SlunkCryptRunner.SlunkOptions options = new SlunkCryptRunner.SlunkOptions(m_config.KeepIncompleteFiles, m_config.ThreadCount);
using (m_processRunner = new SlunkCryptRunner(Dispatcher)) using (m_processRunner = new SlunkCryptRunner(Dispatcher))
{ {
m_processRunner.OutputAvailable += Process_OutputAvailable; m_processRunner.OutputAvailable += Process_OutputAvailable;
m_processRunner.ProgressChanged += Porcess_ProgressChanged; m_processRunner.ProgressChanged += Porcess_ProgressChanged;
SetProcessPriority(ProcessPriorityClass.AboveNormal); SetProcessPriority(ProcessPriorityClass.AboveNormal);
return await m_processRunner.ExecuteAsync(mode, inputFile, outputFile, password); return await m_processRunner.ExecuteAsync(mode, inputFile, outputFile, password, options);
} }
} }
catch (ProcessRunner.ProcessStartException err) catch (ProcessRunner.ProcessStartException err)

View File

@ -4,62 +4,138 @@
/******************************************************************************/ /******************************************************************************/
using System; using System;
using System.Collections.Concurrent;
using System.Configuration; using System.Configuration;
using System.Threading;
namespace com.muldersoft.slunkcrypt.gui.utils namespace com.muldersoft.slunkcrypt.gui.utils
{ {
class ApplicationConfig class ApplicationConfig
{ {
private readonly Lazy<KeyValueConfigurationCollection> m_settings = new Lazy<KeyValueConfigurationCollection>(InitializeSettings); private readonly ConcurrentDictionary<string, int> m_cache = new ConcurrentDictionary<string, int>();
public bool DisableBusyIndicator public bool DisableBusyIndicator
{ {
get get
{ {
return GetConfigValueAsBool("DisableBusyIndicator"); return ComputeIfAbsent("DisableBusyIndicator", (key) => AppConfHelper.GetConfigValueAsBool(key).GetValueOrDefault(false));
}
}
public bool KeepIncompleteFiles
{
get
{
return ComputeIfAbsent("KeepIncompleteFiles", (key) => AppConfHelper.GetConfigValueAsBool(key).GetValueOrDefault(false));
} }
} }
protected string GetConfigValue(string name) public int ThreadCount
{ {
KeyValueConfigurationCollection settings = m_settings.Value; get
if (!ReferenceEquals(settings, null))
{ {
KeyValueConfigurationElement element = settings[name]; return ComputeIfAbsent("ThreadCount", (key) => AppConfHelper.GetConfigValueAsInt32(key).GetValueOrDefault(0));
if (!ReferenceEquals(element, null)) }
}
// =============================================================================
// Internal methods
// =============================================================================
protected int ComputeIfAbsent(string name, Func<string, int> valueFactory)
{
return m_cache.GetOrAdd(name, valueFactory);
}
protected bool ComputeIfAbsent(string name, Func<string, bool> valueFactory)
{
return Convert.ToBoolean(m_cache.GetOrAdd(name, (key) => Convert.ToInt32(valueFactory(key))));
}
// =============================================================================
// Helper class
// =============================================================================
private static class AppConfHelper
{
private static readonly Lazy<KeyValueConfigurationCollection> m_settings = new Lazy<KeyValueConfigurationCollection>(InitializeSettings, LazyThreadSafetyMode.ExecutionAndPublication);
private static volatile object m_syncRoot;
public static string GetConfigValue(string name)
{
KeyValueConfigurationCollection settings = m_settings.Value;
if (!ReferenceEquals(settings, null))
{ {
string value = element.Value; lock (settings.SyncRoot ?? SyncRootInstance)
return string.IsNullOrWhiteSpace(value) ? string.Empty : value; {
try
{
KeyValueConfigurationElement element = settings[name];
if (!ReferenceEquals(element, null))
{
string value = element.Value;
return string.IsNullOrWhiteSpace(value) ? string.Empty : value;
}
}
catch { }
}
} }
return string.Empty;
} }
return string.Empty;
}
protected bool GetConfigValueAsBool(string name) public static bool? GetConfigValueAsBool(string name)
{
string value;
if (!string.IsNullOrWhiteSpace(value = GetConfigValue(name)))
{ {
bool result; string value;
if (bool.TryParse(value.Trim(), out result)) if (!string.IsNullOrWhiteSpace(value = GetConfigValue(name)))
{ {
return result; bool result;
if (bool.TryParse(value.Trim(), out result))
{
return result;
}
} }
}
return false;
}
private static KeyValueConfigurationCollection InitializeSettings()
{
try
{
Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
return configuration.AppSettings.Settings;
}
catch
{
return null; return null;
} }
public static int? GetConfigValueAsInt32(string name)
{
string value;
if (!string.IsNullOrWhiteSpace(value = GetConfigValue(name)))
{
int result;
if (int.TryParse(value.Trim(), out result))
{
return result;
}
}
return null;
}
private static KeyValueConfigurationCollection InitializeSettings()
{
try
{
Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
return configuration.AppSettings.Settings;
}
catch
{
return null;
}
}
private static object SyncRootInstance
{
get
{
if (m_syncRoot == null)
{
Interlocked.CompareExchange<object>(ref m_syncRoot, new object(), null);
}
return m_syncRoot;
}
}
} }
} }
} }

View File

@ -226,7 +226,7 @@ namespace com.muldersoft.slunkcrypt.gui.utils
{ {
process.StartInfo.FileName = executablePath; process.StartInfo.FileName = executablePath;
process.StartInfo.Arguments = CreateArgumentList(arguments); process.StartInfo.Arguments = CreateArgumentList(arguments);
SetupEnvironment(process.StartInfo.EnvironmentVariables, environmentVariables); SetupEnvironment(process.StartInfo.EnvironmentVariables, executablePath, environmentVariables);
process.StartInfo.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory; process.StartInfo.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory;
process.Start(); process.Start();
SetProcessPriority(process, priorityClass); SetProcessPriority(process, priorityClass);
@ -390,13 +390,15 @@ namespace com.muldersoft.slunkcrypt.gui.utils
return false; return false;
} }
private static void SetupEnvironment(StringDictionary dictionary, IReadOnlyDictionary<string, string> environmentVariables) private static void SetupEnvironment(StringDictionary dictionary, string executablePath, IReadOnlyDictionary<string, string> environmentVariables)
{ {
string baseDirectory = Path.GetDirectoryName(executablePath);
dictionary["PATH"] = string.IsNullOrEmpty(baseDirectory) ? Environment.SystemDirectory : baseDirectory;
if (!ReferenceEquals(environmentVariables, null)) if (!ReferenceEquals(environmentVariables, null))
{ {
foreach (KeyValuePair<string, string> entry in environmentVariables) foreach (KeyValuePair<string, string> entry in environmentVariables)
{ {
dictionary.Add(entry.Key, entry.Value); dictionary[entry.Key] = entry.Value;
} }
} }
} }

View File

@ -15,6 +15,7 @@
/* CRT */ /* CRT */
#include <stdlib.h> #include <stdlib.h>
#include <errno.h>
#include <string.h> #include <string.h>
/* PThread */ /* PThread */
@ -80,9 +81,10 @@ static INLINE size_t BOUND(const size_t min, const size_t value, const size_t ma
#define PTHRD_MUTEX_ENTER(X) do \ #define PTHRD_MUTEX_ENTER(X) do \
{ \ { \
if (pthread_mutex_lock((X)) != 0) \ int _retval; \
while ((_retval = pthread_mutex_trylock((X))) != 0) \
{ \ { \
abort(); \ if (_retval != EBUSY) { abort(); } \
} \ } \
} \ } \
while(0) while(0)