mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-08 12:18:50 +02:00
[PTRun] Gracefully shutdown all threads when exiting (#20450)
This commit is contained in:
@@ -31,7 +31,10 @@ namespace PowerLauncher
|
|||||||
{
|
{
|
||||||
public static PublicAPIInstance API { get; private set; }
|
public static PublicAPIInstance API { get; private set; }
|
||||||
|
|
||||||
|
public static CancellationTokenSource NativeThreadCTS { get; private set; }
|
||||||
|
|
||||||
private static bool _disposed;
|
private static bool _disposed;
|
||||||
|
|
||||||
private PowerToysRunSettings _settings;
|
private PowerToysRunSettings _settings;
|
||||||
private MainViewModel _mainVM;
|
private MainViewModel _mainVM;
|
||||||
private MainWindow _mainWindow;
|
private MainWindow _mainWindow;
|
||||||
@@ -46,6 +49,8 @@ namespace PowerLauncher
|
|||||||
[STAThread]
|
[STAThread]
|
||||||
public static void Main()
|
public static void Main()
|
||||||
{
|
{
|
||||||
|
NativeThreadCTS = new CancellationTokenSource();
|
||||||
|
|
||||||
Log.Info($"Starting PowerToys Run with PID={Environment.ProcessId}", typeof(App));
|
Log.Info($"Starting PowerToys Run with PID={Environment.ProcessId}", typeof(App));
|
||||||
int powerToysPid = GetPowerToysPId();
|
int powerToysPid = GetPowerToysPId();
|
||||||
if (powerToysPid != 0)
|
if (powerToysPid != 0)
|
||||||
@@ -67,15 +72,13 @@ namespace PowerLauncher
|
|||||||
using (var application = new App())
|
using (var application = new App())
|
||||||
{
|
{
|
||||||
application.InitializeComponent();
|
application.InitializeComponent();
|
||||||
new Thread(() =>
|
NativeEventWaiter.WaitForEventLoop(
|
||||||
|
Constants.RunExitEvent(),
|
||||||
|
() =>
|
||||||
{
|
{
|
||||||
var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, Constants.RunExitEvent());
|
Log.Warn("RunExitEvent was signaled. Exiting PowerToys", typeof(App));
|
||||||
if (eventHandle.WaitOne())
|
ExitPowerToys(application);
|
||||||
{
|
}, NativeThreadCTS.Token);
|
||||||
Log.Warn("RunExitEvent was signaled. Exiting PowerToys", typeof(App));
|
|
||||||
ExitPowerToys(application);
|
|
||||||
}
|
|
||||||
}).Start();
|
|
||||||
|
|
||||||
if (powerToysPid != 0)
|
if (powerToysPid != 0)
|
||||||
{
|
{
|
||||||
@@ -118,8 +121,8 @@ namespace PowerLauncher
|
|||||||
StringMatcher.Instance = _stringMatcher;
|
StringMatcher.Instance = _stringMatcher;
|
||||||
_stringMatcher.UserSettingSearchPrecision = _settings.QuerySearchPrecision;
|
_stringMatcher.UserSettingSearchPrecision = _settings.QuerySearchPrecision;
|
||||||
|
|
||||||
_mainVM = new MainViewModel(_settings);
|
_mainVM = new MainViewModel(_settings, NativeThreadCTS.Token);
|
||||||
_mainWindow = new MainWindow(_settings, _mainVM);
|
_mainWindow = new MainWindow(_settings, _mainVM, NativeThreadCTS.Token);
|
||||||
API = new PublicAPIInstance(_settingsVM, _mainVM, _themeManager);
|
API = new PublicAPIInstance(_settingsVM, _mainVM, _themeManager);
|
||||||
_settingsReader = new SettingsReader(_settings, _themeManager);
|
_settingsReader = new SettingsReader(_settings, _themeManager);
|
||||||
_settingsReader.ReadSettings();
|
_settingsReader.ReadSettings();
|
||||||
@@ -154,14 +157,7 @@ namespace PowerLauncher
|
|||||||
{
|
{
|
||||||
SingleInstance<App>.SingleInstanceMutex.Close();
|
SingleInstance<App>.SingleInstanceMutex.Close();
|
||||||
|
|
||||||
try
|
app.Dispatcher.Invoke(() => app.Shutdown());
|
||||||
{
|
|
||||||
app.Dispose();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
Environment.Exit(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetPowerToysPId()
|
private static int GetPowerToysPId()
|
||||||
@@ -194,6 +190,7 @@ namespace PowerLauncher
|
|||||||
|
|
||||||
Current.Exit += (s, e) =>
|
Current.Exit += (s, e) =>
|
||||||
{
|
{
|
||||||
|
NativeThreadCTS.Cancel();
|
||||||
Log.Info("Application.Current.Exit", GetType());
|
Log.Info("Application.Current.Exit", GetType());
|
||||||
Dispose();
|
Dispose();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,18 +12,22 @@ namespace PowerLauncher.Helper
|
|||||||
{
|
{
|
||||||
public static class NativeEventWaiter
|
public static class NativeEventWaiter
|
||||||
{
|
{
|
||||||
public static void WaitForEventLoop(string eventName, Action callback)
|
public static void WaitForEventLoop(string eventName, Action callback, CancellationToken cancel)
|
||||||
{
|
{
|
||||||
new Thread(() =>
|
new Thread(() =>
|
||||||
{
|
{
|
||||||
var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName);
|
var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (eventHandle.WaitOne())
|
if (WaitHandle.WaitAny(new WaitHandle[] { cancel.WaitHandle, eventHandle }) == 1)
|
||||||
{
|
{
|
||||||
Log.Info($"Successfully waited for {eventName}", MethodBase.GetCurrentMethod().DeclaringType);
|
Log.Info($"Successfully waited for {eventName}", MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
Application.Current.Dispatcher.Invoke(callback);
|
Application.Current.Dispatcher.Invoke(callback);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}).Start();
|
}).Start();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ using PowerLauncher.Plugin;
|
|||||||
using PowerLauncher.Telemetry.Events;
|
using PowerLauncher.Telemetry.Events;
|
||||||
using PowerLauncher.ViewModel;
|
using PowerLauncher.ViewModel;
|
||||||
using Wox.Infrastructure.UserSettings;
|
using Wox.Infrastructure.UserSettings;
|
||||||
|
using CancellationToken = System.Threading.CancellationToken;
|
||||||
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
|
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
|
||||||
using Log = Wox.Plugin.Logger.Log;
|
using Log = Wox.Plugin.Logger.Log;
|
||||||
using Screen = System.Windows.Forms.Screen;
|
using Screen = System.Windows.Forms.Screen;
|
||||||
@@ -30,6 +31,7 @@ namespace PowerLauncher
|
|||||||
{
|
{
|
||||||
private readonly PowerToysRunSettings _settings;
|
private readonly PowerToysRunSettings _settings;
|
||||||
private readonly MainViewModel _viewModel;
|
private readonly MainViewModel _viewModel;
|
||||||
|
private readonly CancellationToken _nativeWaiterCancelToken;
|
||||||
private bool _isTextSetProgrammatically;
|
private bool _isTextSetProgrammatically;
|
||||||
private bool _deletePressed;
|
private bool _deletePressed;
|
||||||
private HwndSource _hwndSource;
|
private HwndSource _hwndSource;
|
||||||
@@ -38,18 +40,19 @@ namespace PowerLauncher
|
|||||||
private bool _disposedValue;
|
private bool _disposedValue;
|
||||||
private IDisposable _reactiveSubscription;
|
private IDisposable _reactiveSubscription;
|
||||||
|
|
||||||
public MainWindow(PowerToysRunSettings settings, MainViewModel mainVM)
|
public MainWindow(PowerToysRunSettings settings, MainViewModel mainVM, CancellationToken nativeWaiterCancelToken)
|
||||||
: this()
|
: this()
|
||||||
{
|
{
|
||||||
DataContext = mainVM;
|
DataContext = mainVM;
|
||||||
_viewModel = mainVM;
|
_viewModel = mainVM;
|
||||||
|
_nativeWaiterCancelToken = nativeWaiterCancelToken;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
_firstDeleteTimer.Elapsed += CheckForFirstDelete;
|
_firstDeleteTimer.Elapsed += CheckForFirstDelete;
|
||||||
_firstDeleteTimer.Interval = 1000;
|
_firstDeleteTimer.Interval = 1000;
|
||||||
NativeEventWaiter.WaitForEventLoop(Constants.RunSendSettingsTelemetryEvent(), SendSettingsTelemetry);
|
NativeEventWaiter.WaitForEventLoop(Constants.RunSendSettingsTelemetryEvent(), SendSettingsTelemetry, _nativeWaiterCancelToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SendSettingsTelemetry()
|
private void SendSettingsTelemetry()
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ namespace PowerLauncher.ViewModel
|
|||||||
private CancellationTokenSource _updateSource;
|
private CancellationTokenSource _updateSource;
|
||||||
|
|
||||||
private CancellationToken _updateToken;
|
private CancellationToken _updateToken;
|
||||||
|
private CancellationToken _nativeWaiterCancelToken;
|
||||||
private bool _saved;
|
private bool _saved;
|
||||||
private ushort _hotkeyHandle;
|
private ushort _hotkeyHandle;
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ namespace PowerLauncher.ViewModel
|
|||||||
|
|
||||||
internal HotkeyManager HotkeyManager { get; private set; }
|
internal HotkeyManager HotkeyManager { get; private set; }
|
||||||
|
|
||||||
public MainViewModel(PowerToysRunSettings settings)
|
public MainViewModel(PowerToysRunSettings settings, CancellationToken nativeThreadCancelToken)
|
||||||
{
|
{
|
||||||
_saved = false;
|
_saved = false;
|
||||||
_queryTextBeforeLeaveResults = string.Empty;
|
_queryTextBeforeLeaveResults = string.Empty;
|
||||||
@@ -67,7 +68,7 @@ namespace PowerLauncher.ViewModel
|
|||||||
_disposed = false;
|
_disposed = false;
|
||||||
|
|
||||||
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
|
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
|
||||||
|
_nativeWaiterCancelToken = nativeThreadCancelToken;
|
||||||
_historyItemsStorage = new WoxJsonStorage<QueryHistory>();
|
_historyItemsStorage = new WoxJsonStorage<QueryHistory>();
|
||||||
_userSelectedRecordStorage = new WoxJsonStorage<UserSelectedRecord>();
|
_userSelectedRecordStorage = new WoxJsonStorage<UserSelectedRecord>();
|
||||||
_history = _historyItemsStorage.Load();
|
_history = _historyItemsStorage.Load();
|
||||||
@@ -92,12 +93,12 @@ namespace PowerLauncher.ViewModel
|
|||||||
Log.Info("RegisterHotkey()", GetType());
|
Log.Info("RegisterHotkey()", GetType());
|
||||||
|
|
||||||
// Allow OOBE to call PowerToys Run.
|
// Allow OOBE to call PowerToys Run.
|
||||||
NativeEventWaiter.WaitForEventLoop(Constants.PowerLauncherSharedEvent(), OnHotkey);
|
NativeEventWaiter.WaitForEventLoop(Constants.PowerLauncherSharedEvent(), OnHotkey, _nativeWaiterCancelToken);
|
||||||
|
|
||||||
if (_settings.StartedFromPowerToysRunner)
|
if (_settings.StartedFromPowerToysRunner)
|
||||||
{
|
{
|
||||||
// Allow runner to call PowerToys Run from the centralized keyboard hook.
|
// Allow runner to call PowerToys Run from the centralized keyboard hook.
|
||||||
NativeEventWaiter.WaitForEventLoop(Constants.PowerLauncherCentralizedHookSharedEvent(), OnCentralizedKeyboardHookHotKey);
|
NativeEventWaiter.WaitForEventLoop(Constants.PowerLauncherCentralizedHookSharedEvent(), OnCentralizedKeyboardHookHotKey, _nativeWaiterCancelToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
_settings.PropertyChanged += (s, e) =>
|
_settings.PropertyChanged += (s, e) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user