StyleCop enabled.

This commit is contained in:
Clint Rutkas 2021-05-11 10:22:29 -07:00
parent 7cf1c64575
commit e195c42f17
4 changed files with 165 additions and 137 deletions

View file

@ -2,13 +2,13 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Win32;
using NLog;
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Win32;
using NLog;
namespace Espresso.Shell.Core
{
@ -18,7 +18,7 @@ namespace Espresso.Shell.Core
ES_AWAYMODE_REQUIRED = 0x00000040,
ES_CONTINUOUS = 0x80000000,
ES_DISPLAY_REQUIRED = 0x00000002,
ES_SYSTEM_REQUIRED = 0x00000001
ES_SYSTEM_REQUIRED = 0x00000001,
}
/// <summary>
@ -27,16 +27,15 @@ namespace Espresso.Shell.Core
/// </summary>
public class APIHelper
{
private const string BUILD_REGISTRY_LOCATION = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion";
private const string BuildRegistryLocation = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion";
private static CancellationTokenSource TokenSource;
private static CancellationToken ThreadToken;
private static readonly Logger log;
private static readonly Logger _log;
private static CancellationTokenSource _tokenSource;
private static CancellationToken _threadToken;
// More details about the API used: https://docs.microsoft.com/windows/win32/api/winbase/nf-winbase-setthreadexecutionstate
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
private static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
// More details about the API used: https://docs.microsoft.com/windows/win32/api/shellapi/nf-shellapi-extracticonexw
[DllImport("Shell32.dll", EntryPoint = "ExtractIconExW", CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
@ -44,8 +43,8 @@ namespace Espresso.Shell.Core
static APIHelper()
{
log = LogManager.GetCurrentClassLogger();
TokenSource = new CancellationTokenSource();
_log = LogManager.GetCurrentClassLogger();
_tokenSource = new CancellationTokenSource();
}
/// <summary>
@ -60,23 +59,14 @@ namespace Espresso.Shell.Core
try
{
var stateResult = SetThreadExecutionState(state);
bool stateSettingSucceeded = (stateResult != 0);
if (stateSettingSucceeded)
{
return true;
}
else
{
return false;
}
return stateResult != 0;
}
catch
{
return false;
}
}
/// <summary>
/// Attempts to reset the current machine state to one where Espresso doesn't try to keep it awake.
/// This does not interfere with the state that can be potentially set by other applications.
@ -84,7 +74,7 @@ namespace Espresso.Shell.Core
/// <returns>Status of the attempt. True is successful, false if not.</returns>
public static bool SetNormalKeepAwake()
{
TokenSource.Cancel();
_tokenSource.Cancel();
return SetAwakeState(EXECUTION_STATE.ES_CONTINUOUS);
}
@ -102,18 +92,17 @@ namespace Espresso.Shell.Core
else
{
return SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
}
}
}
public static void SetTimedKeepAwake(long seconds, Action<bool> callback, Action failureCallback, bool keepDisplayOn = true)
{
TokenSource = new CancellationTokenSource();
ThreadToken = TokenSource.Token;
_tokenSource = new CancellationTokenSource();
_threadToken = _tokenSource.Token;
Task.Run(() => RunTimedLoop(seconds, keepDisplayOn), ThreadToken)
Task.Run(() => RunTimedLoop(seconds, keepDisplayOn), _threadToken)
.ContinueWith((result) => callback(result.Result), TaskContinuationOptions.OnlyOnRanToCompletion)
.ContinueWith((result) => failureCallback, TaskContinuationOptions.NotOnRanToCompletion); ;
.ContinueWith((result) => failureCallback, TaskContinuationOptions.NotOnRanToCompletion);
}
private static bool RunTimedLoop(long seconds, bool keepDisplayOn = true)
@ -121,7 +110,7 @@ namespace Espresso.Shell.Core
bool success = false;
// In case cancellation was already requested.
ThreadToken.ThrowIfCancellationRequested();
_threadToken.ThrowIfCancellationRequested();
try
{
if (keepDisplayOn)
@ -129,20 +118,21 @@ namespace Espresso.Shell.Core
success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
if (success)
{
log.Info("Timed keep-awake with display on.");
_log.Info("Timed keep-awake with display on.");
var startTime = DateTime.UtcNow;
while (DateTime.UtcNow - startTime < TimeSpan.FromSeconds(seconds))
{
if (ThreadToken.IsCancellationRequested)
if (_threadToken.IsCancellationRequested)
{
ThreadToken.ThrowIfCancellationRequested();
_threadToken.ThrowIfCancellationRequested();
}
}
return success;
}
else
{
log.Info("Could not set up timed keep-awake with display on.");
_log.Info("Could not set up timed keep-awake with display on.");
return success;
}
}
@ -151,20 +141,21 @@ namespace Espresso.Shell.Core
success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
if (success)
{
log.Info("Timed keep-awake with display off.");
_log.Info("Timed keep-awake with display off.");
var startTime = DateTime.UtcNow;
while (DateTime.UtcNow - startTime < TimeSpan.FromSeconds(seconds))
{
if (ThreadToken.IsCancellationRequested)
if (_threadToken.IsCancellationRequested)
{
ThreadToken.ThrowIfCancellationRequested();
_threadToken.ThrowIfCancellationRequested();
}
}
return success;
}
else
{
log.Info("Could not set up timed keep-awake with display off.");
_log.Info("Could not set up timed keep-awake with display off.");
return success;
}
}
@ -172,7 +163,7 @@ namespace Espresso.Shell.Core
catch (OperationCanceledException ex)
{
// Task was clearly cancelled.
log.Info($"Background thread termination. Message: {ex.Message}");
_log.Info($"Background thread termination. Message: {ex.Message}");
return success;
}
}
@ -182,7 +173,7 @@ namespace Espresso.Shell.Core
try
{
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(BUILD_REGISTRY_LOCATION);
RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(BuildRegistryLocation);
#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type.
if (registryKey != null)
@ -192,18 +183,17 @@ namespace Espresso.Shell.Core
}
else
{
log.Debug("Registry key acquisition for OS failed.");
_log.Debug("Registry key acquisition for OS failed.");
return string.Empty;
}
}
catch (Exception ex)
{
log.Debug($"Could not get registry key for the build number. Error: {ex.Message}");
_log.Debug($"Could not get registry key for the build number. Error: {ex.Message}");
return string.Empty;
}
}
public static Icon? Extract(string file, int number, bool largeIcon)
{
ExtractIconEx(file, number, out IntPtr large, out IntPtr small, 1);
@ -215,8 +205,6 @@ namespace Espresso.Shell.Core
{
return null;
}
}
}
}

View file

@ -2,11 +2,11 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.PowerToys.Settings.UI.Library;
using System;
using System.Drawing;
using System.Text.Json;
using System.Windows.Forms;
using Microsoft.PowerToys.Settings.UI.Library;
#pragma warning disable CS8602 // Dereference of a possibly null reference.
#pragma warning disable CS8603 // Possible null reference return.
@ -15,10 +15,12 @@ namespace Espresso.Shell.Core
{
internal static class TrayHelper
{
static NotifyIcon? trayIcon;
private static NotifyIcon? trayIcon;
private static NotifyIcon TrayIcon { get => trayIcon; set => trayIcon = value; }
static SettingsUtils? moduleSettings;
private static SettingsUtils? moduleSettings;
private static SettingsUtils ModuleSettings { get => moduleSettings; set => moduleSettings = value; }
static TrayHelper()
@ -29,7 +31,8 @@ namespace Espresso.Shell.Core
public static void InitializeTray(string text, Icon icon, ContextMenuStrip? contextMenu = null)
{
System.Threading.Tasks.Task.Factory.StartNew((tray) =>
System.Threading.Tasks.Task.Factory.StartNew(
(tray) =>
{
((NotifyIcon?)tray).Text = text;
((NotifyIcon?)tray).Icon = icon;
@ -42,31 +45,51 @@ namespace Espresso.Shell.Core
internal static void SetTray(string text, EspressoSettings settings)
{
SetTray(text, settings.Properties.KeepDisplayOn.Value, settings.Properties.Mode,
() => {
// Set indefinite keep awake.
var currentSettings = ModuleSettings.GetSettings<EspressoSettings>(text);
currentSettings.Properties.Mode = EspressoMode.INDEFINITE;
SetTray(
text,
settings.Properties.KeepDisplayOn.Value,
settings.Properties.Mode,
IndefiniteKeepAwakeCallback(text),
TimedKeepAwakeCallback(text),
KeepDisplayOnCallback(text));
}
ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), text);
},
(hours, minutes) => {
// Set timed keep awake.
var currentSettings = ModuleSettings.GetSettings<EspressoSettings>(text);
currentSettings.Properties.Mode = EspressoMode.TIMED;
currentSettings.Properties.Hours.Value = hours;
currentSettings.Properties.Minutes.Value = minutes;
private static Action KeepDisplayOnCallback(string text)
{
return () =>
{
// Just changing the display mode.
var currentSettings = ModuleSettings.GetSettings<EspressoSettings>(text);
currentSettings.Properties.KeepDisplayOn.Value = !currentSettings.Properties.KeepDisplayOn.Value;
ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), text);
},
() =>
{
// Just changing the display mode.
var currentSettings = ModuleSettings.GetSettings<EspressoSettings>(text);
currentSettings.Properties.KeepDisplayOn.Value = !currentSettings.Properties.KeepDisplayOn.Value;
ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), text);
};
}
ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), text);
});
private static Action<int, int> TimedKeepAwakeCallback(string text)
{
return (hours, minutes) =>
{
// Set timed keep awake.
var currentSettings = ModuleSettings.GetSettings<EspressoSettings>(text);
currentSettings.Properties.Mode = EspressoMode.TIMED;
currentSettings.Properties.Hours.Value = hours;
currentSettings.Properties.Minutes.Value = minutes;
ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), text);
};
}
private static Action IndefiniteKeepAwakeCallback(string text)
{
return () =>
{
// Set indefinite keep awake.
var currentSettings = ModuleSettings.GetSettings<EspressoSettings>(text);
currentSettings.Properties.Mode = EspressoMode.INDEFINITE;
ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), text);
};
}
internal static void SetTray(string text, bool keepDisplayOn, EspressoMode mode, Action indefiniteKeepAwakeCallback, Action<int, int> timedKeepAwakeCallback, Action keepDisplayOnCallback)
@ -76,13 +99,13 @@ namespace Espresso.Shell.Core
// Main toolstrip.
var operationContextMenu = new ToolStripMenuItem
{
Text = "Mode"
Text = "Mode",
};
// Indefinite keep-awake menu item.
var indefiniteMenuItem = new ToolStripMenuItem
{
Text = "Indefinite"
Text = "Indefinite",
};
if (mode == EspressoMode.INDEFINITE)
@ -93,6 +116,7 @@ namespace Espresso.Shell.Core
{
indefiniteMenuItem.Checked = false;
}
indefiniteMenuItem.Click += (e, s) =>
{
// User opted to set the mode to indefinite, so we need to write new settings.
@ -101,7 +125,7 @@ namespace Espresso.Shell.Core
var displayOnMenuItem = new ToolStripMenuItem
{
Text = "Keep display on"
Text = "Keep display on",
};
if (keepDisplayOn)
{
@ -111,6 +135,7 @@ namespace Espresso.Shell.Core
{
displayOnMenuItem.Checked = false;
}
displayOnMenuItem.Click += (e, s) =>
{
// User opted to set the display mode directly.
@ -120,12 +145,12 @@ namespace Espresso.Shell.Core
// Timed keep-awake menu item
var timedMenuItem = new ToolStripMenuItem
{
Text = "Timed"
Text = "Timed",
};
var halfHourMenuItem = new ToolStripMenuItem
{
Text = "30 minutes"
Text = "30 minutes",
};
halfHourMenuItem.Click += (e, s) =>
{
@ -135,7 +160,7 @@ namespace Espresso.Shell.Core
var oneHourMenuItem = new ToolStripMenuItem
{
Text = "1 hour"
Text = "1 hour",
};
oneHourMenuItem.Click += (e, s) =>
{
@ -145,7 +170,7 @@ namespace Espresso.Shell.Core
var twoHoursMenuItem = new ToolStripMenuItem
{
Text = "2 hours"
Text = "2 hours",
};
twoHoursMenuItem.Click += (e, s) =>
{

View file

@ -60,5 +60,19 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\codeAnalysis\GlobalSuppressions.cs">
<Link>GlobalSuppressions.cs</Link>
</Compile>
<AdditionalFiles Include="..\..\..\codeAnalysis\StyleCop.json">
<Link>StyleCop.json</Link>
</AdditionalFiles>
</ItemGroup>
<ItemGroup>
<PackageReference Include="StyleCop.Analyzers">
<Version>1.1.118</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project>

View file

@ -2,10 +2,6 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Espresso.Shell.Core;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using NLog;
using System;
using System.CommandLine;
using System.CommandLine.Invocation;
@ -16,40 +12,44 @@ using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Reflection;
using System.Threading;
using Espresso.Shell.Core;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using NLog;
#pragma warning disable CS8602 // Dereference of a possibly null reference.
#pragma warning disable CS8603 // Possible null reference return.
namespace Espresso.Shell
{
class Program
internal class Program
{
private static Mutex? mutex = null;
private const string appName = "Espresso";
private static FileSystemWatcher? watcher = null;
private static SettingsUtils? settingsUtils = null;
private static Mutex? _mutex = null;
private const string AppName = "Espresso";
private static FileSystemWatcher? _watcher = null;
private static SettingsUtils? _settingsUtils = null;
public static Mutex Mutex { get => mutex; set => mutex = value; }
public static Mutex LockMutex { get => _mutex; set => _mutex = value; }
private static Logger? log;
private static Logger? _log;
static int Main(string[] args)
private static int Main(string[] args)
{
bool instantiated;
Mutex = new Mutex(true, appName, out instantiated);
LockMutex = new Mutex(true, AppName, out instantiated);
if (!instantiated)
{
ForceExit(appName + " is already running! Exiting the application.", 1);
ForceExit(AppName + " is already running! Exiting the application.", 1);
}
log = LogManager.GetCurrentClassLogger();
settingsUtils = new SettingsUtils();
_log = LogManager.GetCurrentClassLogger();
_settingsUtils = new SettingsUtils();
log.Info("Launching Espresso...");
log.Info(FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion);
log.Debug($"OS: {Environment.OSVersion}");
log.Debug($"OS Build: {APIHelper.GetOperatingSystemBuild()}");
_log.Info("Launching Espresso...");
_log.Info(FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion);
_log.Debug($"OS: {Environment.OSVersion}");
_log.Debug($"OS Build: {APIHelper.GetOperatingSystemBuild()}");
var configOption = new Option<bool>(
aliases: new[] { "--use-pt-config", "-c" },
@ -108,10 +108,10 @@ namespace Espresso.Shell
configOption,
displayOption,
timeOption,
pidOption
pidOption,
};
rootCommand.Description = appName;
rootCommand.Description = AppName;
rootCommand.Handler = CommandHandler.Create<bool, bool, long, int>(HandleCommandLineArguments);
@ -120,21 +120,21 @@ namespace Espresso.Shell
private static void ForceExit(string message, int exitCode)
{
log.Debug(message);
log.Info(message);
_log.Debug(message);
_log.Info(message);
Console.ReadKey();
Environment.Exit(exitCode);
}
private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, long timeLimit, int pid)
{
log.Info($"The value for --use-pt-config is: {usePtConfig}");
log.Info($"The value for --display-on is: {displayOn}");
log.Info($"The value for --time-limit is: {timeLimit}");
log.Info($"The value for --pid is: {pid}");
_log.Info($"The value for --use-pt-config is: {usePtConfig}");
_log.Info($"The value for --display-on is: {displayOn}");
_log.Info($"The value for --time-limit is: {timeLimit}");
_log.Info($"The value for --pid is: {pid}");
#pragma warning disable CS8604 // Possible null reference argument.
TrayHelper.InitializeTray(appName, APIHelper.Extract("shell32.dll", 32, true));
TrayHelper.InitializeTray(AppName, APIHelper.Extract("shell32.dll", 32, true));
#pragma warning restore CS8604 // Possible null reference argument.
if (usePtConfig)
@ -143,21 +143,20 @@ namespace Espresso.Shell
// and instead watch for changes in the file.
try
{
var settingsPath = settingsUtils.GetSettingsFilePath(appName);
log.Info($"Reading configuration file: {settingsPath}");
var settingsPath = _settingsUtils.GetSettingsFilePath(AppName);
_log.Info($"Reading configuration file: {settingsPath}");
watcher = new FileSystemWatcher
_watcher = new FileSystemWatcher
{
Path = Path.GetDirectoryName(settingsPath),
EnableRaisingEvents = true,
NotifyFilter = NotifyFilters.LastWrite,
Filter = Path.GetFileName(settingsPath)
Filter = Path.GetFileName(settingsPath),
};
Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
h => watcher.Changed += h,
h => watcher.Changed -= h
)
h => _watcher.Changed += h,
h => _watcher.Changed -= h)
.SubscribeOn(TaskPoolScheduler.Default)
.Select(e => e.EventArgs)
.Throttle(TimeSpan.FromMilliseconds(25))
@ -170,8 +169,8 @@ namespace Espresso.Shell
catch (Exception ex)
{
var errorString = $"There was a problem with the configuration file. Make sure it exists.\n{ex.Message}";
log.Info(errorString);
log.Debug(errorString);
_log.Info(errorString);
_log.Debug(errorString);
}
}
else
@ -204,20 +203,20 @@ namespace Espresso.Shell
bool success = APIHelper.SetIndefiniteKeepAwake(displayOn);
if (success)
{
log.Info($"Currently in indefinite keep awake. Display always on: {displayOn}");
_log.Info($"Currently in indefinite keep awake. Display always on: {displayOn}");
}
else
{
var errorMessage = "Could not set up the state to be indefinite keep awake.";
log.Info(errorMessage);
log.Debug(errorMessage);
_log.Info(errorMessage);
_log.Debug(errorMessage);
}
}
private static void HandleEspressoConfigChange(FileSystemEventArgs fileEvent)
{
log.Info("Detected a settings file change. Updating configuration...");
log.Info("Resetting keep-awake to normal state due to settings change.");
_log.Info("Detected a settings file change. Updating configuration...");
_log.Info("Resetting keep-awake to normal state due to settings change.");
ResetNormalPowerState();
ProcessSettings();
}
@ -226,7 +225,7 @@ namespace Espresso.Shell
{
try
{
EspressoSettings settings = settingsUtils.GetSettings<EspressoSettings>(appName);
EspressoSettings settings = _settingsUtils.GetSettings<EspressoSettings>(AppName);
if (settings != null)
{
@ -238,6 +237,7 @@ namespace Espresso.Shell
SetupIndefiniteKeepAwake(settings.Properties.KeepDisplayOn.Value);
break;
}
case EspressoMode.TIMED:
{
// Timed keep-awake.
@ -246,35 +246,36 @@ namespace Espresso.Shell
break;
}
default:
{
var errorMessage = "Unknown mode of operation. Check config file.";
log.Info(errorMessage);
log.Debug(errorMessage);
_log.Info(errorMessage);
_log.Debug(errorMessage);
break;
}
}
TrayHelper.SetTray(appName, settings);
TrayHelper.SetTray(AppName, settings);
}
else
{
var errorMessage = "Settings are null.";
log.Info(errorMessage);
log.Debug(errorMessage);
_log.Info(errorMessage);
_log.Debug(errorMessage);
}
}
catch (Exception ex)
{
var errorMessage = $"There was a problem reading the configuration file. Error: {ex.Message}";
log.Info(errorMessage);
log.Debug(errorMessage);
_log.Info(errorMessage);
_log.Debug(errorMessage);
}
}
private static void SetupTimedKeepAwake(long time, bool displayOn)
{
log.Info($"Timed keep-awake. Expected runtime: {time} seconds with display on setting set to {displayOn}.");
_log.Info($"Timed keep-awake. Expected runtime: {time} seconds with display on setting set to {displayOn}.");
APIHelper.SetTimedKeepAwake(time, LogTimedKeepAwakeCompletion, LogUnexpectedOrCancelledKeepAwakeCompletion, displayOn);
}
@ -282,13 +283,13 @@ namespace Espresso.Shell
private static void LogUnexpectedOrCancelledKeepAwakeCompletion()
{
var errorMessage = "The keep-awake thread was terminated early.";
log.Info(errorMessage);
log.Debug(errorMessage);
_log.Info(errorMessage);
_log.Debug(errorMessage);
}
private static void LogTimedKeepAwakeCompletion(bool result)
{
log.Info($"Completed timed keep-awake successfully: {result}");
_log.Info($"Completed timed keep-awake successfully: {result}");
}
private static void ResetNormalPowerState()
@ -296,13 +297,13 @@ namespace Espresso.Shell
bool success = APIHelper.SetNormalKeepAwake();
if (success)
{
log.Info("Returned to normal keep-awake state.");
_log.Info("Returned to normal keep-awake state.");
}
else
{
var errorMessage = "Could not return to normal keep-awake state.";
log.Info(errorMessage);
log.Debug(errorMessage);
_log.Info(errorMessage);
_log.Debug(errorMessage);
}
}
}