Fixes for PowerToys Awake (#12215)

* Change how background threads operate
This should reduce CPU usage.

* Well there is just no need for the console here

* Need to keep the full name sanitized

* Update the changes to console handling

* Updating how we handle constants

* Fix process termination logic

* Making some tweaks to the termination logic

* Update how the process is tracked

* Updating how application closing is done for Awake.

* Update with explicit types

* Fix high CPU usage for timed keep awake.

* Logging typo fix.

* Update some of the timer logic.

* Fix variable naming for consistency

* Cleanup the C++ interface

* Cleanup the code a bit
This change introduces support for:

- Proper event handling across the two apps (Awake and runner).
- Removal of unnecessary functions.

* Cleaning up the code even further

* Remove unnecessary functions
This commit is contained in:
Den Delimarsky 2021-07-13 10:39:46 -07:00 committed by GitHub
parent 5027a55e7f
commit 579881002e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 216 additions and 139 deletions

View file

@ -186,5 +186,9 @@ public
static String ^ ShowColorPickerSharedEvent() {
return gcnew String(CommonSharedConstants::SHOW_COLOR_PICKER_SHARED_EVENT);
}
static String ^ AwakeExitEvent() {
return gcnew String(CommonSharedConstants::AWAKE_EXIT_EVENT);
}
};
}

View file

@ -28,6 +28,9 @@ namespace CommonSharedConstants
const wchar_t FANCY_ZONES_EDITOR_TOGGLE_EVENT[] = L"Local\\FancyZones-ToggleEditorEvent-1e174338-06a3-472b-874d-073b21c62f14";
// Path to the event used by Awake
const wchar_t AWAKE_EXIT_EVENT[] = L"Local\\PowerToysAwakeExitEvent-c0d5e305-35fc-4fb5-83ec-f6070cfaf7fe";
// Max DWORD for key code to disable keys.
const DWORD VK_DISABLED = 0x100;
}

View file

@ -21,6 +21,18 @@ namespace Awake.Core
ES_SYSTEM_REQUIRED = 0x00000001,
}
// See: https://docs.microsoft.com/windows/console/handlerroutine
public enum ControlType
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1,
CTRL_CLOSE_EVENT = 2,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT = 6,
}
public delegate bool ConsoleEventHandler(ControlType ctrlType);
/// <summary>
/// Helper class that allows talking to Win32 APIs without having to rely on PInvoke in other parts
/// of the codebase.
@ -37,6 +49,10 @@ namespace Awake.Core
private static CancellationToken _threadToken;
private static Task? _runnerThread;
private static System.Timers.Timer _timedLoopTimer;
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleCtrlHandler(ConsoleEventHandler handler, bool add);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
@ -63,10 +79,16 @@ namespace Awake.Core
static APIHelper()
{
_timedLoopTimer = new System.Timers.Timer();
_log = LogManager.GetCurrentClassLogger();
_tokenSource = new CancellationTokenSource();
}
public static void SetConsoleControlHandler(ConsoleEventHandler handler, bool addHandler)
{
SetConsoleCtrlHandler(handler, addHandler);
}
public static void AllocateConsole()
{
_log.Debug("Bootstrapping the console allocation routine.");
@ -139,7 +161,7 @@ namespace Awake.Core
}
catch (OperationCanceledException)
{
_log.Info("Confirmed background thread cancellation when setting passive keep awake.");
_log.Info("Confirmed background thread cancellation when disabling explicit keep awake.");
}
}
@ -156,7 +178,7 @@ namespace Awake.Core
}
catch (OperationCanceledException)
{
_log.Info("Confirmed background thread cancellation when setting indefinite keep awake.");
_log.Info("Confirmed background thread cancellation when setting timed keep awake.");
}
_tokenSource = new CancellationTokenSource();
@ -223,14 +245,25 @@ namespace Awake.Core
if (success)
{
_log.Info($"Initiated temporary keep awake in background thread: {GetCurrentThreadId()}. Screen on: {keepDisplayOn}");
var startTime = DateTime.UtcNow;
while (DateTime.UtcNow - startTime < TimeSpan.FromSeconds(Math.Abs(seconds)))
_timedLoopTimer = new System.Timers.Timer(seconds * 1000);
_timedLoopTimer.Elapsed += (s, e) =>
{
if (_threadToken.IsCancellationRequested)
{
_threadToken.ThrowIfCancellationRequested();
}
}
_tokenSource.Cancel();
_timedLoopTimer.Stop();
};
_timedLoopTimer.Disposed += (s, e) =>
{
_log.Info("Old timer disposed.");
};
_timedLoopTimer.Start();
WaitHandle.WaitAny(new[] { _threadToken.WaitHandle });
_timedLoopTimer.Stop();
_timedLoopTimer.Dispose();
return success;
}

View file

@ -0,0 +1,12 @@
// 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.
namespace Awake.Core
{
internal static class InternalConstants
{
internal const string AppName = "Awake";
internal const string FullAppName = "PowerToys " + AppName;
}
}

View file

@ -6,8 +6,10 @@ using System;
using System.Drawing;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using System.Windows.Forms;
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.
@ -16,32 +18,43 @@ namespace Awake.Core
{
internal static class TrayHelper
{
private static NotifyIcon? trayIcon;
private static readonly Logger _log;
private static NotifyIcon TrayIcon { get => trayIcon; set => trayIcon = value; }
private static NotifyIcon? _trayIcon;
private static SettingsUtils? moduleSettings;
private static NotifyIcon TrayIcon { get => _trayIcon; set => _trayIcon = value; }
private static SettingsUtils ModuleSettings { get => moduleSettings; set => moduleSettings = value; }
private static SettingsUtils? _moduleSettings;
private static SettingsUtils ModuleSettings { get => _moduleSettings; set => _moduleSettings = value; }
static TrayHelper()
{
_log = LogManager.GetCurrentClassLogger();
TrayIcon = new NotifyIcon();
ModuleSettings = new SettingsUtils();
}
public static void InitializeTray(string text, Icon icon, ContextMenuStrip? contextMenu = null)
{
System.Threading.Tasks.Task.Factory.StartNew(
Task.Factory.StartNew(
(tray) =>
{
((NotifyIcon?)tray).Text = text;
((NotifyIcon?)tray).Icon = icon;
((NotifyIcon?)tray).ContextMenuStrip = contextMenu;
((NotifyIcon?)tray).Visible = true;
{
((NotifyIcon?)tray).Text = text;
((NotifyIcon?)tray).Icon = icon;
((NotifyIcon?)tray).ContextMenuStrip = contextMenu;
((NotifyIcon?)tray).Visible = true;
Application.Run();
}, TrayIcon);
_log.Info("Setting up the tray.");
Application.Run();
_log.Info("Tray setup complete.");
}, TrayIcon);
}
public static void ClearTray()
{
TrayIcon.Icon = null;
TrayIcon.Dispose();
}
internal static void SetTray(string text, AwakeSettings settings)
@ -50,10 +63,10 @@ namespace Awake.Core
text,
settings.Properties.KeepDisplayOn,
settings.Properties.Mode,
PassiveKeepAwakeCallback(text),
IndefiniteKeepAwakeCallback(text),
TimedKeepAwakeCallback(text),
KeepDisplayOnCallback(text),
PassiveKeepAwakeCallback(InternalConstants.AppName),
IndefiniteKeepAwakeCallback(InternalConstants.AppName),
TimedKeepAwakeCallback(InternalConstants.AppName),
KeepDisplayOnCallback(InternalConstants.AppName),
ExitCallback());
}
@ -61,7 +74,7 @@ namespace Awake.Core
{
return () =>
{
Environment.Exit(0);
Environment.Exit(Environment.ExitCode);
};
}
@ -153,28 +166,21 @@ namespace Awake.Core
public static void SetTray(string text, bool keepDisplayOn, AwakeMode mode, Action passiveKeepAwakeCallback, Action indefiniteKeepAwakeCallback, Action<uint, uint> timedKeepAwakeCallback, Action keepDisplayOnCallback, Action exitCallback)
{
var contextMenuStrip = new ContextMenuStrip();
ContextMenuStrip? contextMenuStrip = new ContextMenuStrip();
// Main toolstrip.
var operationContextMenu = new ToolStripMenuItem
ToolStripMenuItem? operationContextMenu = new ToolStripMenuItem
{
Text = "Mode",
};
// No keep-awake menu item.
var passiveMenuItem = new ToolStripMenuItem
ToolStripMenuItem? passiveMenuItem = new ToolStripMenuItem
{
Text = "Off (Passive)",
};
if (mode == AwakeMode.PASSIVE)
{
passiveMenuItem.Checked = true;
}
else
{
passiveMenuItem.Checked = false;
}
passiveMenuItem.Checked = mode == AwakeMode.PASSIVE;
passiveMenuItem.Click += (e, s) =>
{
@ -183,19 +189,12 @@ namespace Awake.Core
};
// Indefinite keep-awake menu item.
var indefiniteMenuItem = new ToolStripMenuItem
ToolStripMenuItem? indefiniteMenuItem = new ToolStripMenuItem
{
Text = "Keep awake indefinitely",
};
if (mode == AwakeMode.INDEFINITE)
{
indefiniteMenuItem.Checked = true;
}
else
{
indefiniteMenuItem.Checked = false;
}
indefiniteMenuItem.Checked = mode == AwakeMode.INDEFINITE;
indefiniteMenuItem.Click += (e, s) =>
{
@ -203,18 +202,12 @@ namespace Awake.Core
indefiniteKeepAwakeCallback();
};
var displayOnMenuItem = new ToolStripMenuItem
ToolStripMenuItem? displayOnMenuItem = new ToolStripMenuItem
{
Text = "Keep screen on",
};
if (keepDisplayOn)
{
displayOnMenuItem.Checked = true;
}
else
{
displayOnMenuItem.Checked = false;
}
displayOnMenuItem.Checked = keepDisplayOn;
displayOnMenuItem.Click += (e, s) =>
{
@ -223,43 +216,40 @@ namespace Awake.Core
};
// Timed keep-awake menu item
var timedMenuItem = new ToolStripMenuItem
ToolStripMenuItem? timedMenuItem = new ToolStripMenuItem
{
Text = "Keep awake temporarily",
};
if (mode == AwakeMode.TIMED)
{
timedMenuItem.Checked = true;
}
else
{
timedMenuItem.Checked = false;
}
var halfHourMenuItem = new ToolStripMenuItem
timedMenuItem.Checked = mode == AwakeMode.TIMED;
ToolStripMenuItem? halfHourMenuItem = new ToolStripMenuItem
{
Text = "30 minutes",
};
halfHourMenuItem.Click += (e, s) =>
{
// User is setting the keep-awake to 30 minutes.
timedKeepAwakeCallback(0, 30);
};
var oneHourMenuItem = new ToolStripMenuItem
ToolStripMenuItem? oneHourMenuItem = new ToolStripMenuItem
{
Text = "1 hour",
};
oneHourMenuItem.Click += (e, s) =>
{
// User is setting the keep-awake to 1 hour.
timedKeepAwakeCallback(1, 0);
};
var twoHoursMenuItem = new ToolStripMenuItem
ToolStripMenuItem? twoHoursMenuItem = new ToolStripMenuItem
{
Text = "2 hours",
};
twoHoursMenuItem.Click += (e, s) =>
{
// User is setting the keep-awake to 2 hours.
@ -267,10 +257,11 @@ namespace Awake.Core
};
// Exit menu item.
var exitContextMenu = new ToolStripMenuItem
ToolStripMenuItem? exitContextMenu = new ToolStripMenuItem
{
Text = "Exit",
};
exitContextMenu.Click += (e, s) =>
{
// User is setting the keep-awake to 2 hours.

View file

@ -15,6 +15,7 @@ using System.Reflection;
using System.Threading;
using System.Windows;
using Awake.Core;
using interop;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using NLog;
@ -27,8 +28,6 @@ namespace Awake
internal class Program
{
private static Mutex? _mutex = null;
private const string AppName = "Awake";
private const string FullAppName = "PowerToys " + AppName;
private static FileSystemWatcher? _watcher = null;
private static SettingsUtils? _settingsUtils = null;
@ -36,17 +35,25 @@ namespace Awake
private static Logger? _log;
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
private static ConsoleEventHandler _handler;
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
private static ManualResetEvent _exitSignal = new ManualResetEvent(false);
private static int Main(string[] args)
{
bool instantiated;
LockMutex = new Mutex(true, AppName, out instantiated);
// Log initialization needs to always happen before we test whether
// only one instance of Awake is running.
_log = LogManager.GetCurrentClassLogger();
LockMutex = new Mutex(true, InternalConstants.AppName, out bool instantiated);
if (!instantiated)
{
ForceExit(AppName + " is already running! Exiting the application.", 1);
Exit(InternalConstants.AppName + " is already running! Exiting the application.", 1, true);
}
_log = LogManager.GetCurrentClassLogger();
_settingsUtils = new SettingsUtils();
_log.Info("Launching PowerToys Awake...");
@ -56,7 +63,7 @@ namespace Awake
_log.Info("Parsing parameters...");
var configOption = new Option<bool>(
Option<bool>? configOption = new Option<bool>(
aliases: new[] { "--use-pt-config", "-c" },
getDefaultValue: () => false,
description: "Specifies whether PowerToys Awake will be using the PowerToys configuration file for managing the state.")
@ -69,7 +76,7 @@ namespace Awake
configOption.Required = false;
var displayOption = new Option<bool>(
Option<bool>? displayOption = new Option<bool>(
aliases: new[] { "--display-on", "-d" },
getDefaultValue: () => true,
description: "Determines whether the display should be kept awake.")
@ -82,7 +89,7 @@ namespace Awake
displayOption.Required = false;
var timeOption = new Option<uint>(
Option<uint>? timeOption = new Option<uint>(
aliases: new[] { "--time-limit", "-t" },
getDefaultValue: () => 0,
description: "Determines the interval, in seconds, during which the computer is kept awake.")
@ -95,7 +102,7 @@ namespace Awake
timeOption.Required = false;
var pidOption = new Option<int>(
Option<int>? pidOption = new Option<int>(
aliases: new[] { "--pid", "-p" },
getDefaultValue: () => 0,
description: "Bind the execution of PowerToys Awake to another process.")
@ -108,7 +115,7 @@ namespace Awake
pidOption.Required = false;
var rootCommand = new RootCommand
RootCommand? rootCommand = new RootCommand
{
configOption,
displayOption,
@ -116,7 +123,7 @@ namespace Awake
pidOption,
};
rootCommand.Description = AppName;
rootCommand.Description = InternalConstants.AppName;
rootCommand.Handler = CommandHandler.Create<bool, bool, uint, int>(HandleCommandLineArguments);
@ -125,14 +132,38 @@ namespace Awake
return rootCommand.InvokeAsync(args).Result;
}
private static void ForceExit(string message, int exitCode)
private static bool ExitHandler(ControlType ctrlType)
{
_log.Info($"Exited through handler with control type: {ctrlType}");
Exit("Exiting from the internal termination handler.", Environment.ExitCode);
return false;
}
private static void Exit(string message, int exitCode, bool force = false)
{
_log.Info(message);
Environment.Exit(exitCode);
APIHelper.SetNoKeepAwake();
TrayHelper.ClearTray();
// Because we are running a message loop for the tray, we can't just use Environment.Exit,
// but have to make sure that we properly send the termination message.
bool cwResult = System.Diagnostics.Process.GetCurrentProcess().CloseMainWindow();
_log.Info($"Request to close main window status: {cwResult}");
if (force)
{
Environment.Exit(exitCode);
}
}
private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, uint timeLimit, int pid)
{
_handler += new ConsoleEventHandler(ExitHandler);
APIHelper.SetConsoleControlHandler(_handler, true);
if (pid == 0)
{
_log.Info("No PID specified. Allocating console...");
@ -150,11 +181,18 @@ namespace Awake
// and instead watch for changes in the file.
try
{
#pragma warning disable CS8604 // Possible null reference argument.
TrayHelper.InitializeTray(FullAppName, new Icon(Application.GetResourceStream(new Uri("/Images/Awake.ico", UriKind.Relative)).Stream));
#pragma warning restore CS8604 // Possible null reference argument.
new Thread(() =>
{
EventWaitHandle? eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.AwakeExitEvent());
if (eventHandle.WaitOne())
{
Exit("Received a signal to end the process. Making sure we quit...", 0, true);
}
}).Start();
var settingsPath = _settingsUtils.GetSettingsFilePath(AppName);
TrayHelper.InitializeTray(InternalConstants.FullAppName, new Icon(Application.GetResourceStream(new Uri("/Images/Awake.ico", UriKind.Relative)).Stream));
string? settingsPath = _settingsUtils.GetSettingsFilePath(InternalConstants.AppName);
_log.Info($"Reading configuration file: {settingsPath}");
_watcher = new FileSystemWatcher
@ -165,22 +203,22 @@ namespace Awake
Filter = Path.GetFileName(settingsPath),
};
var changedObservable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
IObservable<System.Reactive.EventPattern<FileSystemEventArgs>>? changedObservable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
h => _watcher.Changed += h,
h => _watcher.Changed -= h);
var createdObservable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
IObservable<System.Reactive.EventPattern<FileSystemEventArgs>>? createdObservable = Observable.FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
cre => _watcher.Created += cre,
cre => _watcher.Created -= cre);
var mergedObservable = Observable.Merge(changedObservable, createdObservable);
IObservable<System.Reactive.EventPattern<FileSystemEventArgs>>? mergedObservable = Observable.Merge(changedObservable, createdObservable);
mergedObservable.Throttle(TimeSpan.FromMilliseconds(25))
.SubscribeOn(TaskPoolScheduler.Default)
.Select(e => e.EventArgs)
.Subscribe(HandleAwakeConfigChange);
TrayHelper.SetTray(FullAppName, new AwakeSettings());
TrayHelper.SetTray(InternalConstants.FullAppName, new AwakeSettings());
// Initially the file might not be updated, so we need to start processing
// settings right away.
@ -188,14 +226,14 @@ namespace Awake
}
catch (Exception ex)
{
var errorString = $"There was a problem with the configuration file. Make sure it exists.\n{ex.Message}";
string? errorString = $"There was a problem with the configuration file. Make sure it exists.\n{ex.Message}";
_log.Info(errorString);
_log.Debug(errorString);
}
}
else
{
var mode = timeLimit <= 0 ? AwakeMode.INDEFINITE : AwakeMode.TIMED;
AwakeMode mode = timeLimit <= 0 ? AwakeMode.INDEFINITE : AwakeMode.TIMED;
if (mode == AwakeMode.INDEFINITE)
{
@ -207,22 +245,19 @@ namespace Awake
}
}
var exitSignal = new ManualResetEvent(false);
if (pid != 0)
{
RunnerHelper.WaitForPowerToysRunner(pid, () =>
{
exitSignal.Set();
Environment.Exit(0);
Exit("Terminating from PowerToys binding hook.", 0, true);
});
}
exitSignal.WaitOne();
_exitSignal.WaitOne();
}
private static void SetupIndefiniteKeepAwake(bool displayOn)
{
// Indefinite keep awake.
APIHelper.SetIndefiniteKeepAwake(LogCompletedKeepAwakeThread, LogUnexpectedOrCancelledKeepAwakeThreadCompletion, displayOn);
}
@ -237,7 +272,7 @@ namespace Awake
{
try
{
AwakeSettings settings = _settingsUtils.GetSettings<AwakeSettings>(AppName);
AwakeSettings settings = _settingsUtils.GetSettings<AwakeSettings>(InternalConstants.AppName);
if (settings != null)
{
@ -251,14 +286,12 @@ namespace Awake
case AwakeMode.INDEFINITE:
{
// Indefinite keep awake.
SetupIndefiniteKeepAwake(settings.Properties.KeepDisplayOn);
break;
}
case AwakeMode.TIMED:
{
// Timed keep-awake.
uint computedTime = (settings.Properties.Hours * 60 * 60) + (settings.Properties.Minutes * 60);
SetupTimedKeepAwake(computedTime, settings.Properties.KeepDisplayOn);
@ -267,25 +300,25 @@ namespace Awake
default:
{
var errorMessage = "Unknown mode of operation. Check config file.";
string? errorMessage = "Unknown mode of operation. Check config file.";
_log.Info(errorMessage);
_log.Debug(errorMessage);
break;
}
}
TrayHelper.SetTray(FullAppName, settings);
TrayHelper.SetTray(InternalConstants.FullAppName, settings);
}
else
{
var errorMessage = "Settings are null.";
string? errorMessage = "Settings are null.";
_log.Info(errorMessage);
_log.Debug(errorMessage);
}
}
catch (Exception ex)
{
var errorMessage = $"There was a problem reading the configuration file. Error: {ex.GetType()} {ex.Message}";
string? errorMessage = $"There was a problem reading the configuration file. Error: {ex.GetType()} {ex.Message}";
_log.Info(errorMessage);
_log.Debug(errorMessage);
}
@ -307,7 +340,7 @@ namespace Awake
private static void LogUnexpectedOrCancelledKeepAwakeThreadCompletion()
{
var errorMessage = "The keep-awake thread was terminated early.";
string? errorMessage = "The keep-awake thread was terminated early.";
_log.Info(errorMessage);
_log.Debug(errorMessage);
}

View file

@ -15,6 +15,7 @@
#include <common/utils/winapi_error.h>
#include <filesystem>
#include <set>
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
@ -33,34 +34,23 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
return TRUE;
}
// The PowerToy name that will be shown in the settings.
const static wchar_t* MODULE_NAME = L"Awake";
// Add a description that will we shown in the module settings page.
const static wchar_t* MODULE_DESC = L"A module that keeps your computer awake on-demand.";
// Implement the PowerToy Module Interface and all the required methods.
class Awake : public PowertoyModuleIface
{
std::wstring app_name;
// Contains the non localized key of the powertoy
std::wstring app_key;
private:
// The PowerToy state.
bool m_enabled = false;
HANDLE m_hProcess;
HANDLE send_telemetry_event;
// Handle to event used to invoke PowerToys Awake
HANDLE m_hInvokeEvent;
PROCESS_INFORMATION p_info;
bool is_process_running()
{
return WaitForSingleObject(m_hProcess, 0) == WAIT_TIMEOUT;
return WaitForSingleObject(p_info.hProcess, 0) == WAIT_TIMEOUT;
}
void launch_process()
@ -69,26 +59,22 @@ private:
unsigned long powertoys_pid = GetCurrentProcessId();
std::wstring executable_args = L"--use-pt-config --pid " + std::to_wstring(powertoys_pid);
std::wstring application_path = L"modules\\Awake\\PowerToys.Awake.exe";
std::wstring full_command_path = application_path + L" " + executable_args.data();
Logger::trace(L"PowerToys Awake launching with parameters: " + executable_args);
SHELLEXECUTEINFOW sei{ sizeof(sei) };
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
sei.lpFile = L"modules\\Awake\\PowerToys.Awake.exe";
sei.nShow = SW_SHOWNORMAL;
sei.lpParameters = executable_args.data();
if (!ShellExecuteExW(&sei))
STARTUPINFO info = { sizeof(info) };
if (!CreateProcess(application_path.c_str(), full_command_path.data(), NULL, NULL, true, NULL, NULL, NULL, &info, &p_info))
{
DWORD error = GetLastError();
std::wstring message = L"PowerToys Awake failed to start with error = ";
std::wstring message = L"PowerToys Awake failed to start with error: ";
message += std::to_wstring(error);
Logger::error(message);
}
m_hProcess = sei.hProcess;
}
public:
// Constructor
Awake()
{
app_name = GET_RESOURCE_STRING(IDS_AWAKE_NAME);
@ -99,37 +85,31 @@ public:
Logger::info("Launcher object is constructing");
};
// Destroy the powertoy and free memory
virtual void destroy() override
{
delete this;
}
// Return the display name of the powertoy, this will be cached by the runner
virtual const wchar_t* get_name() override
{
return MODULE_NAME;
}
// Return JSON with the configuration options.
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
{
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
// Create a Settings object.
PowerToysSettings::Settings settings(hinstance, get_name());
settings.set_description(MODULE_DESC);
return settings.serialize_to_buffer(buffer, buffer_size);
}
// Return the non localized key of the powertoy, this will be cached by the runner
virtual const wchar_t* get_key() override
{
return app_key.c_str();
}
// Called by the runner to pass the updated settings values as a serialized JSON.
virtual void set_config(const wchar_t* config) override
{
try
@ -139,7 +119,7 @@ public:
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
// If you don't need to do any custom processing of the settings, proceed
// to persists the values calling:
// to persists the values.
values.save_to_settings_file();
}
catch (std::exception&)
@ -160,15 +140,36 @@ public:
{
if (m_enabled)
{
Logger::trace(L"Disabling Awake...");
ResetEvent(send_telemetry_event);
ResetEvent(m_hInvokeEvent);
TerminateProcess(m_hProcess, 1);
auto exitEvent = CreateEvent(nullptr, false, false, CommonSharedConstants::AWAKE_EXIT_EVENT);
if (!exitEvent)
{
Logger::warn(L"Failed to create exit event for PowerToys Awake. {}", get_last_error_or_default(GetLastError()));
}
else
{
Logger::trace(L"Signaled exit event for PowerToys Awake.");
if (!SetEvent(exitEvent))
{
Logger::warn(L"Failed to signal exit event for PowerToys Awake. {}", get_last_error_or_default(GetLastError()));
// For some reason, we couldn't process the signal correctly, so we still
// need to terminate the Awake process.
TerminateProcess(p_info.hProcess, 1);
}
ResetEvent(exitEvent);
CloseHandle(exitEvent);
CloseHandle(p_info.hProcess);
}
}
m_enabled = false;
}
// Returns if the powertoys is enabled
virtual bool is_enabled() override
{
return m_enabled;

View file

@ -58,7 +58,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
OnPropertyChanged(nameof(IsEnabled));
OnPropertyChanged(nameof(IsTimeConfigurationEnabled));
var outgoing = new OutGoingGeneralSettings(GeneralSettingsConfig);
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(GeneralSettingsConfig);
SendConfigMSG(outgoing.ToString());
NotifyPropertyChanged();
}
@ -143,7 +143,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library.ViewModels
SndAwakeSettings outsettings = new SndAwakeSettings(Settings);
SndModuleSettings<SndAwakeSettings> ipcMessage = new SndModuleSettings<SndAwakeSettings>(outsettings);
var targetMessage = ipcMessage.ToJsonString();
string targetMessage = ipcMessage.ToJsonString();
SendConfigMSG(targetMessage);
}
}