diff --git a/src/modules/espresso/Espresso/Core/APIHelper.cs b/src/modules/espresso/Espresso/Core/APIHelper.cs index 54a6bb3b8b..da437f0204 100644 --- a/src/modules/espresso/Espresso/Core/APIHelper.cs +++ b/src/modules/espresso/Espresso/Core/APIHelper.cs @@ -3,12 +3,15 @@ // See the LICENSE file in the project root for more information. using System; +using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Microsoft.Win32; using NLog; +#pragma warning disable SA1116 // Split parameters should start on line after declaration + namespace Espresso.Shell.Core { [Flags] @@ -27,6 +30,11 @@ namespace Espresso.Shell.Core public class APIHelper { private const string BuildRegistryLocation = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion"; + public const int StdOutputHandle = -11; + public const int StdInputHandle = -10; + public const int StdErrorHandle = -12; + public const uint GenericWrite = 0x40000000; + public const uint GenericRead = 0x80000000; private static readonly Logger _log; private static CancellationTokenSource _tokenSource; @@ -36,12 +44,45 @@ namespace Espresso.Shell.Core [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags); + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool AllocConsole(); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr GetStdHandle(int nStdHandle); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + + public static extern IntPtr CreateFile([MarshalAs(UnmanagedType.LPTStr)] string filename, + [MarshalAs(UnmanagedType.U4)] uint access, + [MarshalAs(UnmanagedType.U4)] FileShare share, + IntPtr securityAttributes, + [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, + [MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes, + IntPtr templateFile); + static APIHelper() { _log = LogManager.GetCurrentClassLogger(); _tokenSource = new CancellationTokenSource(); } + public static void AllocateConsole() + { + AllocConsole(); + + var outputHandle = GetStdHandle(StdOutputHandle); + var outputFilePointer = CreateFile("CONOUT$", GenericRead | GenericWrite, FileShare.Write, IntPtr.Zero, FileMode.OpenOrCreate, 0, IntPtr.Zero); + if (outputFilePointer != outputHandle) + { + SetStdHandle(StdOutputHandle, outputFilePointer); + Console.SetOut(new StreamWriter(Console.OpenStandardOutput(), Console.OutputEncoding) { AutoFlush = true }); + } + } + /// /// Sets the computer awake state using the native Win32 SetThreadExecutionState API. This /// function is just a nice-to-have wrapper that helps avoid tracking the success or failure of diff --git a/src/modules/espresso/Espresso/Core/TrayHelper.cs b/src/modules/espresso/Espresso/Core/TrayHelper.cs index 3aea4656e4..3ec3e9aef6 100644 --- a/src/modules/espresso/Espresso/Core/TrayHelper.cs +++ b/src/modules/espresso/Espresso/Core/TrayHelper.cs @@ -63,45 +63,45 @@ namespace Espresso.Shell.Core }; } - private static Action KeepDisplayOnCallback(string text) + private static Action KeepDisplayOnCallback(string moduleName) { return () => { // Just changing the display mode. - var currentSettings = ModuleSettings.GetSettings(text); + var currentSettings = ModuleSettings.GetSettings(moduleName); currentSettings.Properties.KeepDisplayOn.Value = !currentSettings.Properties.KeepDisplayOn.Value; - ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), text); + ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), moduleName); }; } - private static Action TimedKeepAwakeCallback(string text) + private static Action TimedKeepAwakeCallback(string moduleName) { return (hours, minutes) => { // Set timed keep awake. - var currentSettings = ModuleSettings.GetSettings(text); + var currentSettings = ModuleSettings.GetSettings(moduleName); currentSettings.Properties.Mode = EspressoMode.TIMED; currentSettings.Properties.Hours.Value = hours; currentSettings.Properties.Minutes.Value = minutes; - ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), text); + ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), moduleName); }; } - private static Action IndefiniteKeepAwakeCallback(string text) + private static Action IndefiniteKeepAwakeCallback(string moduleName) { return () => { // Set indefinite keep awake. - var currentSettings = ModuleSettings.GetSettings(text); + var currentSettings = ModuleSettings.GetSettings(moduleName); currentSettings.Properties.Mode = EspressoMode.INDEFINITE; - ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), text); + ModuleSettings.SaveSettings(JsonSerializer.Serialize(currentSettings), moduleName); }; } - internal static void SetTray(string text, bool keepDisplayOn, EspressoMode mode, Action indefiniteKeepAwakeCallback, Action timedKeepAwakeCallback, Action keepDisplayOnCallback, Action exitCallback) + public static void SetTray(string text, bool keepDisplayOn, EspressoMode mode, Action indefiniteKeepAwakeCallback, Action timedKeepAwakeCallback, Action keepDisplayOnCallback, Action exitCallback) { var contextMenuStrip = new ContextMenuStrip(); diff --git a/src/modules/espresso/Espresso/Espresso.csproj b/src/modules/espresso/Espresso/Espresso.csproj index 8ae7328e0b..7a23756ddf 100644 --- a/src/modules/espresso/Espresso/Espresso.csproj +++ b/src/modules/espresso/Espresso/Espresso.csproj @@ -1,7 +1,7 @@  - Exe + WinExe netcoreapp3.1 $(SolutionDir)$(Platform)\$(Configuration)\modules\Espresso enable diff --git a/src/modules/espresso/Espresso/Program.cs b/src/modules/espresso/Espresso/Program.cs index 6b826878cb..b7c2d79f16 100644 --- a/src/modules/espresso/Espresso/Program.cs +++ b/src/modules/espresso/Espresso/Program.cs @@ -55,10 +55,10 @@ namespace Espresso.Shell var configOption = new Option( aliases: new[] { "--use-pt-config", "-c" }, - getDefaultValue: () => true, + getDefaultValue: () => false, description: "Specifies whether Espresso will be using the PowerToys configuration file for managing the state.") { - Argument = new Argument(() => true) + Argument = new Argument(() => false) { Arity = ArgumentArity.ZeroOrOne, }, @@ -130,17 +130,22 @@ namespace Espresso.Shell private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, long timeLimit, int pid) { + if (pid == 0) + { + APIHelper.AllocateConsole(); + } + _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, new Icon(Application.GetResourceStream(new Uri("/Images/Espresso.ico", UriKind.Relative)).Stream)); -#pragma warning restore CS8604 // Possible null reference argument. - if (usePtConfig) { +#pragma warning disable CS8604 // Possible null reference argument. + TrayHelper.InitializeTray(AppName, new Icon(Application.GetResourceStream(new Uri("/Images/Espresso.ico", UriKind.Relative)).Stream)); +#pragma warning restore CS8604 // Possible null reference argument. + // Configuration file is used, therefore we disregard any other command-line parameter // and instead watch for changes in the file. try @@ -177,13 +182,14 @@ namespace Espresso.Shell } else { - if (timeLimit <= 0) + var mode = timeLimit <= 0 ? EspressoMode.INDEFINITE : EspressoMode.TIMED; + + if (mode == EspressoMode.INDEFINITE) { SetupIndefiniteKeepAwake(displayOn); } else { - // Timed keep-awake. SetupTimedKeepAwake(timeLimit, displayOn); } }