mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 19:57:57 +01:00
Don't use Environment.Exit (#20532)
* [Awake] Don't use Process.Exit and move to CsWin32 * [PowerLauncher] Remove unused API * [ColorPicker] Use cancellable NativeEventWaiter + cleanup using * [TextExtractor] Don't use Environment.Exit * [MeasureTool] Don't use Environment.Exit(0); * [FZE] don't use Environment.Exit and fix WaitForPowerToysRunner
This commit is contained in:
15
.github/actions/spell-check/expect.txt
vendored
15
.github/actions/spell-check/expect.txt
vendored
@@ -60,7 +60,6 @@ APeriod
|
||||
api
|
||||
APIENTRY
|
||||
APIIs
|
||||
Apm
|
||||
APPBARDATA
|
||||
appdata
|
||||
APPICON
|
||||
@@ -130,7 +129,6 @@ Avanc
|
||||
Awaitable
|
||||
awakeness
|
||||
awakeversion
|
||||
AWAYMODE
|
||||
AYUV
|
||||
backend
|
||||
backtracer
|
||||
@@ -498,7 +496,6 @@ dvr
|
||||
DVSD
|
||||
DVSL
|
||||
DVTARGETDEVICE
|
||||
dwhkl
|
||||
DWINRT
|
||||
dwl
|
||||
dwm
|
||||
@@ -728,8 +725,6 @@ hhk
|
||||
HHmmss
|
||||
HHOOK
|
||||
hhx
|
||||
Hiber
|
||||
Hiberboot
|
||||
HIBYTE
|
||||
HICON
|
||||
HIDEWINDOW
|
||||
@@ -907,7 +902,6 @@ inheritdoc
|
||||
initguid
|
||||
Inkscape
|
||||
Inlines
|
||||
Inlining
|
||||
inorder
|
||||
INotification
|
||||
INotify
|
||||
@@ -1037,7 +1031,6 @@ jxr
|
||||
jyuwono
|
||||
KBDLLHOOKSTRUCT
|
||||
kbm
|
||||
KCode
|
||||
KEYBDINPUT
|
||||
keybindings
|
||||
keyboardeventhandlers
|
||||
@@ -1161,7 +1154,6 @@ lpsz
|
||||
lpt
|
||||
LPTHREAD
|
||||
LPTOP
|
||||
lptpm
|
||||
LPTSTR
|
||||
LPVOID
|
||||
LPW
|
||||
@@ -1226,7 +1218,6 @@ Melman
|
||||
memcmp
|
||||
memcpy
|
||||
memset
|
||||
MENUBREAK
|
||||
MENUITEMINFO
|
||||
MENUITEMINFOW
|
||||
Metadatas
|
||||
@@ -1432,7 +1423,6 @@ ntdll
|
||||
NTFS
|
||||
NTSTATUS
|
||||
nuget
|
||||
nuint
|
||||
nullonfailure
|
||||
nullopt
|
||||
nullptr
|
||||
@@ -1494,7 +1484,6 @@ overlaywindow
|
||||
Overridable
|
||||
Oversampling
|
||||
OWNDC
|
||||
OWNERDRAW
|
||||
PACL
|
||||
pagos
|
||||
PAINTSTRUCT
|
||||
@@ -1536,6 +1525,7 @@ pfo
|
||||
pft
|
||||
pgp
|
||||
pguid
|
||||
PHANDLER
|
||||
phbm
|
||||
phbmp
|
||||
phwnd
|
||||
@@ -1938,6 +1928,7 @@ sse
|
||||
ssf
|
||||
ssh
|
||||
sstream
|
||||
stackalloc
|
||||
STACKFRAME
|
||||
stackoverflow
|
||||
stackpanel
|
||||
@@ -2237,14 +2228,12 @@ VIDEOINFOHEADER
|
||||
viewbox
|
||||
viewmodel
|
||||
vih
|
||||
Virt
|
||||
virtualization
|
||||
Virtualizing
|
||||
visiblecolorformats
|
||||
Visibletrue
|
||||
visualbrush
|
||||
visualstudio
|
||||
viter
|
||||
VKey
|
||||
VKTAB
|
||||
vmovl
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
using ControlzEx.Theming;
|
||||
|
||||
namespace Common.UI
|
||||
|
||||
@@ -3,26 +3,24 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using Wox.Plugin.Logger;
|
||||
|
||||
namespace PowerLauncher.Helper
|
||||
using Dispatcher = System.Windows.Threading.Dispatcher;
|
||||
|
||||
namespace Common.UI
|
||||
{
|
||||
public static class NativeEventWaiter
|
||||
{
|
||||
public static void WaitForEventLoop(string eventName, Action callback, CancellationToken cancel)
|
||||
public static void WaitForEventLoop(string eventName, Action callback, Dispatcher dispatcher, CancellationToken cancel)
|
||||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName);
|
||||
var eventHandle = new EventWaitHandle(false, EventResetMode.ManualReset, eventName);
|
||||
while (true)
|
||||
{
|
||||
if (WaitHandle.WaitAny(new WaitHandle[] { cancel.WaitHandle, eventHandle }) == 1)
|
||||
{
|
||||
Log.Info($"Successfully waited for {eventName}", MethodBase.GetCurrentMethod().DeclaringType);
|
||||
Application.Current.Dispatcher.Invoke(callback);
|
||||
dispatcher.BeginInvoke(callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -5,6 +5,7 @@
|
||||
using System;
|
||||
using ManagedCommon;
|
||||
using MeasureToolUI.Helpers;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
namespace MeasureToolUI
|
||||
@@ -36,9 +37,10 @@ namespace MeasureToolUI
|
||||
{
|
||||
if (int.TryParse(cmdArgs[cmdArgs.Length - 1], out int powerToysRunnerPid))
|
||||
{
|
||||
var dispatcher = DispatcherQueue.GetForCurrentThread();
|
||||
RunnerHelper.WaitForPowerToysRunner(powerToysRunnerPid, () =>
|
||||
{
|
||||
Environment.Exit(0);
|
||||
dispatcher.TryEnqueue(App.Current.Exit);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -51,7 +53,8 @@ namespace MeasureToolUI
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"MeasureToolCore failed to initialize: {ex}");
|
||||
Environment.Exit(1);
|
||||
App.Current.Exit();
|
||||
return;
|
||||
}
|
||||
|
||||
_window = new MainWindow(core);
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using ManagedCommon;
|
||||
@@ -23,6 +22,13 @@ public partial class App : Application, IDisposable
|
||||
private Mutex? _instanceMutex;
|
||||
private int _powerToysRunnerPid;
|
||||
|
||||
private CancellationTokenSource NativeThreadCTS { get; set; }
|
||||
|
||||
public App()
|
||||
{
|
||||
NativeThreadCTS = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
@@ -37,7 +43,7 @@ public partial class App : Application, IDisposable
|
||||
{
|
||||
Logger.LogWarning("Another running TextExtractor instance was detected. Exiting TextExtractor");
|
||||
_instanceMutex = null;
|
||||
Environment.Exit(0);
|
||||
Shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -51,10 +57,11 @@ public partial class App : Application, IDisposable
|
||||
RunnerHelper.WaitForPowerToysRunner(_powerToysRunnerPid, () =>
|
||||
{
|
||||
Logger.LogInfo("PowerToys Runner exited. Exiting TextExtractor");
|
||||
Environment.Exit(0);
|
||||
NativeThreadCTS.Cancel();
|
||||
Application.Current.Dispatcher.Invoke(() => Shutdown());
|
||||
});
|
||||
var userSettings = new UserSettings(new Helpers.ThrottledActionInvoker());
|
||||
eventMonitor = new EventMonitor();
|
||||
eventMonitor = new EventMonitor(Application.Current.Dispatcher, NativeThreadCTS.Token);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
// 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.Threading;
|
||||
using System.Windows;
|
||||
|
||||
namespace PowerOCR.Helpers
|
||||
{
|
||||
public static class NativeEventWaiter
|
||||
{
|
||||
public static void WaitForEventLoop(string eventName, Action callback)
|
||||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName);
|
||||
while (true)
|
||||
{
|
||||
if (eventHandle.WaitOne())
|
||||
{
|
||||
Logger.LogInfo($"Successfully waited for {eventName}");
|
||||
Application.Current.Dispatcher.Invoke(callback);
|
||||
}
|
||||
}
|
||||
}).Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
using System;
|
||||
using System.Windows.Interop;
|
||||
using Common.UI;
|
||||
using interop;
|
||||
using PowerOCR.Helpers;
|
||||
using PowerOCR.Utilities;
|
||||
@@ -16,9 +17,9 @@ namespace PowerOCR.Keyboard
|
||||
/// </summary>
|
||||
internal class EventMonitor
|
||||
{
|
||||
public EventMonitor()
|
||||
public EventMonitor(System.Windows.Threading.Dispatcher dispatcher, System.Threading.CancellationToken exitToken)
|
||||
{
|
||||
NativeEventWaiter.WaitForEventLoop(Constants.ShowPowerOCRSharedEvent(), StartOCRSession);
|
||||
NativeEventWaiter.WaitForEventLoop(Constants.ShowPowerOCRSharedEvent(), StartOCRSession, dispatcher, exitToken);
|
||||
}
|
||||
|
||||
public void StartOCRSession()
|
||||
|
||||
@@ -43,6 +43,9 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.46-beta">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="NLog" Version="4.7.13" />
|
||||
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20071.2" />
|
||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||
|
||||
@@ -7,17 +7,20 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Awake.Core.Models;
|
||||
using Microsoft.Win32;
|
||||
using NLog;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.Storage.FileSystem;
|
||||
using Windows.Win32.System.Console;
|
||||
using Windows.Win32.System.Power;
|
||||
|
||||
namespace Awake.Core
|
||||
{
|
||||
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.
|
||||
@@ -25,9 +28,6 @@ namespace Awake.Core
|
||||
public class APIHelper
|
||||
{
|
||||
private const string BuildRegistryLocation = @"SOFTWARE\Microsoft\Windows NT\CurrentVersion";
|
||||
private const int StdOutputHandle = -11;
|
||||
private const uint GenericWrite = 0x40000000;
|
||||
private const uint GenericRead = 0x80000000;
|
||||
|
||||
private static readonly Logger _log;
|
||||
private static CancellationTokenSource _tokenSource;
|
||||
@@ -43,21 +43,21 @@ namespace Awake.Core
|
||||
_tokenSource = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
public static void SetConsoleControlHandler(ConsoleEventHandler handler, bool addHandler)
|
||||
internal static void SetConsoleControlHandler(PHANDLER_ROUTINE handler, bool addHandler)
|
||||
{
|
||||
NativeMethods.SetConsoleCtrlHandler(handler, addHandler);
|
||||
PInvoke.SetConsoleCtrlHandler(handler, addHandler);
|
||||
}
|
||||
|
||||
public static void AllocateConsole()
|
||||
{
|
||||
_log.Debug("Bootstrapping the console allocation routine.");
|
||||
NativeMethods.AllocConsole();
|
||||
PInvoke.AllocConsole();
|
||||
_log.Debug($"Console allocation result: {Marshal.GetLastWin32Error()}");
|
||||
|
||||
var outputFilePointer = NativeMethods.CreateFile("CONOUT$", GenericRead | GenericWrite, FileShare.Write, IntPtr.Zero, FileMode.OpenOrCreate, 0, IntPtr.Zero);
|
||||
var outputFilePointer = PInvoke.CreateFile("CONOUT$", FILE_ACCESS_FLAGS.FILE_GENERIC_READ | FILE_ACCESS_FLAGS.FILE_GENERIC_WRITE, FILE_SHARE_MODE.FILE_SHARE_WRITE, null, FILE_CREATION_DISPOSITION.OPEN_EXISTING, 0, null);
|
||||
_log.Debug($"CONOUT creation result: {Marshal.GetLastWin32Error()}");
|
||||
|
||||
NativeMethods.SetStdHandle(StdOutputHandle, outputFilePointer);
|
||||
PInvoke.SetStdHandle(Windows.Win32.System.Console.STD_HANDLE.STD_OUTPUT_HANDLE, outputFilePointer);
|
||||
_log.Debug($"SetStdHandle result: {Marshal.GetLastWin32Error()}");
|
||||
|
||||
Console.SetOut(new StreamWriter(Console.OpenStandardOutput(), Console.OutputEncoding) { AutoFlush = true });
|
||||
@@ -70,11 +70,11 @@ namespace Awake.Core
|
||||
/// </summary>
|
||||
/// <param name="state">Single or multiple EXECUTION_STATE entries.</param>
|
||||
/// <returns>true if successful, false if failed</returns>
|
||||
private static bool SetAwakeState(ExecutionState state)
|
||||
private static bool SetAwakeState(EXECUTION_STATE state)
|
||||
{
|
||||
try
|
||||
{
|
||||
var stateResult = NativeMethods.SetThreadExecutionState(state);
|
||||
var stateResult = PInvoke.SetThreadExecutionState(state);
|
||||
return stateResult != 0;
|
||||
}
|
||||
catch
|
||||
@@ -160,18 +160,18 @@ namespace Awake.Core
|
||||
bool success;
|
||||
if (keepDisplayOn)
|
||||
{
|
||||
success = SetAwakeState(ExecutionState.ES_SYSTEM_REQUIRED | ExecutionState.ES_DISPLAY_REQUIRED | ExecutionState.ES_CONTINUOUS);
|
||||
success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = SetAwakeState(ExecutionState.ES_SYSTEM_REQUIRED | ExecutionState.ES_CONTINUOUS);
|
||||
success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
_log.Info($"Initiated indefinite keep awake in background thread: {NativeMethods.GetCurrentThreadId()}. Screen on: {keepDisplayOn}");
|
||||
_log.Info($"Initiated indefinite keep awake in background thread: {PInvoke.GetCurrentThreadId()}. Screen on: {keepDisplayOn}");
|
||||
|
||||
WaitHandle.WaitAny(new[] { _threadToken.WaitHandle });
|
||||
|
||||
@@ -186,28 +186,35 @@ namespace Awake.Core
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
// Task was clearly cancelled.
|
||||
_log.Info($"Background thread termination: {NativeMethods.GetCurrentThreadId()}. Message: {ex.Message}");
|
||||
_log.Info($"Background thread termination: {PInvoke.GetCurrentThreadId()}. Message: {ex.Message}");
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void CompleteExit(int exitCode, bool force = false)
|
||||
internal static void CompleteExit(int exitCode, ManualResetEvent? exitSignal, bool force = false)
|
||||
{
|
||||
APIHelper.SetNoKeepAwake();
|
||||
TrayHelper.ClearTray();
|
||||
SetNoKeepAwake();
|
||||
|
||||
// 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.
|
||||
IntPtr windowHandle = APIHelper.GetHiddenWindow();
|
||||
HWND windowHandle = GetHiddenWindow();
|
||||
|
||||
if (windowHandle != IntPtr.Zero)
|
||||
if (windowHandle != HWND.Null)
|
||||
{
|
||||
NativeMethods.SendMessage(windowHandle, NativeConstants.WM_CLOSE, 0, string.Empty);
|
||||
PInvoke.SendMessage(windowHandle, PInvoke.WM_CLOSE, 0, 0);
|
||||
}
|
||||
|
||||
if (force)
|
||||
{
|
||||
Environment.Exit(exitCode);
|
||||
PInvoke.PostQuitMessage(0);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
exitSignal?.Set();
|
||||
PInvoke.DestroyWindow(windowHandle);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Info($"Exit signal error ${ex}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,18 +228,18 @@ namespace Awake.Core
|
||||
{
|
||||
if (keepDisplayOn)
|
||||
{
|
||||
success = SetAwakeState(ExecutionState.ES_SYSTEM_REQUIRED | ExecutionState.ES_DISPLAY_REQUIRED | ExecutionState.ES_CONTINUOUS);
|
||||
success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_DISPLAY_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = SetAwakeState(ExecutionState.ES_SYSTEM_REQUIRED | ExecutionState.ES_CONTINUOUS);
|
||||
success = SetAwakeState(EXECUTION_STATE.ES_SYSTEM_REQUIRED | EXECUTION_STATE.ES_CONTINUOUS);
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
_log.Info($"Initiated temporary keep awake in background thread: {NativeMethods.GetCurrentThreadId()}. Screen on: {keepDisplayOn}");
|
||||
_log.Info($"Initiated temporary keep awake in background thread: {PInvoke.GetCurrentThreadId()}. Screen on: {keepDisplayOn}");
|
||||
|
||||
_timedLoopTimer = new System.Timers.Timer(seconds * 1000);
|
||||
_timedLoopTimer = new System.Timers.Timer((seconds * 1000) + 1);
|
||||
_timedLoopTimer.Elapsed += (s, e) =>
|
||||
{
|
||||
_tokenSource.Cancel();
|
||||
@@ -262,7 +269,7 @@ namespace Awake.Core
|
||||
catch (OperationCanceledException ex)
|
||||
{
|
||||
// Task was clearly cancelled.
|
||||
_log.Info($"Background thread termination: {NativeMethods.GetCurrentThreadId()}. Message: {ex.Message}");
|
||||
_log.Info($"Background thread termination: {PInvoke.GetCurrentThreadId()}. Message: {ex.Message}");
|
||||
return success;
|
||||
}
|
||||
}
|
||||
@@ -294,15 +301,20 @@ namespace Awake.Core
|
||||
}
|
||||
|
||||
[SuppressMessage("Performance", "CA1806:Do not ignore method results", Justification = "Function returns DWORD value that identifies the current thread, but we do not need it.")]
|
||||
public static IEnumerable<IntPtr> EnumerateWindowsForProcess(int processId)
|
||||
internal static IEnumerable<HWND> EnumerateWindowsForProcess(int processId)
|
||||
{
|
||||
var handles = new List<IntPtr>();
|
||||
IntPtr hCurrentWnd = IntPtr.Zero;
|
||||
var handles = new List<HWND>();
|
||||
var hCurrentWnd = HWND.Null;
|
||||
|
||||
do
|
||||
{
|
||||
hCurrentWnd = NativeMethods.FindWindowEx(IntPtr.Zero, hCurrentWnd, null, null);
|
||||
NativeMethods.GetWindowThreadProcessId(hCurrentWnd, out uint targetProcessId);
|
||||
hCurrentWnd = PInvoke.FindWindowEx(HWND.Null, hCurrentWnd, null as string, null);
|
||||
uint targetProcessId = 0;
|
||||
unsafe
|
||||
{
|
||||
PInvoke.GetWindowThreadProcessId(hCurrentWnd, &targetProcessId);
|
||||
}
|
||||
|
||||
if (targetProcessId == processId)
|
||||
{
|
||||
handles.Add(hCurrentWnd);
|
||||
@@ -314,23 +326,30 @@ namespace Awake.Core
|
||||
}
|
||||
|
||||
[SuppressMessage("Globalization", "CA1305:Specify IFormatProvider", Justification = "In this context, the string is only converted to a hex value.")]
|
||||
public static IntPtr GetHiddenWindow()
|
||||
internal static HWND GetHiddenWindow()
|
||||
{
|
||||
IEnumerable<IntPtr> windowHandles = EnumerateWindowsForProcess(Environment.ProcessId);
|
||||
IEnumerable<HWND> windowHandles = EnumerateWindowsForProcess(Environment.ProcessId);
|
||||
var domain = AppDomain.CurrentDomain.GetHashCode().ToString("x");
|
||||
string targetClass = $"{InternalConstants.TrayWindowId}{domain}";
|
||||
|
||||
foreach (var handle in windowHandles)
|
||||
unsafe
|
||||
{
|
||||
StringBuilder className = new (256);
|
||||
int classQueryResult = NativeMethods.GetClassName(handle, className, className.Capacity);
|
||||
if (classQueryResult != 0 && className.ToString().StartsWith(targetClass, StringComparison.InvariantCultureIgnoreCase))
|
||||
var classNameLen = 256;
|
||||
Span<char> className = stackalloc char[classNameLen];
|
||||
foreach (var handle in windowHandles)
|
||||
{
|
||||
return handle;
|
||||
fixed (char* ptr = className)
|
||||
{
|
||||
int classQueryResult = PInvoke.GetClassName(handle, ptr, classNameLen);
|
||||
if (classQueryResult != 0 && className.ToString().StartsWith(targetClass, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return IntPtr.Zero;
|
||||
return HWND.Null;
|
||||
}
|
||||
|
||||
public static Dictionary<string, int> GetDefaultTrayOptions()
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,16 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Windows.Win32;
|
||||
|
||||
namespace Awake.Core.Models
|
||||
{
|
||||
internal enum TrayCommands : uint
|
||||
{
|
||||
TC_DISPLAY_SETTING = NativeConstants.WM_USER + 1,
|
||||
TC_MODE_PASSIVE = NativeConstants.WM_USER + 2,
|
||||
TC_MODE_INDEFINITE = NativeConstants.WM_USER + 3,
|
||||
TC_EXIT = NativeConstants.WM_USER + 4,
|
||||
TC_TIME = NativeConstants.WM_USER + 5,
|
||||
TC_DISPLAY_SETTING = PInvoke.WM_USER + 1,
|
||||
TC_MODE_PASSIVE = PInvoke.WM_USER + 2,
|
||||
TC_MODE_INDEFINITE = PInvoke.WM_USER + 3,
|
||||
TC_EXIT = PInvoke.WM_USER + 4,
|
||||
TC_TIME = PInvoke.WM_USER + 5,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#pragma warning disable SA1310 // Field names should not contain underscore
|
||||
|
||||
namespace Awake.Core
|
||||
{
|
||||
internal class NativeConstants
|
||||
{
|
||||
internal const uint WM_COMMAND = 0x111;
|
||||
internal const uint WM_USER = 0x400;
|
||||
internal const uint WM_GETTEXT = 0x000D;
|
||||
internal const uint WM_CLOSE = 0x0010;
|
||||
|
||||
// Popup menu constants.
|
||||
internal const uint MF_BYPOSITION = 1024;
|
||||
internal const uint MF_STRING = 0;
|
||||
internal const uint MF_MENUBREAK = 0x00000040;
|
||||
internal const uint MF_SEPARATOR = 0x00000800;
|
||||
internal const uint MF_POPUP = 0x00000010;
|
||||
internal const uint MF_UNCHECKED = 0x00000000;
|
||||
internal const uint MF_CHECKED = 0x00000008;
|
||||
internal const uint MF_OWNERDRAW = 0x00000100;
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
// 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.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Awake.Core.Models;
|
||||
|
||||
namespace Awake.Core
|
||||
{
|
||||
internal static class NativeMethods
|
||||
{
|
||||
internal delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);
|
||||
|
||||
[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", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
internal static extern ExecutionState SetThreadExecutionState(ExecutionState esFlags);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool AllocConsole();
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
internal static extern bool SetStdHandle(int nStdHandle, IntPtr hHandle);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
internal static extern uint GetCurrentThreadId();
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
internal static extern IntPtr CreateFile(
|
||||
[MarshalAs(UnmanagedType.LPWStr)] 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);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
internal static extern IntPtr CreatePopupMenu();
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
internal static extern bool InsertMenu(IntPtr hMenu, uint uPosition, uint uFlags, uint uIDNewItem, string lpNewItem);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
internal static extern bool TrackPopupMenuEx(IntPtr hmenu, uint fuFlags, int x, int y, IntPtr hwnd, IntPtr lptpm);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
internal static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
internal static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr hWndChildAfter, string? className, string? windowTitle);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool SetForegroundWindow(IntPtr hWnd);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
internal static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, nuint wParam, string lParam);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
internal static extern bool DestroyMenu(IntPtr hMenu);
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,16 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Awake.Core.Models;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using NLog;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
|
||||
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||
#pragma warning disable CS8603 // Possible null reference return.
|
||||
@@ -22,21 +27,18 @@ namespace Awake.Core
|
||||
{
|
||||
private static readonly Logger _log;
|
||||
|
||||
private static IntPtr _trayMenu;
|
||||
private static DestroyMenuSafeHandle TrayMenu { get; set; }
|
||||
|
||||
private static IntPtr TrayMenu { get => _trayMenu; set => _trayMenu = value; }
|
||||
|
||||
private static NotifyIcon? _trayIcon;
|
||||
|
||||
private static NotifyIcon TrayIcon { get => _trayIcon; set => _trayIcon = value; }
|
||||
private static NotifyIcon TrayIcon { get; set; }
|
||||
|
||||
static TrayHelper()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
TrayMenu = new DestroyMenuSafeHandle();
|
||||
TrayIcon = new NotifyIcon();
|
||||
}
|
||||
|
||||
public static void InitializeTray(string text, Icon icon, ContextMenuStrip? contextMenu = null)
|
||||
public static void InitializeTray(string text, Icon icon, ManualResetEvent? exitSignal, ContextMenuStrip? contextMenu = null)
|
||||
{
|
||||
Task.Factory.StartNew(
|
||||
(tray) =>
|
||||
@@ -49,7 +51,7 @@ namespace Awake.Core
|
||||
((NotifyIcon?)tray).ContextMenuStrip = contextMenu;
|
||||
((NotifyIcon?)tray).Visible = true;
|
||||
((NotifyIcon?)tray).MouseClick += TrayClickHandler;
|
||||
Application.AddMessageFilter(new TrayMessageFilter());
|
||||
Application.AddMessageFilter(new TrayMessageFilter(exitSignal));
|
||||
Application.Run();
|
||||
_log.Info("Tray setup complete.");
|
||||
}
|
||||
@@ -74,21 +76,15 @@ namespace Awake.Core
|
||||
/// <param name="e">MouseEventArgs instance containing mouse click event information.</param>
|
||||
private static void TrayClickHandler(object? sender, MouseEventArgs e)
|
||||
{
|
||||
IntPtr windowHandle = APIHelper.GetHiddenWindow();
|
||||
HWND windowHandle = APIHelper.GetHiddenWindow();
|
||||
|
||||
if (windowHandle != IntPtr.Zero)
|
||||
if (windowHandle != HWND.Null)
|
||||
{
|
||||
NativeMethods.SetForegroundWindow(windowHandle);
|
||||
NativeMethods.TrackPopupMenuEx(TrayMenu, 0, Cursor.Position.X, Cursor.Position.Y, windowHandle, IntPtr.Zero);
|
||||
PInvoke.SetForegroundWindow(windowHandle);
|
||||
PInvoke.TrackPopupMenuEx(TrayMenu, 0, Cursor.Position.X, Cursor.Position.Y, windowHandle, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ClearTray()
|
||||
{
|
||||
TrayIcon.Icon = null;
|
||||
TrayIcon.Dispose();
|
||||
}
|
||||
|
||||
internal static void SetTray(string text, AwakeSettings settings)
|
||||
{
|
||||
SetTray(
|
||||
@@ -101,19 +97,14 @@ namespace Awake.Core
|
||||
[SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1005:Single line comments should begin with single space", Justification = "For debugging purposes - will remove later.")]
|
||||
public static void SetTray(string text, bool keepDisplayOn, AwakeMode mode, Dictionary<string, int> trayTimeShortcuts)
|
||||
{
|
||||
if (TrayMenu != IntPtr.Zero)
|
||||
{
|
||||
var destructionStatus = NativeMethods.DestroyMenu(TrayMenu);
|
||||
if (destructionStatus != true)
|
||||
{
|
||||
_log.Error("Failed to destroy tray menu and free up memory.");
|
||||
}
|
||||
}
|
||||
TrayMenu = new DestroyMenuSafeHandle(PInvoke.CreatePopupMenu());
|
||||
|
||||
TrayMenu = NativeMethods.CreatePopupMenu();
|
||||
NativeMethods.InsertMenu(TrayMenu, 0, NativeConstants.MF_BYPOSITION | NativeConstants.MF_STRING, (uint)TrayCommands.TC_EXIT, "Exit");
|
||||
NativeMethods.InsertMenu(TrayMenu, 0, NativeConstants.MF_BYPOSITION | NativeConstants.MF_SEPARATOR, 0, string.Empty);
|
||||
NativeMethods.InsertMenu(TrayMenu, 0, NativeConstants.MF_BYPOSITION | NativeConstants.MF_STRING | (keepDisplayOn ? NativeConstants.MF_CHECKED : NativeConstants.MF_UNCHECKED), (uint)TrayCommands.TC_DISPLAY_SETTING, "Keep screen on");
|
||||
if (!TrayMenu.IsInvalid)
|
||||
{
|
||||
PInvoke.InsertMenu(TrayMenu, 0, MENU_ITEM_FLAGS.MF_BYPOSITION | MENU_ITEM_FLAGS.MF_STRING, (uint)TrayCommands.TC_EXIT, "Exit");
|
||||
PInvoke.InsertMenu(TrayMenu, 0, MENU_ITEM_FLAGS.MF_BYPOSITION | MENU_ITEM_FLAGS.MF_SEPARATOR, 0, string.Empty);
|
||||
PInvoke.InsertMenu(TrayMenu, 0, MENU_ITEM_FLAGS.MF_BYPOSITION | MENU_ITEM_FLAGS.MF_STRING | (keepDisplayOn ? MENU_ITEM_FLAGS.MF_CHECKED : MENU_ITEM_FLAGS.MF_UNCHECKED), (uint)TrayCommands.TC_DISPLAY_SETTING, "Keep screen on");
|
||||
}
|
||||
|
||||
// In case there are no tray shortcuts defined for the application default to a
|
||||
// reasonable initial set.
|
||||
@@ -123,18 +114,18 @@ namespace Awake.Core
|
||||
}
|
||||
|
||||
// TODO: Make sure that this loads from JSON instead of being hard-coded.
|
||||
var awakeTimeMenu = NativeMethods.CreatePopupMenu();
|
||||
var awakeTimeMenu = new DestroyMenuSafeHandle(PInvoke.CreatePopupMenu(), false);
|
||||
for (int i = 0; i < trayTimeShortcuts.Count; i++)
|
||||
{
|
||||
NativeMethods.InsertMenu(awakeTimeMenu, (uint)i, NativeConstants.MF_BYPOSITION | NativeConstants.MF_STRING, (uint)TrayCommands.TC_TIME + (uint)i, trayTimeShortcuts.ElementAt(i).Key);
|
||||
PInvoke.InsertMenu(awakeTimeMenu, (uint)i, MENU_ITEM_FLAGS.MF_BYPOSITION | MENU_ITEM_FLAGS.MF_STRING, (uint)TrayCommands.TC_TIME + (uint)i, trayTimeShortcuts.ElementAt(i).Key);
|
||||
}
|
||||
|
||||
var modeMenu = NativeMethods.CreatePopupMenu();
|
||||
NativeMethods.InsertMenu(modeMenu, 0, NativeConstants.MF_BYPOSITION | NativeConstants.MF_STRING | (mode == AwakeMode.PASSIVE ? NativeConstants.MF_CHECKED : NativeConstants.MF_UNCHECKED), (uint)TrayCommands.TC_MODE_PASSIVE, "Off (keep using the selected power plan)");
|
||||
NativeMethods.InsertMenu(modeMenu, 1, NativeConstants.MF_BYPOSITION | NativeConstants.MF_STRING | (mode == AwakeMode.INDEFINITE ? NativeConstants.MF_CHECKED : NativeConstants.MF_UNCHECKED), (uint)TrayCommands.TC_MODE_INDEFINITE, "Keep awake indefinitely");
|
||||
var modeMenu = new DestroyMenuSafeHandle(PInvoke.CreatePopupMenu(), false);
|
||||
PInvoke.InsertMenu(modeMenu, 0, MENU_ITEM_FLAGS.MF_BYPOSITION | MENU_ITEM_FLAGS.MF_STRING | (mode == AwakeMode.PASSIVE ? MENU_ITEM_FLAGS.MF_CHECKED : MENU_ITEM_FLAGS.MF_UNCHECKED), (uint)TrayCommands.TC_MODE_PASSIVE, "Off (keep using the selected power plan)");
|
||||
PInvoke.InsertMenu(modeMenu, 1, MENU_ITEM_FLAGS.MF_BYPOSITION | MENU_ITEM_FLAGS.MF_STRING | (mode == AwakeMode.INDEFINITE ? MENU_ITEM_FLAGS.MF_CHECKED : MENU_ITEM_FLAGS.MF_UNCHECKED), (uint)TrayCommands.TC_MODE_INDEFINITE, "Keep awake indefinitely");
|
||||
|
||||
NativeMethods.InsertMenu(modeMenu, 2, NativeConstants.MF_BYPOSITION | NativeConstants.MF_POPUP | (mode == AwakeMode.TIMED ? NativeConstants.MF_CHECKED : NativeConstants.MF_UNCHECKED), (uint)awakeTimeMenu, "Keep awake temporarily");
|
||||
NativeMethods.InsertMenu(TrayMenu, 0, NativeConstants.MF_BYPOSITION | NativeConstants.MF_POPUP, (uint)modeMenu, "Mode");
|
||||
PInvoke.InsertMenu(modeMenu, 2, MENU_ITEM_FLAGS.MF_BYPOSITION | MENU_ITEM_FLAGS.MF_POPUP | (mode == AwakeMode.TIMED ? MENU_ITEM_FLAGS.MF_CHECKED : MENU_ITEM_FLAGS.MF_UNCHECKED), (uint)awakeTimeMenu.DangerousGetHandle(), "Keep awake temporarily");
|
||||
PInvoke.InsertMenu(TrayMenu, 0, MENU_ITEM_FLAGS.MF_BYPOSITION | MENU_ITEM_FLAGS.MF_POPUP, (uint)modeMenu.DangerousGetHandle(), "Mode");
|
||||
|
||||
TrayIcon.Text = text;
|
||||
}
|
||||
|
||||
@@ -6,9 +6,11 @@ using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using Awake.Core.Models;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Windows.Win32;
|
||||
|
||||
#pragma warning disable CS8603 // Possible null reference return.
|
||||
|
||||
@@ -20,8 +22,11 @@ namespace Awake.Core
|
||||
|
||||
private static SettingsUtils ModuleSettings { get => _moduleSettings; set => _moduleSettings = value; }
|
||||
|
||||
public TrayMessageFilter()
|
||||
private static ManualResetEvent? _exitSignal;
|
||||
|
||||
public TrayMessageFilter(ManualResetEvent? exitSignal)
|
||||
{
|
||||
_exitSignal = exitSignal;
|
||||
ModuleSettings = new SettingsUtils();
|
||||
}
|
||||
|
||||
@@ -31,12 +36,12 @@ namespace Awake.Core
|
||||
|
||||
switch (m.Msg)
|
||||
{
|
||||
case (int)NativeConstants.WM_COMMAND:
|
||||
case (int)PInvoke.WM_COMMAND:
|
||||
var targetCommandIndex = m.WParam.ToInt64() & 0xFFFF;
|
||||
switch (targetCommandIndex)
|
||||
{
|
||||
case (long)TrayCommands.TC_EXIT:
|
||||
ExitCommandHandler();
|
||||
ExitCommandHandler(_exitSignal);
|
||||
break;
|
||||
case (long)TrayCommands.TC_DISPLAY_SETTING:
|
||||
DisplaySettingCommandHandler(InternalConstants.AppName);
|
||||
@@ -68,9 +73,9 @@ namespace Awake.Core
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void ExitCommandHandler()
|
||||
private static void ExitCommandHandler(ManualResetEvent? exitSignal)
|
||||
{
|
||||
APIHelper.CompleteExit(0, true);
|
||||
APIHelper.CompleteExit(0, exitSignal, true);
|
||||
}
|
||||
|
||||
private static void DisplaySettingCommandHandler(string moduleName)
|
||||
|
||||
23
src/modules/awake/Awake/NativeMethods.txt
Normal file
23
src/modules/awake/Awake/NativeMethods.txt
Normal file
@@ -0,0 +1,23 @@
|
||||
AllocConsole
|
||||
CreateFile
|
||||
CreatePopupMenu
|
||||
DestroyMenu
|
||||
DestroyWindow
|
||||
FindWindowEx
|
||||
GetClassName
|
||||
GetCurrentThreadId
|
||||
GetPwrCapabilities
|
||||
GetWindowThreadProcessId
|
||||
HMENU
|
||||
InsertMenu
|
||||
PostQuitMessage
|
||||
SendMessage
|
||||
SetConsoleCtrlHandler
|
||||
SetForegroundWindow
|
||||
SetStdHandle
|
||||
SetThreadExecutionState
|
||||
TrackPopupMenuEx
|
||||
WM_CLOSE
|
||||
WM_COMMAND
|
||||
WM_GETTEXT
|
||||
WM_USER
|
||||
@@ -3,7 +3,6 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.CommandLine;
|
||||
using System.CommandLine.Invocation;
|
||||
using System.Diagnostics;
|
||||
@@ -17,11 +16,15 @@ using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Awake.Core;
|
||||
using Awake.Core.Models;
|
||||
using interop;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library;
|
||||
using Microsoft.PowerToys.Telemetry.Events;
|
||||
using NLog;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.System.Console;
|
||||
using Windows.Win32.System.Power;
|
||||
|
||||
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||
#pragma warning disable CS8603 // Possible null reference return.
|
||||
@@ -47,8 +50,8 @@ 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;
|
||||
private static SystemPowerCapabilities _powerCapabilities;
|
||||
private static PHANDLER_ROUTINE _handler;
|
||||
private static SYSTEM_POWER_CAPABILITIES _powerCapabilities;
|
||||
#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);
|
||||
@@ -63,7 +66,7 @@ namespace Awake
|
||||
|
||||
if (!instantiated)
|
||||
{
|
||||
Exit(InternalConstants.AppName + " is already running! Exiting the application.", 1, true);
|
||||
Exit(InternalConstants.AppName + " is already running! Exiting the application.", 1, _exitSignal, true);
|
||||
}
|
||||
|
||||
_settingsUtils = new SettingsUtils();
|
||||
@@ -82,12 +85,12 @@ namespace Awake
|
||||
|
||||
// To make it easier to diagnose future issues, let's get the
|
||||
// system power capabilities and aggregate them in the log.
|
||||
NativeMethods.GetPwrCapabilities(out _powerCapabilities);
|
||||
PInvoke.GetPwrCapabilities(out _powerCapabilities);
|
||||
_log.Info(JsonSerializer.Serialize(_powerCapabilities));
|
||||
|
||||
_log.Info("Parsing parameters...");
|
||||
|
||||
Option<bool>? configOption = new (
|
||||
var configOption = new Option<bool>(
|
||||
aliases: new[] { "--use-pt-config", "-c" },
|
||||
getDefaultValue: () => false,
|
||||
description: $"Specifies whether {InternalConstants.AppName} will be using the PowerToys configuration file for managing the state.")
|
||||
@@ -100,7 +103,7 @@ namespace Awake
|
||||
|
||||
configOption.Required = false;
|
||||
|
||||
Option<bool>? displayOption = new (
|
||||
var displayOption = new Option<bool>(
|
||||
aliases: new[] { "--display-on", "-d" },
|
||||
getDefaultValue: () => true,
|
||||
description: "Determines whether the display should be kept awake.")
|
||||
@@ -113,7 +116,7 @@ namespace Awake
|
||||
|
||||
displayOption.Required = false;
|
||||
|
||||
Option<uint>? timeOption = new (
|
||||
var timeOption = new Option<uint>(
|
||||
aliases: new[] { "--time-limit", "-t" },
|
||||
getDefaultValue: () => 0,
|
||||
description: "Determines the interval, in seconds, during which the computer is kept awake.")
|
||||
@@ -126,7 +129,7 @@ namespace Awake
|
||||
|
||||
timeOption.Required = false;
|
||||
|
||||
Option<int>? pidOption = new (
|
||||
var pidOption = new Option<int>(
|
||||
aliases: new[] { "--pid", "-p" },
|
||||
getDefaultValue: () => 0,
|
||||
description: $"Bind the execution of {InternalConstants.AppName} to another process.")
|
||||
@@ -156,23 +159,23 @@ namespace Awake
|
||||
return rootCommand.InvokeAsync(args).Result;
|
||||
}
|
||||
|
||||
private static bool ExitHandler(ControlType ctrlType)
|
||||
private static BOOL ExitHandler(uint ctrlType)
|
||||
{
|
||||
_log.Info($"Exited through handler with control type: {ctrlType}");
|
||||
Exit("Exiting from the internal termination handler.", Environment.ExitCode);
|
||||
Exit("Exiting from the internal termination handler.", Environment.ExitCode, _exitSignal);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void Exit(string message, int exitCode, bool force = false)
|
||||
private static void Exit(string message, int exitCode, ManualResetEvent exitSignal, bool force = false)
|
||||
{
|
||||
_log.Info(message);
|
||||
|
||||
APIHelper.CompleteExit(exitCode, force);
|
||||
APIHelper.CompleteExit(exitCode, exitSignal, force);
|
||||
}
|
||||
|
||||
private static void HandleCommandLineArguments(bool usePtConfig, bool displayOn, uint timeLimit, int pid)
|
||||
{
|
||||
_handler += new ConsoleEventHandler(ExitHandler);
|
||||
_handler += ExitHandler;
|
||||
APIHelper.SetConsoleControlHandler(_handler, true);
|
||||
|
||||
if (pid == 0)
|
||||
@@ -192,16 +195,15 @@ namespace Awake
|
||||
// and instead watch for changes in the file.
|
||||
try
|
||||
{
|
||||
var eventHandle = new EventWaitHandle(false, EventResetMode.ManualReset, Constants.AwakeExitEvent());
|
||||
new Thread(() =>
|
||||
{
|
||||
EventWaitHandle? eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.AwakeExitEvent());
|
||||
if (eventHandle.WaitOne())
|
||||
if (WaitHandle.WaitAny(new WaitHandle[] { _exitSignal, eventHandle }) == 1)
|
||||
{
|
||||
Exit("Received a signal to end the process. Making sure we quit...", 0, true);
|
||||
Exit("Received a signal to end the process. Making sure we quit...", 0, _exitSignal, true);
|
||||
}
|
||||
}).Start();
|
||||
|
||||
TrayHelper.InitializeTray(InternalConstants.FullAppName, new Icon("modules/awake/images/awake.ico"));
|
||||
TrayHelper.InitializeTray(InternalConstants.FullAppName, new Icon("modules/awake/images/awake.ico"), _exitSignal);
|
||||
|
||||
string? settingsPath = _settingsUtils.GetSettingsFilePath(InternalConstants.AppName);
|
||||
_log.Info($"Reading configuration file: {settingsPath}");
|
||||
@@ -263,7 +265,7 @@ namespace Awake
|
||||
RunnerHelper.WaitForPowerToysRunner(pid, () =>
|
||||
{
|
||||
_log.Info($"Triggered PID-based exit handler for PID {pid}.");
|
||||
Exit("Terminating from process binding hook.", 0, true);
|
||||
Exit("Terminating from process binding hook.", 0, _exitSignal, true);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using ColorPicker.Helpers;
|
||||
@@ -23,8 +24,16 @@ namespace ColorPickerUI
|
||||
private bool disposedValue;
|
||||
private ThemeManager _themeManager;
|
||||
|
||||
private CancellationTokenSource NativeThreadCTS { get; set; }
|
||||
|
||||
[Export]
|
||||
private static CancellationToken ExitToken { get; set; }
|
||||
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
NativeThreadCTS = new CancellationTokenSource();
|
||||
ExitToken = NativeThreadCTS.Token;
|
||||
|
||||
_args = e?.Args;
|
||||
|
||||
// allow only one instance of color picker
|
||||
@@ -33,7 +42,7 @@ namespace ColorPickerUI
|
||||
{
|
||||
Logger.LogWarning("There is ColorPicker instance running. Exiting Color Picker");
|
||||
_instanceMutex = null;
|
||||
Environment.Exit(0);
|
||||
Shutdown(0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -45,7 +54,8 @@ namespace ColorPickerUI
|
||||
RunnerHelper.WaitForPowerToysRunner(_powerToysRunnerPid, () =>
|
||||
{
|
||||
Logger.LogInfo("PowerToys Runner exited. Exiting ColorPicker");
|
||||
Environment.Exit(0);
|
||||
NativeThreadCTS.Cancel();
|
||||
Dispatcher.Invoke(Shutdown);
|
||||
});
|
||||
}
|
||||
else
|
||||
|
||||
@@ -7,7 +7,6 @@ using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Automation.Peers;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
using ColorPicker.Helpers;
|
||||
|
||||
@@ -3,11 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace ColorPicker.Controls
|
||||
{
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
// 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.Threading;
|
||||
using System.Windows;
|
||||
|
||||
namespace ColorPicker.Helpers
|
||||
{
|
||||
public static class NativeEventWaiter
|
||||
{
|
||||
public static void WaitForEventLoop(string eventName, Action callback)
|
||||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName);
|
||||
while (true)
|
||||
{
|
||||
if (eventHandle.WaitOne())
|
||||
{
|
||||
Logger.LogInfo($"Successfully waited for {eventName}");
|
||||
Application.Current.Dispatcher.Invoke(callback);
|
||||
}
|
||||
}
|
||||
}).Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,8 @@ using System.ComponentModel.Composition;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Imaging;
|
||||
using ColorPicker.Telemetry;
|
||||
using ColorPicker.ViewModelContracts;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
|
||||
namespace ColorPicker.Helpers
|
||||
{
|
||||
|
||||
@@ -8,10 +8,7 @@ using System.ComponentModel.Composition;
|
||||
using System.Windows.Input;
|
||||
using ColorPicker.Helpers;
|
||||
using ColorPicker.Settings;
|
||||
using ColorPicker.Telemetry;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Enumerations;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using static ColorPicker.NativeMethods;
|
||||
|
||||
namespace ColorPicker.Keyboard
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
using System;
|
||||
using ColorPicker.Helpers;
|
||||
using ColorPicker.Mouse;
|
||||
|
||||
using ColorPickerUI;
|
||||
|
||||
namespace ColorPicker
|
||||
|
||||
@@ -2,7 +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 System;
|
||||
using System.Diagnostics.Tracing;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using Microsoft.PowerToys.Telemetry.Events;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
@@ -13,11 +12,9 @@ using ColorPicker.Helpers;
|
||||
using ColorPicker.Keyboard;
|
||||
using ColorPicker.Mouse;
|
||||
using ColorPicker.Settings;
|
||||
using ColorPicker.Telemetry;
|
||||
using ColorPicker.ViewModelContracts;
|
||||
using Common.UI;
|
||||
using interop;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Enumerations;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
|
||||
namespace ColorPicker.ViewModels
|
||||
{
|
||||
@@ -49,13 +46,24 @@ namespace ColorPicker.ViewModels
|
||||
ZoomWindowHelper zoomWindowHelper,
|
||||
AppStateHandler appStateHandler,
|
||||
KeyboardMonitor keyboardMonitor,
|
||||
IUserSettings userSettings)
|
||||
IUserSettings userSettings,
|
||||
CancellationToken exitToken)
|
||||
{
|
||||
_zoomWindowHelper = zoomWindowHelper;
|
||||
_appStateHandler = appStateHandler;
|
||||
_userSettings = userSettings;
|
||||
NativeEventWaiter.WaitForEventLoop(Constants.ShowColorPickerSharedEvent(), _appStateHandler.StartUserSession);
|
||||
NativeEventWaiter.WaitForEventLoop(Constants.ColorPickerSendSettingsTelemetryEvent(), _userSettings.SendSettingsTelemetry);
|
||||
|
||||
NativeEventWaiter.WaitForEventLoop(
|
||||
Constants.ShowColorPickerSharedEvent(),
|
||||
_appStateHandler.StartUserSession,
|
||||
Application.Current.Dispatcher,
|
||||
exitToken);
|
||||
|
||||
NativeEventWaiter.WaitForEventLoop(
|
||||
Constants.ColorPickerSendSettingsTelemetryEvent(),
|
||||
_userSettings.SendSettingsTelemetry,
|
||||
Application.Current.Dispatcher,
|
||||
exitToken);
|
||||
|
||||
if (mouseInfoProvider != null)
|
||||
{
|
||||
|
||||
@@ -2,7 +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 System.ComponentModel;
|
||||
using System.Windows;
|
||||
|
||||
namespace ColorPicker
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
using Common.UI;
|
||||
using FancyZonesEditor.Logs;
|
||||
using FancyZonesEditor.Utils;
|
||||
@@ -35,10 +35,6 @@ namespace FancyZonesEditor
|
||||
|
||||
private ThemeManager _themeManager;
|
||||
|
||||
private EventWaitHandle _eventHandle;
|
||||
|
||||
private Thread _exitWaitThread;
|
||||
|
||||
public static bool DebugMode
|
||||
{
|
||||
get
|
||||
@@ -50,6 +46,8 @@ namespace FancyZonesEditor
|
||||
private static bool _debugMode;
|
||||
private bool _isDisposed;
|
||||
|
||||
private CancellationTokenSource NativeThreadCTS { get; set; }
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private void DebugModeCheck()
|
||||
{
|
||||
@@ -59,27 +57,29 @@ namespace FancyZonesEditor
|
||||
public App()
|
||||
{
|
||||
// DebugModeCheck();
|
||||
NativeThreadCTS = new CancellationTokenSource();
|
||||
FancyZonesEditorIO = new FancyZonesEditorIO();
|
||||
Overlay = new Overlay();
|
||||
MainWindowSettings = new MainWindowSettingsModel();
|
||||
|
||||
_exitWaitThread = new Thread(App_WaitExit);
|
||||
_exitWaitThread.Start();
|
||||
App_WaitExit();
|
||||
}
|
||||
|
||||
private void OnStartup(object sender, StartupEventArgs e)
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
|
||||
|
||||
RunnerHelper.WaitForPowerToysRunner(PowerToysPID, () =>
|
||||
{
|
||||
Logger.LogInfo("Runner exited");
|
||||
Environment.Exit(0);
|
||||
});
|
||||
|
||||
_themeManager = new ThemeManager(this);
|
||||
|
||||
var parseResult = FancyZonesEditorIO.ParseParams();
|
||||
|
||||
RunnerHelper.WaitForPowerToysRunner(PowerToysPID, () =>
|
||||
{
|
||||
Logger.LogInfo("Runner exited");
|
||||
NativeThreadCTS.Cancel();
|
||||
Application.Current.Dispatcher.Invoke(Application.Current.Shutdown);
|
||||
});
|
||||
|
||||
if (!parseResult.Result)
|
||||
{
|
||||
Logger.LogError(ParsingErrorReportTag + ": " + parseResult.Message + "; " + ParsingErrorDataTag + ": " + parseResult.MalformedData);
|
||||
@@ -122,26 +122,23 @@ namespace FancyZonesEditor
|
||||
|
||||
private void OnExit(object sender, ExitEventArgs e)
|
||||
{
|
||||
NativeThreadCTS.Cancel();
|
||||
Dispose();
|
||||
|
||||
if (_eventHandle != null)
|
||||
{
|
||||
_eventHandle.Set();
|
||||
}
|
||||
|
||||
_exitWaitThread.Join();
|
||||
|
||||
Logger.LogInfo("FancyZones Editor exited");
|
||||
}
|
||||
|
||||
private void App_WaitExit()
|
||||
{
|
||||
_eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, interop.Constants.FZEExitEvent());
|
||||
if (_eventHandle.WaitOne())
|
||||
NativeEventWaiter.WaitForEventLoop(
|
||||
interop.Constants.FZEExitEvent(),
|
||||
() =>
|
||||
{
|
||||
Logger.LogInfo("Exit event triggered");
|
||||
Environment.Exit(0);
|
||||
}
|
||||
Application.Current.Shutdown();
|
||||
},
|
||||
Current.Dispatcher,
|
||||
NativeThreadCTS.Token);
|
||||
}
|
||||
|
||||
public void App_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
|
||||
|
||||
@@ -72,13 +72,16 @@ namespace PowerLauncher
|
||||
using (var application = new App())
|
||||
{
|
||||
application.InitializeComponent();
|
||||
|
||||
NativeEventWaiter.WaitForEventLoop(
|
||||
Constants.RunExitEvent(),
|
||||
() =>
|
||||
{
|
||||
Log.Warn("RunExitEvent was signaled. Exiting PowerToys", typeof(App));
|
||||
ExitPowerToys(application);
|
||||
}, NativeThreadCTS.Token);
|
||||
{
|
||||
Log.Warn("RunExitEvent was signaled. Exiting PowerToys", typeof(App));
|
||||
ExitPowerToys(application);
|
||||
},
|
||||
Application.Current.Dispatcher,
|
||||
NativeThreadCTS.Token);
|
||||
|
||||
if (powerToysPid != 0)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,7 @@ using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
using Common.UI;
|
||||
using interop;
|
||||
using Microsoft.PowerLauncher.Telemetry;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
@@ -52,7 +53,11 @@ namespace PowerLauncher
|
||||
|
||||
_firstDeleteTimer.Elapsed += CheckForFirstDelete;
|
||||
_firstDeleteTimer.Interval = 1000;
|
||||
NativeEventWaiter.WaitForEventLoop(Constants.RunSendSettingsTelemetryEvent(), SendSettingsTelemetry, _nativeWaiterCancelToken);
|
||||
NativeEventWaiter.WaitForEventLoop(
|
||||
Constants.RunSendSettingsTelemetryEvent(),
|
||||
SendSettingsTelemetry,
|
||||
Application.Current.Dispatcher,
|
||||
_nativeWaiterCancelToken);
|
||||
}
|
||||
|
||||
private void SendSettingsTelemetry()
|
||||
@@ -701,7 +706,15 @@ namespace PowerLauncher
|
||||
|
||||
private void OnClosed(object sender, EventArgs e)
|
||||
{
|
||||
_hwndSource.RemoveHook(ProcessWindowMessages);
|
||||
try
|
||||
{
|
||||
_hwndSource.RemoveHook(ProcessWindowMessages);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Exception($"Exception when trying to Remove hook", ex, ex.GetType());
|
||||
}
|
||||
|
||||
_hwndSource = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,19 +49,6 @@ namespace Wox
|
||||
_mainVM.ChangeQueryText(query, requery);
|
||||
}
|
||||
|
||||
public void RestartApp()
|
||||
{
|
||||
_mainVM.MainWindowVisibility = Visibility.Hidden;
|
||||
|
||||
// we must manually save
|
||||
// UpdateManager.RestartApp() will call Environment.Exit(0)
|
||||
// which will cause ungraceful exit
|
||||
SaveAppAllSettings();
|
||||
|
||||
// Todo : Implement logic to restart this app.
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
public void CheckForNewUpdate()
|
||||
{
|
||||
// _settingsVM.UpdateApp();
|
||||
|
||||
@@ -12,6 +12,7 @@ using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
using Common.UI;
|
||||
using interop;
|
||||
using Microsoft.PowerLauncher.Telemetry;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
@@ -93,12 +94,12 @@ namespace PowerLauncher.ViewModel
|
||||
Log.Info("RegisterHotkey()", GetType());
|
||||
|
||||
// Allow OOBE to call PowerToys Run.
|
||||
NativeEventWaiter.WaitForEventLoop(Constants.PowerLauncherSharedEvent(), OnHotkey, _nativeWaiterCancelToken);
|
||||
NativeEventWaiter.WaitForEventLoop(Constants.PowerLauncherSharedEvent(), OnHotkey, Application.Current.Dispatcher, _nativeWaiterCancelToken);
|
||||
|
||||
if (_settings.StartedFromPowerToysRunner)
|
||||
{
|
||||
// Allow runner to call PowerToys Run from the centralized keyboard hook.
|
||||
NativeEventWaiter.WaitForEventLoop(Constants.PowerLauncherCentralizedHookSharedEvent(), OnCentralizedKeyboardHookHotKey, _nativeWaiterCancelToken);
|
||||
NativeEventWaiter.WaitForEventLoop(Constants.PowerLauncherCentralizedHookSharedEvent(), OnCentralizedKeyboardHookHotKey, Application.Current.Dispatcher, _nativeWaiterCancelToken);
|
||||
}
|
||||
|
||||
_settings.PropertyChanged += (s, e) =>
|
||||
|
||||
@@ -23,11 +23,6 @@ namespace Wox.Plugin
|
||||
/// </param>
|
||||
void ChangeQuery(string query, bool requery = false);
|
||||
|
||||
/// <summary>
|
||||
/// Restart Wox
|
||||
/// </summary>
|
||||
void RestartApp();
|
||||
|
||||
/// <summary>
|
||||
/// Remove user selected history item and refresh/requery
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user