From 3df2c5fe6a84514bff25adfc0e31a1de84c2c906 Mon Sep 17 00:00:00 2001
From: Den Delimarsky <1389609+dend@users.noreply.github.com>
Date: Sat, 12 Feb 2022 10:42:14 -0800
Subject: [PATCH] PowerToys Awake - Improved Logging/Minor Bug Fixes (#15875)
* Some code cleanup
* Making sure that the native wrapper lives in Awake.Core
* Adding power state logging, as well as termination entries.
* Better logging.
* Typos and logging improvements
* Remove dependency
---
src/modules/awake/Awake/Core/APIHelper.cs | 30 ++------
.../Core/Models/BatteryReportingScale.cs | 12 ++++
.../awake/Awake/Core/Models/ControlType.cs | 16 +++++
.../awake/Awake/Core/Models/ExecutionState.cs | 17 +++++
.../Core/Models/SystemPowerCapabilities.cs | 70 +++++++++++++++++++
.../Awake/Core/Models/SystemPowerState.cs | 20 ++++++
.../awake/Awake/{ => Core}/NativeMethods.cs | 6 +-
src/modules/awake/Awake/NLog.config | 4 +-
src/modules/awake/Awake/Program.cs | 37 +++++++---
9 files changed, 174 insertions(+), 38 deletions(-)
create mode 100644 src/modules/awake/Awake/Core/Models/BatteryReportingScale.cs
create mode 100644 src/modules/awake/Awake/Core/Models/ControlType.cs
create mode 100644 src/modules/awake/Awake/Core/Models/ExecutionState.cs
create mode 100644 src/modules/awake/Awake/Core/Models/SystemPowerCapabilities.cs
create mode 100644 src/modules/awake/Awake/Core/Models/SystemPowerState.cs
rename src/modules/awake/Awake/{ => Core}/NativeMethods.cs (83%)
diff --git a/src/modules/awake/Awake/Core/APIHelper.cs b/src/modules/awake/Awake/Core/APIHelper.cs
index 4f6d7ba8fa..49bc7a34cf 100644
--- a/src/modules/awake/Awake/Core/APIHelper.cs
+++ b/src/modules/awake/Awake/Core/APIHelper.cs
@@ -7,30 +7,12 @@ using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
+using Awake.Core.Models;
using Microsoft.Win32;
using NLog;
namespace Awake.Core
{
- [Flags]
- public enum EXECUTION_STATE : uint
- {
- ES_AWAYMODE_REQUIRED = 0x00000040,
- ES_CONTINUOUS = 0x80000000,
- ES_DISPLAY_REQUIRED = 0x00000002,
- 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);
///
@@ -85,7 +67,7 @@ namespace Awake.Core
///
/// Single or multiple EXECUTION_STATE entries.
/// true if successful, false if failed
- private static bool SetAwakeState(EXECUTION_STATE state)
+ private static bool SetAwakeState(ExecutionState state)
{
try
{
@@ -168,11 +150,11 @@ namespace Awake.Core
bool success;
if (keepDisplayOn)
{
- success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
+ success = SetAwakeState(ExecutionState.ES_SYSTEM_REQUIRED | ExecutionState.ES_DISPLAY_REQUIRED | ExecutionState.ES_CONTINUOUS);
}
else
{
- success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
+ success = SetAwakeState(ExecutionState.ES_SYSTEM_REQUIRED | ExecutionState.ES_CONTINUOUS);
}
try
@@ -209,11 +191,11 @@ namespace Awake.Core
{
if (keepDisplayOn)
{
- success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
+ success = SetAwakeState(ExecutionState.ES_SYSTEM_REQUIRED | ExecutionState.ES_DISPLAY_REQUIRED | ExecutionState.ES_CONTINUOUS);
}
else
{
- success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
+ success = SetAwakeState(ExecutionState.ES_SYSTEM_REQUIRED | ExecutionState.ES_CONTINUOUS);
}
if (success)
diff --git a/src/modules/awake/Awake/Core/Models/BatteryReportingScale.cs b/src/modules/awake/Awake/Core/Models/BatteryReportingScale.cs
new file mode 100644
index 0000000000..1520662e47
--- /dev/null
+++ b/src/modules/awake/Awake/Core/Models/BatteryReportingScale.cs
@@ -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.Models
+{
+ public struct BatteryReportingScale
+ {
+ public uint Granularity;
+ public uint Capacity;
+ }
+}
diff --git a/src/modules/awake/Awake/Core/Models/ControlType.cs b/src/modules/awake/Awake/Core/Models/ControlType.cs
new file mode 100644
index 0000000000..5f05345cb0
--- /dev/null
+++ b/src/modules/awake/Awake/Core/Models/ControlType.cs
@@ -0,0 +1,16 @@
+// 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.Models
+{
+ // 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,
+ }
+}
diff --git a/src/modules/awake/Awake/Core/Models/ExecutionState.cs b/src/modules/awake/Awake/Core/Models/ExecutionState.cs
new file mode 100644
index 0000000000..3c5ab849f1
--- /dev/null
+++ b/src/modules/awake/Awake/Core/Models/ExecutionState.cs
@@ -0,0 +1,17 @@
+// 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;
+
+namespace Awake.Core.Models
+{
+ [Flags]
+ public enum ExecutionState : uint
+ {
+ ES_AWAYMODE_REQUIRED = 0x00000040,
+ ES_CONTINUOUS = 0x80000000,
+ ES_DISPLAY_REQUIRED = 0x00000002,
+ ES_SYSTEM_REQUIRED = 0x00000001,
+ }
+}
diff --git a/src/modules/awake/Awake/Core/Models/SystemPowerCapabilities.cs b/src/modules/awake/Awake/Core/Models/SystemPowerCapabilities.cs
new file mode 100644
index 0000000000..c803941130
--- /dev/null
+++ b/src/modules/awake/Awake/Core/Models/SystemPowerCapabilities.cs
@@ -0,0 +1,70 @@
+// 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.Runtime.InteropServices;
+
+namespace Awake.Core.Models
+{
+ public struct SystemPowerCapabilities
+ {
+ [MarshalAs(UnmanagedType.U1)]
+ public bool PowerButtonPresent;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool SleepButtonPresent;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool LidPresent;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool SystemS1;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool SystemS2;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool SystemS3;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool SystemS4;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool SystemS5;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool HiberFilePresent;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool FullWake;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool VideoDimPresent;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool ApmPresent;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool UpsPresent;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool ThermalControl;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool ProcessorThrottle;
+ public byte ProcessorMinThrottle;
+ public byte ProcessorMaxThrottle;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool FastSystemS4;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool Hiberboot;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool WakeAlarmPresent;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool AoAc;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool DiskSpinDown;
+ public byte HiberFileType;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool AoAcConnectivitySupported;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
+ private readonly byte[] spare3;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool SystemBatteriesPresent;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool BatteriesAreShortTerm;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public BatteryReportingScale[] BatteryScale;
+ public SystemPowerState AcOnLineWake;
+ public SystemPowerState SoftLidWake;
+ public SystemPowerState RtcWake;
+ public SystemPowerState MinDeviceWakeState;
+ public SystemPowerState DefaultLowLatencyWake;
+ }
+}
diff --git a/src/modules/awake/Awake/Core/Models/SystemPowerState.cs b/src/modules/awake/Awake/Core/Models/SystemPowerState.cs
new file mode 100644
index 0000000000..337333612f
--- /dev/null
+++ b/src/modules/awake/Awake/Core/Models/SystemPowerState.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.
+
+namespace Awake.Core.Models
+{
+ // Maps to the OS power state.
+ // See documentation: https://docs.microsoft.com/windows/win32/power/system-power-states
+ public enum SystemPowerState
+ {
+ PowerSystemUnspecified = 0,
+ PowerSystemWorking = 1,
+ PowerSystemSleeping1 = 2,
+ PowerSystemSleeping2 = 3,
+ PowerSystemSleeping3 = 4,
+ PowerSystemHibernate = 5,
+ PowerSystemShutdown = 6,
+ PowerSystemMaximum = 7,
+ }
+}
diff --git a/src/modules/awake/Awake/NativeMethods.cs b/src/modules/awake/Awake/Core/NativeMethods.cs
similarity index 83%
rename from src/modules/awake/Awake/NativeMethods.cs
rename to src/modules/awake/Awake/Core/NativeMethods.cs
index 2f0bc0d107..4b80608f5b 100644
--- a/src/modules/awake/Awake/NativeMethods.cs
+++ b/src/modules/awake/Awake/Core/NativeMethods.cs
@@ -5,16 +5,20 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
+using Awake.Core.Models;
namespace Awake.Core
{
internal static class NativeMethods
{
+ [DllImport("PowrProf.dll", SetLastError = true)]
+ internal static extern bool GetPwrCapabilities(out SystemPowerCapabilities lpSystemPowerCapabilities);
+
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool SetConsoleCtrlHandler(ConsoleEventHandler handler, bool add);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
- internal static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
+ internal static extern ExecutionState SetThreadExecutionState(ExecutionState esFlags);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
diff --git a/src/modules/awake/Awake/NLog.config b/src/modules/awake/Awake/NLog.config
index 5d19f72d81..f58ab302e5 100644
--- a/src/modules/awake/Awake/NLog.config
+++ b/src/modules/awake/Awake/NLog.config
@@ -2,12 +2,12 @@
-
+
? configOption = new Option(
+ Option? configOption = new (
aliases: new[] { "--use-pt-config", "-c" },
getDefaultValue: () => false,
- description: "Specifies whether PowerToys Awake will be using the PowerToys configuration file for managing the state.")
+ description: $"Specifies whether {InternalConstants.AppName} will be using the PowerToys configuration file for managing the state.")
{
Argument = new Argument(() => false)
{
@@ -76,7 +92,7 @@ namespace Awake
configOption.Required = false;
- Option? displayOption = new Option(
+ Option? displayOption = new (
aliases: new[] { "--display-on", "-d" },
getDefaultValue: () => true,
description: "Determines whether the display should be kept awake.")
@@ -89,7 +105,7 @@ namespace Awake
displayOption.Required = false;
- Option? timeOption = new Option(
+ Option? timeOption = new (
aliases: new[] { "--time-limit", "-t" },
getDefaultValue: () => 0,
description: "Determines the interval, in seconds, during which the computer is kept awake.")
@@ -102,10 +118,10 @@ namespace Awake
timeOption.Required = false;
- Option? pidOption = new Option(
+ Option? pidOption = new (
aliases: new[] { "--pid", "-p" },
getDefaultValue: () => 0,
- description: "Bind the execution of PowerToys Awake to another process.")
+ description: $"Bind the execution of {InternalConstants.AppName} to another process.")
{
Argument = new Argument(() => 0)
{
@@ -135,9 +151,7 @@ namespace Awake
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;
}
@@ -251,7 +265,8 @@ namespace Awake
{
RunnerHelper.WaitForPowerToysRunner(pid, () =>
{
- Exit("Terminating from PowerToys binding hook.", 0, true);
+ _log.Info($"Triggered PID-based exit handler for PID {pid}.");
+ Exit("Terminating from process binding hook.", 0, true);
});
}