From f8c488331ed72ea213b568b8763be275ac24a749 Mon Sep 17 00:00:00 2001 From: Den Delimarsky Date: Thu, 15 Aug 2024 15:57:08 -0700 Subject: [PATCH 01/11] Update with bug fixes for tray icon and support for parent process --- doc/planning/awake.md | 17 ++++--- src/modules/awake/Awake/Core/Constants.cs | 2 +- src/modules/awake/Awake/Core/Manager.cs | 36 ++++++++++--- src/modules/awake/Awake/Core/Native/Bridge.cs | 17 ++++--- src/modules/awake/Awake/Core/TrayHelper.cs | 17 ++++--- src/modules/awake/Awake/Program.cs | 50 ++++++++++++++----- .../Awake/Properties/Resources.Designer.cs | 9 ++++ .../awake/Awake/Properties/Resources.resx | 3 ++ 8 files changed, 111 insertions(+), 40 deletions(-) diff --git a/doc/planning/awake.md b/doc/planning/awake.md index cfbbbefac9f..713a52ee1fa 100644 --- a/doc/planning/awake.md +++ b/doc/planning/awake.md @@ -10,12 +10,17 @@ The build ID can be found in `Core\Constants.cs` in the `BuildId` variable - it The build ID moniker is made up of two components - a reference to a [Halo](https://en.wikipedia.org/wiki/Halo_(franchise)) character, and the date when the work on the specific build started in the format of `MMDDYYYY`. -| Build ID | Build Date | -|:----------------------------------------------------------|:-----------------| -| [`DAISY023_04102024`](#DAISY023_04102024-april-10-2024) | April 10, 2024 | -| [`ATRIOX_04132023`](#ATRIOX_04132023-april-13-2023) | April 13, 2023 | -| [`LIBRARIAN_03202022`](#librarian_03202022-march-20-2022) | March 20, 2022 | -| `ARBITER_01312022` | January 31, 2022 | +| Build ID | Build Date | +|:-------------------------------------------------------------------|:----------------| +| [`VISEGRADRELAY_08152024`](#VISEGRADRELAY_08152024-august-15-2024) | August 15, 2024 | +| [`DAISY023_04102024`](#DAISY023_04102024-april-10-2024) | April 10, 2024 | +| [`ATRIOX_04132023`](#ATRIOX_04132023-april-13-2023) | April 13, 2023 | +| [`LIBRARIAN_03202022`](#librarian_03202022-march-20-2022) | March 20, 2022 | +| `ARBITER_01312022` | January 31, 2022 | + +### `VISEGRADRELAY_08152024` (August 15, 2024) + +- Amending the native API surface to make sure that the Win32 error is set correctly. ### `DAISY023_04102024` (April 10, 2024) diff --git a/src/modules/awake/Awake/Core/Constants.cs b/src/modules/awake/Awake/Core/Constants.cs index 80a75dc1eda..db3d20d745c 100644 --- a/src/modules/awake/Awake/Core/Constants.cs +++ b/src/modules/awake/Awake/Core/Constants.cs @@ -17,6 +17,6 @@ internal static class Constants // Format of the build ID is: CODENAME_MMDDYYYY, where MMDDYYYY // is representative of the date when the last change was made before // the pull request is issued. - internal const string BuildId = "DAISY023_04102024"; + internal const string BuildId = "VISEGRADRELAY_08152024"; } } diff --git a/src/modules/awake/Awake/Core/Manager.cs b/src/modules/awake/Awake/Core/Manager.cs index c5217dcdba3..f2372506356 100644 --- a/src/modules/awake/Awake/Core/Manager.cs +++ b/src/modules/awake/Awake/Core/Manager.cs @@ -5,10 +5,12 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.Drawing; using System.Globalization; using System.IO; using System.Reactive.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Text.Json; using System.Threading; @@ -62,7 +64,7 @@ internal static void StartMonitor() { Thread monitorThread = new(() => { - Thread.CurrentThread.IsBackground = true; + Thread.CurrentThread.IsBackground = false; while (true) { ExecutionState state = _stateQueue.Take(); @@ -126,10 +128,18 @@ internal static void CancelExistingThread() _stateQueue.Add(ExecutionState.ES_CONTINUOUS); // Next, make sure that any existing background threads are terminated. - _tokenSource.Cancel(); - _tokenSource.Dispose(); + if (_tokenSource != null) + { + _tokenSource.Cancel(); + _tokenSource.Dispose(); + + _tokenSource = new CancellationTokenSource(); + } + else + { + Logger.LogWarning("The token source was null."); + } - _tokenSource = new CancellationTokenSource(); Logger.LogInfo("Instantiating of new token source and thread token completed."); } @@ -137,12 +147,11 @@ internal static void SetIndefiniteKeepAwake(bool keepDisplayOn = false) { PowerToysTelemetry.Log.WriteEvent(new Telemetry.AwakeIndefinitelyKeepAwakeEvent()); - CancelExistingThread(); + TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, $"{Constants.FullAppName} [{Resources.AWAKE_TRAY_TEXT_INDEFINITE}]", _indefiniteIcon, TrayIconAction.Update); + CancelExistingThread(); _stateQueue.Add(ComputeAwakeState(keepDisplayOn)); - TrayHelper.SetShellIcon(TrayHelper.HiddenWindowHandle, $"{Constants.FullAppName} [{Resources.AWAKE_TRAY_TEXT_INDEFINITE}]", _indefiniteIcon, TrayIconAction.Update); - if (IsUsingPowerToysConfig) { try @@ -417,5 +426,18 @@ internal static void SetDisplay() } } } + + public static Process? GetParentProcess() + { + return GetParentProcess(Process.GetCurrentProcess().Handle); + } + + private static Process? GetParentProcess(IntPtr handle) + { + ProcessBasicInformation pbi = default; + int status = Bridge.NtQueryInformationProcess(handle, 0, ref pbi, Marshal.SizeOf(), out _); + + return status != 0 ? null : Process.GetProcessById(pbi.InheritedFromUniqueProcessId.ToInt32()); + } } } diff --git a/src/modules/awake/Awake/Core/Native/Bridge.cs b/src/modules/awake/Awake/Core/Native/Bridge.cs index 2fc2864dec3..4be81db855b 100644 --- a/src/modules/awake/Awake/Core/Native/Bridge.cs +++ b/src/modules/awake/Awake/Core/Native/Bridge.cs @@ -56,13 +56,13 @@ internal static extern IntPtr CreateFile( [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool DestroyMenu(IntPtr hMenu); - [DllImport("user32.dll")] + [DllImport("user32.dll", SetLastError = true)] internal static extern bool DestroyWindow(IntPtr hWnd); - [DllImport("user32.dll")] + [DllImport("user32.dll", SetLastError = true)] internal static extern void PostQuitMessage(int nExitCode); - [DllImport("shell32.dll")] + [DllImport("shell32.dll", SetLastError = true)] internal static extern bool Shell_NotifyIcon(int dwMessage, ref NotifyIconData pnid); [DllImport("user32.dll", SetLastError = true)] @@ -83,14 +83,14 @@ internal static extern IntPtr CreateFile( [DllImport("user32.dll", SetLastError = true)] internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); - [DllImport("user32.dll")] + [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool GetCursorPos(out Point lpPoint); - [DllImport("user32.dll")] + [DllImport("user32.dll", SetLastError = true)] internal static extern bool ScreenToClient(IntPtr hWnd, ref Point lpPoint); - [DllImport("user32.dll")] + [DllImport("user32.dll", SetLastError = true)] internal static extern bool GetMessage(out Msg lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax); [DllImport("user32.dll", SetLastError = true)] @@ -100,7 +100,10 @@ internal static extern IntPtr CreateFile( [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool SetMenuInfo(IntPtr hMenu, ref MenuInfo lpcmi); - [DllImport("user32.dll")] + [DllImport("user32.dll", SetLastError = true)] internal static extern bool SetForegroundWindow(IntPtr hWnd); + + [DllImport("ntdll.dll")] + internal static extern int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, ref ProcessBasicInformation processInformation, int processInformationLength, out int returnLength); } } diff --git a/src/modules/awake/Awake/Core/TrayHelper.cs b/src/modules/awake/Awake/Core/TrayHelper.cs index 00000a431f9..029df797d2f 100644 --- a/src/modules/awake/Awake/Core/TrayHelper.cs +++ b/src/modules/awake/Awake/Core/TrayHelper.cs @@ -43,11 +43,6 @@ static TrayHelper() HiddenWindowHandle = IntPtr.Zero; } - public static void InitializeTray(string text, Icon icon) - { - CreateHiddenWindow(icon, text); - } - private static void ShowContextMenu(IntPtr hWnd) { if (TrayMenu != IntPtr.Zero) @@ -88,7 +83,7 @@ private static void ShowContextMenu(IntPtr hWnd) } } - private static void CreateHiddenWindow(Icon icon, string text) + public static void InitializeTray(Icon icon, string text) { IntPtr hWnd = IntPtr.Zero; @@ -143,7 +138,13 @@ private static void CreateHiddenWindow(Icon icon, string text) Bridge.UpdateWindow(hWnd); SetShellIcon(hWnd, text, icon); + }); + }).Wait(); + Task.Run(() => + { + RunOnMainThread(() => + { RunMessageLoop(); }); }); @@ -151,6 +152,8 @@ private static void CreateHiddenWindow(Icon icon, string text) internal static void SetShellIcon(IntPtr hWnd, string text, Icon? icon, TrayIconAction action = TrayIconAction.Add) { + Logger.LogInfo($"Setting the shell icon.\nText: {text}\nAction: {action}"); + int message = Native.Constants.NIM_ADD; switch (action) @@ -168,6 +171,8 @@ internal static void SetShellIcon(IntPtr hWnd, string text, Icon? icon, TrayIcon if (action == TrayIconAction.Add || action == TrayIconAction.Update) { + Logger.LogInfo($"Adding or updating tray icon. HIcon handle is {icon?.Handle}\nHWnd: {hWnd}"); + _notifyIconData = new NotifyIconData { CbSize = Marshal.SizeOf(typeof(NotifyIconData)), diff --git a/src/modules/awake/Awake/Program.cs b/src/modules/awake/Awake/Program.cs index 229ad84efc6..d363fbddf72 100644 --- a/src/modules/awake/Awake/Program.cs +++ b/src/modules/awake/Awake/Program.cs @@ -44,6 +44,7 @@ internal sealed class Program internal static readonly string[] AliasesTimeOption = ["--time-limit", "-t"]; internal static readonly string[] AliasesPidOption = ["--pid", "-p"]; internal static readonly string[] AliasesExpireAtOption = ["--expire-at", "-e"]; + internal static readonly string[] AliasesParentPidOption = ["--use-parent-pid", "-u"]; private static readonly Icon _defaultAwakeIcon = new(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Awake/awake.ico")); @@ -116,6 +117,12 @@ private static int Main(string[] args) IsRequired = false, }; + var parentPidOption = new Option(AliasesParentPidOption, () => true, Resources.AWAKE_CMD_PARENT_PID_OPTION) + { + Arity = ArgumentArity.ZeroOrOne, + IsRequired = false, + }; + RootCommand? rootCommand = [ configOption, @@ -123,10 +130,11 @@ private static int Main(string[] args) timeOption, pidOption, expireAtOption, + parentPidOption, ]; rootCommand.Description = Core.Constants.AppName; - rootCommand.SetHandler(HandleCommandLineArguments, configOption, displayOption, timeOption, pidOption, expireAtOption); + rootCommand.SetHandler(HandleCommandLineArguments, configOption, displayOption, timeOption, pidOption, expireAtOption, parentPidOption); return rootCommand.InvokeAsync(args).Result; } @@ -153,9 +161,9 @@ private static void Exit(string message, int exitCode) Manager.CompleteExit(exitCode); } - private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, uint timeLimit, int pid, string expireAt) + private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, uint timeLimit, int pid, string expireAt, bool useParentPid) { - if (pid == 0) + if (pid == 0 && !useParentPid) { Logger.LogInfo("No PID specified. Allocating console..."); Manager.AllocateConsole(); @@ -175,11 +183,12 @@ private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, Logger.LogInfo($"The value for --time-limit is: {timeLimit}"); Logger.LogInfo($"The value for --pid is: {pid}"); Logger.LogInfo($"The value for --expire-at is: {expireAt}"); + Logger.LogInfo($"The value for --use-parent-pid is: {useParentPid}"); // Start the monitor thread that will be used to track the current state. Manager.StartMonitor(); - TrayHelper.InitializeTray(Core.Constants.FullAppName, _defaultAwakeIcon); + TrayHelper.InitializeTray(_defaultAwakeIcon, Core.Constants.FullAppName); var eventHandle = new EventWaitHandle(false, EventResetMode.ManualReset, PowerToys.Interop.Constants.AwakeExitEvent()); new Thread(() => @@ -215,6 +224,30 @@ private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, Logger.LogError($"There was a problem with the configuration file. Make sure it exists.\n{ex.Message}"); } } + else if (pid != 0 || useParentPid) + { + // Second, we snap to process-based execution. Because this is something that + // is snapped to a running entity, we only want to enable the ability to set + // indefinite keep-awake with the display settings that the user wants to set. + int targetPid = pid != 0 ? pid : useParentPid ? Manager.GetParentProcess()?.Id ?? 0 : 0; + + if (targetPid != 0) + { + Logger.LogInfo($"Bound to target process: {targetPid}"); + + Manager.SetIndefiniteKeepAwake(displayOn); + + RunnerHelper.WaitForPowerToysRunner(targetPid, () => + { + Logger.LogInfo($"Triggered PID-based exit handler for PID {targetPid}."); + Exit(Resources.AWAKE_EXIT_BINDING_HOOK_MESSAGE, 0); + }); + } + else + { + Logger.LogError("Not binding to any process."); + } + } else { // Date-based binding takes precedence over timed configuration, so we want to @@ -247,15 +280,6 @@ private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, } } } - - if (pid != 0) - { - RunnerHelper.WaitForPowerToysRunner(pid, () => - { - Logger.LogInfo($"Triggered PID-based exit handler for PID {pid}."); - Exit(Resources.AWAKE_EXIT_BINDING_HOOK_MESSAGE, 0); - }); - } } private static void ScaffoldConfiguration(string settingsPath) diff --git a/src/modules/awake/Awake/Properties/Resources.Designer.cs b/src/modules/awake/Awake/Properties/Resources.Designer.cs index 0cdaf23605c..be22d149d21 100644 --- a/src/modules/awake/Awake/Properties/Resources.Designer.cs +++ b/src/modules/awake/Awake/Properties/Resources.Designer.cs @@ -114,6 +114,15 @@ internal static string AWAKE_CMD_HELP_TIME_OPTION { } } + /// + /// Looks up a localized string similar to Uses the parent process as the bound target - once the process terminates, Awake stops.. + /// + internal static string AWAKE_CMD_PARENT_PID_OPTION { + get { + return ResourceManager.GetString("AWAKE_CMD_PARENT_PID_OPTION", resourceCulture); + } + } + /// /// Looks up a localized string similar to Exit. /// diff --git a/src/modules/awake/Awake/Properties/Resources.resx b/src/modules/awake/Awake/Properties/Resources.resx index 7ef19501287..8bafe1d4db0 100644 --- a/src/modules/awake/Awake/Properties/Resources.resx +++ b/src/modules/awake/Awake/Properties/Resources.resx @@ -205,4 +205,7 @@ s Used to display number of seconds in the system tray tooltip. + + Uses the parent process as the bound target - once the process terminates, Awake stops. + \ No newline at end of file From e9f8c23e187746b9c8c0d041b8ef378041b59996 Mon Sep 17 00:00:00 2001 From: Den Delimarsky Date: Thu, 15 Aug 2024 15:57:43 -0700 Subject: [PATCH 02/11] Process information enum --- .../Core/Models/ProcessBasicInformation.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/modules/awake/Awake/Core/Models/ProcessBasicInformation.cs diff --git a/src/modules/awake/Awake/Core/Models/ProcessBasicInformation.cs b/src/modules/awake/Awake/Core/Models/ProcessBasicInformation.cs new file mode 100644 index 00000000000..98d1c4a5b4c --- /dev/null +++ b/src/modules/awake/Awake/Core/Models/ProcessBasicInformation.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; + +namespace Awake.Core.Models +{ + [StructLayout(LayoutKind.Sequential)] + internal struct ProcessBasicInformation + { + public IntPtr ExitStatus; + public IntPtr PebAddress; + public IntPtr AffinityMask; + public IntPtr BasePriority; + public IntPtr UniquePID; + public IntPtr InheritedFromUniqueProcessId; + } +} From bd07382302a17c86b42334d1740dd0e9ad26800d Mon Sep 17 00:00:00 2001 From: Den Delimarsky Date: Thu, 15 Aug 2024 16:10:21 -0700 Subject: [PATCH 03/11] Update the docs --- doc/planning/awake.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/planning/awake.md b/doc/planning/awake.md index 713a52ee1fa..1f42eaca838 100644 --- a/doc/planning/awake.md +++ b/doc/planning/awake.md @@ -20,6 +20,12 @@ The build ID moniker is made up of two components - a reference to a [Halo](http ### `VISEGRADRELAY_08152024` (August 15, 2024) +>[!NOTE] +>See pull request: [Awake - `VISEGRADRELAY_08152024`](https://github.com/microsoft/PowerToys/pull/34316) + +- [#34148](https://github.com/microsoft/PowerToys/issues/34148) Fixes the issue where the Awake icon is not displayed. +- [#17969](https://github.com/microsoft/PowerToys/issues/17969) Add the ability to bind the process target to the parent of the Awake launcher. +- PID binding now correctly ignores irrelevant parameters (e.g., expiration, interval) and only works for indefinite periods. - Amending the native API surface to make sure that the Win32 error is set correctly. ### `DAISY023_04102024` (April 10, 2024) From 8c947952d352661fe323bc866d9f148c2ba528bd Mon Sep 17 00:00:00 2001 From: Den Delimarsky Date: Thu, 15 Aug 2024 16:59:11 -0700 Subject: [PATCH 04/11] Fix spelling --- .github/actions/spell-check/excludes.txt | 1 + .github/actions/spell-check/expect.txt | 14 ++++---------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/.github/actions/spell-check/excludes.txt b/.github/actions/spell-check/excludes.txt index 79b69758a96..fd89d668a2c 100644 --- a/.github/actions/spell-check/excludes.txt +++ b/.github/actions/spell-check/excludes.txt @@ -117,6 +117,7 @@ ^\Qsrc/modules/previewpane/UnitTests-StlThumbnailProvider/HelperFiles/sample.stl\E$ ^\Qtools/project_template/ModuleTemplate/resource.h\E$ ^doc/devdocs/akaLinks\.md$ +^src/modules/launcher/Plugins/Microsoft\.PowerToys\.Run\.Plugin\.TimeDate/Properties/ ^src/modules/MouseWithoutBorders/App/.*/NativeMethods\.cs$ ^src/modules/MouseWithoutBorders/App/Form/.*\.Designer\.cs$ ^src/modules/MouseWithoutBorders/App/Form/.*\.resx$ diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt index c5c09310820..2bf5ff9492d 100644 --- a/.github/actions/spell-check/expect.txt +++ b/.github/actions/spell-check/expect.txt @@ -189,7 +189,6 @@ CLIPBOARDUPDATE CLIPCHILDREN CLIPSIBLINGS closesocket -clrcall CLSCTX Clusion cmder @@ -200,8 +199,8 @@ CMINVOKECOMMANDINFO CMINVOKECOMMANDINFOEX CMock CMONITORS -cmph cmpgt +cmph cne CNF coclass @@ -247,10 +246,7 @@ countof cph CPower cppblog -cppruntime -cppstd cppwinrt -CProj createdump CREATESCHEDULEDTASK CREATESTRUCT @@ -605,7 +601,6 @@ hmenu hmodule hmonitor homljgmgpmcbpjbnjpfijnhipfkiclkd -HOOKPROC Hostbackdropbrush hotkeycontrol hotkeys @@ -673,7 +668,6 @@ imageresizerinput imageresizersettings imagingdevices ime -imperialounce inetcpl Infobar INFOEXAMPLE @@ -934,7 +928,6 @@ MRT mru mrw msc -msclr mscorlib msdata msedge @@ -1114,6 +1107,7 @@ PATINVERT PATPAINT PAUDIO pbc +pbi PBlob pcb pcch @@ -1127,6 +1121,7 @@ pdo pdto pdtobj pdw +Peb pef PElems Pels @@ -1506,7 +1501,6 @@ STATICEDGE STATSTG stdafx STDAPI -stdcpp stdcpplatest STDMETHODCALLTYPE STDMETHODIMP @@ -1674,7 +1668,6 @@ USERDATA Userenv USESHOWWINDOW USESTDHANDLES -usounce USRDLL UType uuidv @@ -1711,6 +1704,7 @@ VIDEOINFOHEADER viewmodel vih VIRTUALDESK +VISEGRADRELAY visiblecolorformats Visibletrue visualeffects From 708ef511ab593344f270f9f0f282eee664043197 Mon Sep 17 00:00:00 2001 From: Den Delimarsky Date: Mon, 19 Aug 2024 14:21:07 -0700 Subject: [PATCH 05/11] Make sure that PID is used in PT config flow --- src/modules/awake/Awake/Program.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/modules/awake/Awake/Program.cs b/src/modules/awake/Awake/Program.cs index d363fbddf72..03c7d9d6bcc 100644 --- a/src/modules/awake/Awake/Program.cs +++ b/src/modules/awake/Awake/Program.cs @@ -218,6 +218,17 @@ private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, } ScaffoldConfiguration(settingsPath); + + if (pid != 0) + { + Logger.LogInfo($"Bound to target process while also using PowerToys settings: {pid}"); + + RunnerHelper.WaitForPowerToysRunner(pid, () => + { + Logger.LogInfo($"Triggered PID-based exit handler for PID {pid}."); + Exit(Resources.AWAKE_EXIT_BINDING_HOOK_MESSAGE, 0); + }); + } } catch (Exception ex) { From b58398bc075a52642f3ca5e37361293a6b073822 Mon Sep 17 00:00:00 2001 From: Den Delimarsky Date: Sun, 8 Sep 2024 11:48:18 -0700 Subject: [PATCH 06/11] Logic for checks based on #34148 --- doc/planning/awake.md | 19 ++-- src/modules/awake/Awake/Core/Constants.cs | 2 +- src/modules/awake/Awake/Program.cs | 121 ++++++++++++---------- 3 files changed, 77 insertions(+), 65 deletions(-) diff --git a/doc/planning/awake.md b/doc/planning/awake.md index 1f42eaca838..650cc203f57 100644 --- a/doc/planning/awake.md +++ b/doc/planning/awake.md @@ -10,13 +10,18 @@ The build ID can be found in `Core\Constants.cs` in the `BuildId` variable - it The build ID moniker is made up of two components - a reference to a [Halo](https://en.wikipedia.org/wiki/Halo_(franchise)) character, and the date when the work on the specific build started in the format of `MMDDYYYY`. -| Build ID | Build Date | -|:-------------------------------------------------------------------|:----------------| -| [`VISEGRADRELAY_08152024`](#VISEGRADRELAY_08152024-august-15-2024) | August 15, 2024 | -| [`DAISY023_04102024`](#DAISY023_04102024-april-10-2024) | April 10, 2024 | -| [`ATRIOX_04132023`](#ATRIOX_04132023-april-13-2023) | April 13, 2023 | -| [`LIBRARIAN_03202022`](#librarian_03202022-march-20-2022) | March 20, 2022 | -| `ARBITER_01312022` | January 31, 2022 | +| Build ID | Build Date | +|:-------------------------------------------------------------------|:------------------| +| [`PROMETHEAN_09082024`](#PROMETHEAN_09082024-september-8-2024) | September 8, 2024 | +| [`VISEGRADRELAY_08152024`](#VISEGRADRELAY_08152024-august-15-2024) | August 15, 2024 | +| [`DAISY023_04102024`](#DAISY023_04102024-april-10-2024) | April 10, 2024 | +| [`ATRIOX_04132023`](#ATRIOX_04132023-april-13-2023) | April 13, 2023 | +| [`LIBRARIAN_03202022`](#librarian_03202022-march-20-2022) | March 20, 2022 | +| `ARBITER_01312022` | January 31, 2022 | + +### `PROMETHEAN_09082024` (September 8, 2024) + +- Updating the initialization logic to make sure that settings are respected for proper group policy and single-instance detection. ### `VISEGRADRELAY_08152024` (August 15, 2024) diff --git a/src/modules/awake/Awake/Core/Constants.cs b/src/modules/awake/Awake/Core/Constants.cs index db3d20d745c..1bd6f0a0436 100644 --- a/src/modules/awake/Awake/Core/Constants.cs +++ b/src/modules/awake/Awake/Core/Constants.cs @@ -17,6 +17,6 @@ internal static class Constants // Format of the build ID is: CODENAME_MMDDYYYY, where MMDDYYYY // is representative of the date when the last change was made before // the pull request is issued. - internal const string BuildId = "VISEGRADRELAY_08152024"; + internal const string BuildId = "PROMETHEAN_09082024"; } } diff --git a/src/modules/awake/Awake/Program.cs b/src/modules/awake/Awake/Program.cs index 03c7d9d6bcc..8b01fcb8348 100644 --- a/src/modules/awake/Awake/Program.cs +++ b/src/modules/awake/Awake/Program.cs @@ -60,72 +60,77 @@ private static int Main(string[] args) if (PowerToys.GPOWrapper.GPOWrapper.GetConfiguredAwakeEnabledValue() == PowerToys.GPOWrapper.GpoRuleConfigured.Disabled) { Exit("PowerToys.Awake tried to start with a group policy setting that disables the tool. Please contact your system administrator.", 1); - return 0; + return 1; } - - if (!instantiated) + else { - Exit(Core.Constants.AppName + " is already running! Exiting the application.", 1); - } - - Logger.LogInfo($"Launching {Core.Constants.AppName}..."); - Logger.LogInfo(FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion); - Logger.LogInfo($"Build: {Core.Constants.BuildId}"); - Logger.LogInfo($"OS: {Environment.OSVersion}"); - Logger.LogInfo($"OS Build: {Manager.GetOperatingSystemBuild()}"); + if (!instantiated) + { + // Awake is already running - there is no need for us to process + // anything further. + Exit(Core.Constants.AppName + " is already running! Exiting the application.", 1); + return 1; + } + else + { + Logger.LogInfo($"Launching {Core.Constants.AppName}..."); + Logger.LogInfo(FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion); + Logger.LogInfo($"Build: {Core.Constants.BuildId}"); + Logger.LogInfo($"OS: {Environment.OSVersion}"); + Logger.LogInfo($"OS Build: {Manager.GetOperatingSystemBuild()}"); - TaskScheduler.UnobservedTaskException += (sender, args) => - { - Trace.WriteLine($"Task scheduler error: {args.Exception.Message}"); // somebody forgot to check! - args.SetObserved(); - }; + TaskScheduler.UnobservedTaskException += (sender, args) => + { + Trace.WriteLine($"Task scheduler error: {args.Exception.Message}"); // somebody forgot to check! + args.SetObserved(); + }; - // To make it easier to diagnose future issues, let's get the - // system power capabilities and aggregate them in the log. - Bridge.GetPwrCapabilities(out _powerCapabilities); - Logger.LogInfo(JsonSerializer.Serialize(_powerCapabilities)); + // To make it easier to diagnose future issues, let's get the + // system power capabilities and aggregate them in the log. + Bridge.GetPwrCapabilities(out _powerCapabilities); + Logger.LogInfo(JsonSerializer.Serialize(_powerCapabilities)); - Logger.LogInfo("Parsing parameters..."); + Logger.LogInfo("Parsing parameters..."); - var configOption = new Option(AliasesConfigOption, () => false, Resources.AWAKE_CMD_HELP_CONFIG_OPTION) - { - Arity = ArgumentArity.ZeroOrOne, - IsRequired = false, - }; + var configOption = new Option(AliasesConfigOption, () => false, Resources.AWAKE_CMD_HELP_CONFIG_OPTION) + { + Arity = ArgumentArity.ZeroOrOne, + IsRequired = false, + }; - var displayOption = new Option(AliasesDisplayOption, () => true, Resources.AWAKE_CMD_HELP_DISPLAY_OPTION) - { - Arity = ArgumentArity.ZeroOrOne, - IsRequired = false, - }; + var displayOption = new Option(AliasesDisplayOption, () => true, Resources.AWAKE_CMD_HELP_DISPLAY_OPTION) + { + Arity = ArgumentArity.ZeroOrOne, + IsRequired = false, + }; - var timeOption = new Option(AliasesTimeOption, () => 0, Resources.AWAKE_CMD_HELP_TIME_OPTION) - { - Arity = ArgumentArity.ExactlyOne, - IsRequired = false, - }; + var timeOption = new Option(AliasesTimeOption, () => 0, Resources.AWAKE_CMD_HELP_TIME_OPTION) + { + Arity = ArgumentArity.ExactlyOne, + IsRequired = false, + }; - var pidOption = new Option(AliasesPidOption, () => 0, Resources.AWAKE_CMD_HELP_PID_OPTION) - { - Arity = ArgumentArity.ZeroOrOne, - IsRequired = false, - }; + var pidOption = new Option(AliasesPidOption, () => 0, Resources.AWAKE_CMD_HELP_PID_OPTION) + { + Arity = ArgumentArity.ZeroOrOne, + IsRequired = false, + }; - var expireAtOption = new Option(AliasesExpireAtOption, () => string.Empty, Resources.AWAKE_CMD_HELP_EXPIRE_AT_OPTION) - { - Arity = ArgumentArity.ZeroOrOne, - IsRequired = false, - }; + var expireAtOption = new Option(AliasesExpireAtOption, () => string.Empty, Resources.AWAKE_CMD_HELP_EXPIRE_AT_OPTION) + { + Arity = ArgumentArity.ZeroOrOne, + IsRequired = false, + }; - var parentPidOption = new Option(AliasesParentPidOption, () => true, Resources.AWAKE_CMD_PARENT_PID_OPTION) - { - Arity = ArgumentArity.ZeroOrOne, - IsRequired = false, - }; + var parentPidOption = new Option(AliasesParentPidOption, () => true, Resources.AWAKE_CMD_PARENT_PID_OPTION) + { + Arity = ArgumentArity.ZeroOrOne, + IsRequired = false, + }; - RootCommand? rootCommand = - [ - configOption, + RootCommand? rootCommand = + [ + configOption, displayOption, timeOption, pidOption, @@ -133,10 +138,12 @@ private static int Main(string[] args) parentPidOption, ]; - rootCommand.Description = Core.Constants.AppName; - rootCommand.SetHandler(HandleCommandLineArguments, configOption, displayOption, timeOption, pidOption, expireAtOption, parentPidOption); + rootCommand.Description = Core.Constants.AppName; + rootCommand.SetHandler(HandleCommandLineArguments, configOption, displayOption, timeOption, pidOption, expireAtOption, parentPidOption); - return rootCommand.InvokeAsync(args).Result; + return rootCommand.InvokeAsync(args).Result; + } + } } private static void AwakeUnhandledExceptionCatcher(object sender, UnhandledExceptionEventArgs e) From 524c19a6228b3e54d652c7d08a1ab98fe3498871 Mon Sep 17 00:00:00 2001 From: Den Delimarsky Date: Sun, 8 Sep 2024 11:51:08 -0700 Subject: [PATCH 07/11] Update with link to PR --- doc/planning/awake.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/planning/awake.md b/doc/planning/awake.md index 650cc203f57..0566cd86dfb 100644 --- a/doc/planning/awake.md +++ b/doc/planning/awake.md @@ -21,6 +21,9 @@ The build ID moniker is made up of two components - a reference to a [Halo](http ### `PROMETHEAN_09082024` (September 8, 2024) +>[!NOTE] +>See pull request: [Awake - `PROMETHEAN_09082024`](https://github.com/microsoft/PowerToys/pull/34717) + - Updating the initialization logic to make sure that settings are respected for proper group policy and single-instance detection. ### `VISEGRADRELAY_08152024` (August 15, 2024) From 104120374a61919408458c61f96ac1c275e28fa3 Mon Sep 17 00:00:00 2001 From: Den Delimarsky Date: Sun, 8 Sep 2024 12:06:37 -0700 Subject: [PATCH 08/11] Fixes #34717 --- src/modules/awake/Awake/Program.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/modules/awake/Awake/Program.cs b/src/modules/awake/Awake/Program.cs index 8b01fcb8348..7b60ab194f5 100644 --- a/src/modules/awake/Awake/Program.cs +++ b/src/modules/awake/Awake/Program.cs @@ -122,7 +122,7 @@ private static int Main(string[] args) IsRequired = false, }; - var parentPidOption = new Option(AliasesParentPidOption, () => true, Resources.AWAKE_CMD_PARENT_PID_OPTION) + var parentPidOption = new Option(AliasesParentPidOption, () => false, Resources.AWAKE_CMD_PARENT_PID_OPTION) { Arity = ArgumentArity.ZeroOrOne, IsRequired = false, @@ -131,12 +131,12 @@ private static int Main(string[] args) RootCommand? rootCommand = [ configOption, - displayOption, - timeOption, - pidOption, - expireAtOption, - parentPidOption, - ]; + displayOption, + timeOption, + pidOption, + expireAtOption, + parentPidOption, + ]; rootCommand.Description = Core.Constants.AppName; rootCommand.SetHandler(HandleCommandLineArguments, configOption, displayOption, timeOption, pidOption, expireAtOption, parentPidOption); From 75125f25be9702af61e0c9b855499bffe9da0b63 Mon Sep 17 00:00:00 2001 From: Den Delimarsky Date: Sun, 8 Sep 2024 12:41:13 -0700 Subject: [PATCH 09/11] Small cleanup --- src/modules/awake/Awake/Program.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/modules/awake/Awake/Program.cs b/src/modules/awake/Awake/Program.cs index 7b60ab194f5..53e3e69e759 100644 --- a/src/modules/awake/Awake/Program.cs +++ b/src/modules/awake/Awake/Program.cs @@ -52,9 +52,7 @@ private static int Main(string[] args) { _settingsUtils = new SettingsUtils(); LockMutex = new Mutex(true, Core.Constants.AppName, out bool instantiated); - Logger.InitializeLogger(Path.Combine("\\", Core.Constants.AppName, "Logs")); - AppDomain.CurrentDomain.UnhandledException += AwakeUnhandledExceptionCatcher; if (PowerToys.GPOWrapper.GPOWrapper.GetConfiguredAwakeEnabledValue() == PowerToys.GPOWrapper.GpoRuleConfigured.Disabled) @@ -182,6 +180,7 @@ private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, } else { + Logger.LogInfo("Starting with PID binding."); _startedFromPowerToys = true; } From 14299bae24ee2367574b79ec344e54264b69ab99 Mon Sep 17 00:00:00 2001 From: Den Delimarsky Date: Sun, 8 Sep 2024 12:59:21 -0700 Subject: [PATCH 10/11] Proper task segmentation in a function --- src/modules/awake/Awake/Program.cs | 62 ++++++++++++++++-------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/src/modules/awake/Awake/Program.cs b/src/modules/awake/Awake/Program.cs index 53e3e69e759..a5453d5ce37 100644 --- a/src/modules/awake/Awake/Program.cs +++ b/src/modules/awake/Awake/Program.cs @@ -303,34 +303,8 @@ private static void ScaffoldConfiguration(string settingsPath) { try { - var directory = Path.GetDirectoryName(settingsPath)!; - var fileName = Path.GetFileName(settingsPath); - - _watcher = new FileSystemWatcher - { - Path = directory, - EnableRaisingEvents = true, - NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.CreationTime, - Filter = fileName, - }; - - var mergedObservable = Observable.Merge( - Observable.FromEventPattern( - h => _watcher.Changed += h, - h => _watcher.Changed -= h), - Observable.FromEventPattern( - h => _watcher.Created += h, - h => _watcher.Created -= h)); - - mergedObservable - .Throttle(TimeSpan.FromMilliseconds(25)) - .SubscribeOn(TaskPoolScheduler.Default) - .Select(e => e.EventArgs) - .Subscribe(HandleAwakeConfigChange); - - var settings = Manager.ModuleSettings!.GetSettings(Core.Constants.AppName) ?? new AwakeSettings(); - TrayHelper.SetTray(settings, _startedFromPowerToys); - + SetupFileSystemWatcher(settingsPath); + InitializeSettings(); ProcessSettings(); } catch (Exception ex) @@ -339,6 +313,38 @@ private static void ScaffoldConfiguration(string settingsPath) } } + private static void SetupFileSystemWatcher(string settingsPath) + { + var directory = Path.GetDirectoryName(settingsPath)!; + var fileName = Path.GetFileName(settingsPath); + + _watcher = new FileSystemWatcher + { + Path = directory, + EnableRaisingEvents = true, + NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.CreationTime, + Filter = fileName, + }; + + Observable.Merge( + Observable.FromEventPattern( + h => _watcher.Changed += h, + h => _watcher.Changed -= h), + Observable.FromEventPattern( + h => _watcher.Created += h, + h => _watcher.Created -= h)) + .Throttle(TimeSpan.FromMilliseconds(25)) + .SubscribeOn(TaskPoolScheduler.Default) + .Select(e => e.EventArgs) + .Subscribe(HandleAwakeConfigChange); + } + + private static void InitializeSettings() + { + var settings = Manager.ModuleSettings?.GetSettings(Core.Constants.AppName) ?? new AwakeSettings(); + TrayHelper.SetTray(settings, _startedFromPowerToys); + } + private static void HandleAwakeConfigChange(FileSystemEventArgs fileEvent) { try From 3d66e1f7d11ff3ac78622eaa7e59a9aca983ecff Mon Sep 17 00:00:00 2001 From: Den Delimarsky Date: Sun, 8 Sep 2024 18:30:17 -0700 Subject: [PATCH 11/11] Cleanup the code --- src/modules/awake/Awake/Core/TrayHelper.cs | 153 ++++++++++----------- src/modules/awake/Awake/Program.cs | 37 +++-- 2 files changed, 97 insertions(+), 93 deletions(-) diff --git a/src/modules/awake/Awake/Core/TrayHelper.cs b/src/modules/awake/Awake/Core/TrayHelper.cs index 029df797d2f..816f8d513c1 100644 --- a/src/modules/awake/Awake/Core/TrayHelper.cs +++ b/src/modules/awake/Awake/Core/TrayHelper.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics; using System.Drawing; using System.Linq; using System.Runtime.InteropServices; @@ -28,13 +29,11 @@ namespace Awake.Core internal static class TrayHelper { private static NotifyIconData _notifyIconData; - private static IntPtr _trayMenu; + private static IntPtr _hiddenWindowHandle; private static IntPtr TrayMenu { get => _trayMenu; set => _trayMenu = value; } - private static IntPtr _hiddenWindowHandle; - internal static IntPtr HiddenWindowHandle { get => _hiddenWindowHandle; private set => _hiddenWindowHandle = value; } static TrayHelper() @@ -45,42 +44,35 @@ static TrayHelper() private static void ShowContextMenu(IntPtr hWnd) { - if (TrayMenu != IntPtr.Zero) + if (TrayMenu == IntPtr.Zero) { - Bridge.SetForegroundWindow(hWnd); - - // Get the handle to the context menu associated with the tray icon - IntPtr hMenu = TrayMenu; + Logger.LogError("Tried to create a context menu while the TrayMenu object is a null pointer. Normal when used in standalone mode."); + return; + } - // Get the current cursor position - Bridge.GetCursorPos(out Models.Point cursorPos); + Bridge.SetForegroundWindow(hWnd); - Bridge.ScreenToClient(hWnd, ref cursorPos); + // Get cursor position and convert it to client coordinates + Bridge.GetCursorPos(out Models.Point cursorPos); + Bridge.ScreenToClient(hWnd, ref cursorPos); - MenuInfo menuInfo = new() - { - CbSize = (uint)Marshal.SizeOf(typeof(MenuInfo)), - FMask = Native.Constants.MIM_STYLE, - DwStyle = Native.Constants.MNS_AUTO_DISMISS, - }; - Bridge.SetMenuInfo(hMenu, ref menuInfo); - - // Display the context menu at the cursor position - Bridge.TrackPopupMenuEx( - hMenu, - Native.Constants.TPM_LEFT_ALIGN | Native.Constants.TPM_BOTTOMALIGN | Native.Constants.TPM_LEFT_BUTTON, - cursorPos.X, - cursorPos.Y, - hWnd, - IntPtr.Zero); - } - else + // Set menu information + var menuInfo = new MenuInfo { - // Tray menu was not initialized. Log the issue. - // This is normal when operating in "standalone mode" - that is, detached - // from the PowerToys configuration file. - Logger.LogError("Tried to create a context menu while the TrayMenu object is a null pointer. Normal when used in standalone mode."); - } + CbSize = (uint)Marshal.SizeOf(), + FMask = Native.Constants.MIM_STYLE, + DwStyle = Native.Constants.MNS_AUTO_DISMISS, + }; + Bridge.SetMenuInfo(TrayMenu, ref menuInfo); + + // Display the context menu at the cursor position + Bridge.TrackPopupMenuEx( + TrayMenu, + Native.Constants.TPM_LEFT_ALIGN | Native.Constants.TPM_BOTTOMALIGN | Native.Constants.TPM_LEFT_BUTTON, + cursorPos.X, + cursorPos.Y, + hWnd, + IntPtr.Zero); } public static void InitializeTray(Icon icon, string text) @@ -152,58 +144,63 @@ public static void InitializeTray(Icon icon, string text) internal static void SetShellIcon(IntPtr hWnd, string text, Icon? icon, TrayIconAction action = TrayIconAction.Add) { - Logger.LogInfo($"Setting the shell icon.\nText: {text}\nAction: {action}"); - - int message = Native.Constants.NIM_ADD; - - switch (action) + if (hWnd != IntPtr.Zero && icon != null) { - case TrayIconAction.Update: - message = Native.Constants.NIM_MODIFY; - break; - case TrayIconAction.Delete: - message = Native.Constants.NIM_DELETE; - break; - case TrayIconAction.Add: - default: - break; - } + int message = Native.Constants.NIM_ADD; - if (action == TrayIconAction.Add || action == TrayIconAction.Update) - { - Logger.LogInfo($"Adding or updating tray icon. HIcon handle is {icon?.Handle}\nHWnd: {hWnd}"); + switch (action) + { + case TrayIconAction.Update: + message = Native.Constants.NIM_MODIFY; + break; + case TrayIconAction.Delete: + message = Native.Constants.NIM_DELETE; + break; + case TrayIconAction.Add: + default: + break; + } - _notifyIconData = new NotifyIconData + if (action == TrayIconAction.Add || action == TrayIconAction.Update) { - CbSize = Marshal.SizeOf(typeof(NotifyIconData)), - HWnd = hWnd, - UId = 1000, - UFlags = Native.Constants.NIF_ICON | Native.Constants.NIF_TIP | Native.Constants.NIF_MESSAGE, - UCallbackMessage = (int)Native.Constants.WM_USER, - HIcon = icon?.Handle ?? IntPtr.Zero, - SzTip = text, - }; - } - else if (action == TrayIconAction.Delete) - { - _notifyIconData = new NotifyIconData + _notifyIconData = new NotifyIconData + { + CbSize = Marshal.SizeOf(typeof(NotifyIconData)), + HWnd = hWnd, + UId = 1000, + UFlags = Native.Constants.NIF_ICON | Native.Constants.NIF_TIP | Native.Constants.NIF_MESSAGE, + UCallbackMessage = (int)Native.Constants.WM_USER, + HIcon = icon?.Handle ?? IntPtr.Zero, + SzTip = text, + }; + } + else if (action == TrayIconAction.Delete) { - CbSize = Marshal.SizeOf(typeof(NotifyIconData)), - HWnd = hWnd, - UId = 1000, - UFlags = 0, - }; - } + _notifyIconData = new NotifyIconData + { + CbSize = Marshal.SizeOf(typeof(NotifyIconData)), + HWnd = hWnd, + UId = 1000, + UFlags = 0, + }; + } - if (!Bridge.Shell_NotifyIcon(message, ref _notifyIconData)) - { - int errorCode = Marshal.GetLastWin32Error(); - throw new Win32Exception(errorCode, $"Failed to change tray icon. Action: {action} and error code: {errorCode}"); - } + if (!Bridge.Shell_NotifyIcon(message, ref _notifyIconData)) + { + int errorCode = Marshal.GetLastWin32Error(); + Logger.LogInfo($"Could not set the shell icon. Action: {action} and error code: {errorCode}. HIcon handle is {icon?.Handle} and HWnd is {hWnd}"); + + throw new Win32Exception(errorCode, $"Failed to change tray icon. Action: {action} and error code: {errorCode}"); + } - if (action == TrayIconAction.Delete) + if (action == TrayIconAction.Delete) + { + _notifyIconData = default; + } + } + else { - _notifyIconData = default; + Logger.LogInfo($"Cannot set the shell icon - parent window handle is zero or icon is not available. Text: {text} Action: {action}"); } } diff --git a/src/modules/awake/Awake/Program.cs b/src/modules/awake/Awake/Program.cs index a5453d5ce37..c9fdfbf1175 100644 --- a/src/modules/awake/Awake/Program.cs +++ b/src/modules/awake/Awake/Program.cs @@ -55,18 +55,18 @@ private static int Main(string[] args) Logger.InitializeLogger(Path.Combine("\\", Core.Constants.AppName, "Logs")); AppDomain.CurrentDomain.UnhandledException += AwakeUnhandledExceptionCatcher; - if (PowerToys.GPOWrapper.GPOWrapper.GetConfiguredAwakeEnabledValue() == PowerToys.GPOWrapper.GpoRuleConfigured.Disabled) + if (!instantiated) { - Exit("PowerToys.Awake tried to start with a group policy setting that disables the tool. Please contact your system administrator.", 1); + // Awake is already running - there is no need for us to process + // anything further + Exit(Core.Constants.AppName + " is already running! Exiting the application.", 1); return 1; } else { - if (!instantiated) + if (PowerToys.GPOWrapper.GPOWrapper.GetConfiguredAwakeEnabledValue() == PowerToys.GPOWrapper.GpoRuleConfigured.Disabled) { - // Awake is already running - there is no need for us to process - // anything further. - Exit(Core.Constants.AppName + " is already running! Exiting the application.", 1); + Exit("PowerToys.Awake tried to start with a group policy setting that disables the tool. Please contact your system administrator.", 1); return 1; } else @@ -171,12 +171,7 @@ private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, if (pid == 0 && !useParentPid) { Logger.LogInfo("No PID specified. Allocating console..."); - Manager.AllocateConsole(); - - _handler += new ConsoleEventHandler(ExitHandler); - Manager.SetConsoleControlHandler(_handler, true); - - Trace.Listeners.Add(new ConsoleTraceListener()); + AllocateLocalConsole(); } else { @@ -238,7 +233,7 @@ private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, } catch (Exception ex) { - Logger.LogError($"There was a problem with the configuration file. Make sure it exists.\n{ex.Message}"); + Logger.LogError($"There was a problem with the configuration file. Make sure it exists. {ex.Message}"); } } else if (pid != 0 || useParentPid) @@ -299,6 +294,16 @@ private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, } } + private static void AllocateLocalConsole() + { + Manager.AllocateConsole(); + + _handler += new ConsoleEventHandler(ExitHandler); + Manager.SetConsoleControlHandler(_handler, true); + + Trace.Listeners.Add(new ConsoleTraceListener()); + } + private static void ScaffoldConfiguration(string settingsPath) { try @@ -362,7 +367,9 @@ private static void ProcessSettings() { try { - var settings = _settingsUtils!.GetSettings(Core.Constants.AppName) ?? throw new InvalidOperationException("Settings are null."); + var settings = _settingsUtils!.GetSettings(Core.Constants.AppName) + ?? throw new InvalidOperationException("Settings are null."); + Logger.LogInfo($"Identified custom time shortcuts for the tray: {settings.Properties.CustomTrayTimes.Count}"); switch (settings.Properties.Mode) @@ -376,7 +383,7 @@ private static void ProcessSettings() break; case AwakeMode.TIMED: - uint computedTime = (settings.Properties.IntervalHours * 60 * 60) + (settings.Properties.IntervalMinutes * 60); + uint computedTime = (settings.Properties.IntervalHours * 3600) + (settings.Properties.IntervalMinutes * 60); Manager.SetTimedKeepAwake(computedTime, settings.Properties.KeepDisplayOn); break;