Files
PowerToys/src/modules/launcher/PowerLauncher/App.xaml.cs
Jeremy Sinclair 00ee6c1510 [Dev][Build] .NET 9 Upgrade (#35716)
* [Deps] Upgrade Framework Libraries to .NET 9 RC2

* [Common][Build] Update TFM to NET9

* [FileLocksmith][Build] Update TFM to NET9 in Publish Profile

* [PreviewPane][Build] Update TFM to NET9 in Publish Profile

* [PTRun][Build] Update TFM to NET9 in Publish Profile

* [Settings][Build] Update TFM to NET9 in Publish Profile

* [MouseWithoutBorders][Analyzers] Resolve WFO1000 by configuring Designer Serialization Visibility

* [Deps] Update Microsoft.CodeAnalysis.NetAnalyzers

* [Analyzers] Set CA1859,CA2263,CA2022 to be excluded from error

* [MouseWithoutBorders] Use System.Threading.Lock to lock instead of object instance

* [ColorPicker] Use System.Threading.Lock to lock instead of object instance

* [AdvancedPaste] Use System.Threading.Lock to lock instead of object instance

* [TextExtractor] Use System.Threading.Lock to lock instead of object instance

* [Hosts] Use System.Threading.Lock to lock instead of object instance

* [MouseJump] Use System.Threading.Lock to lock instead of object instance

* [PTRun] Use System.Threading.Lock to lock instead of object instance

* [Wox] Use System.Threading.Lock to lock instead of object instance

* [Peek] Use System.Threading.Lock to lock instead of object instance

* [PowerAccent] Use System.Threading.Lock to lock instead of object instance

* [Settings] Use System.Threading.Lock to lock instead of object instance

* [Deps] Update NOTICE.md

* [CI] Update .NET version step to target 9.0

* [Build] Attempt to add manual trigger for using Visual Studio Preview for building

* [Build] Fix variable typo

* [Build][Temporary] set to use preview builds

* [Build] Add missing parameters

* [Build][Temporary] directly hardcode preview image

* [Build][Temporary] Trying ImageOverride

* [Build] Revert hardcode and use ImageOverride

* [Build] Add env var for adding prerelease argument for vswhere

* [Build] Update VCToolsVersion script to use env var to optionally add prerelease version checking

* [Build] Remove unneeded parameter

* [Build] Re-add parameter in all the right places

* [CI][Build] Add NoWarn NU5104 when building with VS Preview

* [Deps] Update to stable .NET 9 packages

* [Deps] Update NOTICE.md

* Everything is WPF and WindowsForms now to fix .NET 9 dependency conflicts

* Ensure .NET 9 SDK for tests too

---------

Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
2024-11-13 12:36:45 -05:00

298 lines
10 KiB
C#

// 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.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using ManagedCommon;
using Microsoft.PowerLauncher.Telemetry;
using Microsoft.PowerToys.Telemetry;
using PowerLauncher.Helper;
using PowerLauncher.Plugin;
using PowerLauncher.ViewModel;
using PowerToys.Interop;
using Windows.Globalization;
using Wox;
using Wox.Infrastructure;
using Wox.Infrastructure.Image;
using Wox.Infrastructure.UserSettings;
using Wox.Plugin;
using Wox.Plugin.Logger;
using Stopwatch = Wox.Infrastructure.Stopwatch;
namespace PowerLauncher
{
public partial class App : IDisposable, ISingleInstanceApp
{
public static PublicAPIInstance API { get; private set; }
private readonly Alphabet _alphabet = new Alphabet();
public static CancellationTokenSource NativeThreadCTS { get; private set; }
private static bool _disposed;
private PowerToysRunSettings _settings;
private MainViewModel _mainVM;
private MainWindow _mainWindow;
private ThemeManager _themeManager;
private SettingWindowViewModel _settingsVM;
private StringMatcher _stringMatcher;
private SettingsReader _settingsReader;
private ETWTrace etwTrace = new ETWTrace();
// To prevent two disposals running at the same time.
private static readonly Lock _disposingLock = new Lock();
[STAThread]
public static void Main()
{
NativeThreadCTS = new CancellationTokenSource();
try
{
string appLanguage = LanguageHelper.LoadLanguage();
if (!string.IsNullOrEmpty(appLanguage))
{
System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo(appLanguage);
}
}
catch (CultureNotFoundException ex)
{
Logger.LogError("CultureNotFoundException: " + ex.Message);
}
Log.Info($"Starting PowerToys Run with PID={Environment.ProcessId}", typeof(App));
if (PowerToys.GPOWrapperProjection.GPOWrapper.GetConfiguredPowerLauncherEnabledValue() == PowerToys.GPOWrapperProjection.GpoRuleConfigured.Disabled)
{
Log.Warn("Tried to start with a GPO policy setting the utility to always be disabled. Please contact your systems administrator.", typeof(App));
return;
}
int powerToysPid = GetPowerToysPId();
if (powerToysPid != 0)
{
// The process started from the PT Run module interface. One instance is handled there.
Log.Info($"Runner pid={powerToysPid}", typeof(App));
SingleInstance<App>.CreateInstanceMutex();
}
else
{
// If PT Run is started as standalone application check if there is already running instance
if (!SingleInstance<App>.InitializeAsFirstInstance())
{
Log.Warn("There is already running PowerToys Run instance. Exiting PowerToys Run", typeof(App));
return;
}
}
using (var application = new App())
{
application.InitializeComponent();
Common.UI.NativeEventWaiter.WaitForEventLoop(
Constants.RunExitEvent(),
() =>
{
Log.Warn("RunExitEvent was signaled. Exiting PowerToys", typeof(App));
application.etwTrace?.Dispose();
application.etwTrace = null;
ExitPowerToys(application);
},
Application.Current.Dispatcher,
NativeThreadCTS.Token);
if (powerToysPid != 0)
{
RunnerHelper.WaitForPowerToysRunner(powerToysPid, () =>
{
Log.Info($"Runner with pid={powerToysPid} exited. Exiting PowerToys Run", typeof(App));
application.etwTrace?.Dispose();
application.etwTrace = null;
ExitPowerToys(application);
});
}
application.Run();
}
}
private void OnStartup(object sender, StartupEventArgs e)
{
Log.Info("On Startup.", GetType());
// Fix for .net 3.1.19 making PowerToys Run not adapt to DPI changes.
PowerLauncher.Helper.NativeMethods.SetProcessDPIAware();
var bootTime = new System.Diagnostics.Stopwatch();
bootTime.Start();
Stopwatch.Normal("App.OnStartup - Startup cost", () =>
{
var textToLog = new StringBuilder();
textToLog.AppendLine("Begin PowerToys Run startup ----------------------------------------------------");
textToLog.AppendLine(CultureInfo.InvariantCulture, $"Runtime info:{ErrorReporting.RuntimeInfo()}");
RegisterAppDomainExceptions();
RegisterDispatcherUnhandledException();
ImageLoader.Initialize();
_settingsVM = new SettingWindowViewModel();
_settings = _settingsVM.Settings;
_settings.StartedFromPowerToysRunner = e.Args.Contains("--started-from-runner");
_alphabet.Initialize(_settings);
_stringMatcher = new StringMatcher(_alphabet);
StringMatcher.Instance = _stringMatcher;
_stringMatcher.UserSettingSearchPrecision = _settings.QuerySearchPrecision;
_mainVM = new MainViewModel(_settings, NativeThreadCTS.Token);
_mainWindow = new MainWindow(_settings, _mainVM, NativeThreadCTS.Token);
_themeManager = new ThemeManager(_settings, _mainWindow);
API = new PublicAPIInstance(_settingsVM, _mainVM, _alphabet, _themeManager);
_settingsReader = new SettingsReader(_settings, _themeManager);
_settingsReader.ReadSettings();
PluginManager.InitializePlugins(API);
_mainVM.RefreshPluginsOverview();
_settingsReader.SetRefreshPluginsOverviewCallback(() => _mainVM.RefreshPluginsOverview());
Current.MainWindow = _mainWindow;
Current.MainWindow.Title = Constant.ExeFileName;
RegisterExitEvents();
_settingsReader.ReadSettingsOnChange();
textToLog.AppendLine("End PowerToys Run startup ---------------------------------------------------- ");
bootTime.Stop();
Log.Info(textToLog.ToString(), GetType());
PowerToysTelemetry.Log.WriteEvent(new LauncherBootEvent() { BootTimeMs = bootTime.ElapsedMilliseconds });
});
}
private static void ExitPowerToys(App app)
{
SingleInstance<App>.SingleInstanceMutex.Close();
app.Dispatcher.Invoke(() => app.Shutdown());
}
private static int GetPowerToysPId()
{
var args = Environment.GetCommandLineArgs();
for (int i = 0; i + 1 < args.Length; i++)
{
if (args[i] == "-powerToysPid")
{
int powerToysPid;
if (int.TryParse(args[i + 1], out powerToysPid))
{
return powerToysPid;
}
break;
}
}
return 0;
}
private void RegisterExitEvents()
{
AppDomain.CurrentDomain.ProcessExit += (s, e) =>
{
Log.Info("AppDomain.CurrentDomain.ProcessExit", GetType());
Dispose();
};
Current.Exit += (s, e) =>
{
NativeThreadCTS.Cancel();
Log.Info("Application.Current.Exit", GetType());
Dispose();
};
Current.SessionEnding += (s, e) =>
{
Log.Info("Application.Current.SessionEnding", GetType());
Dispose();
};
}
/// <summary>
/// let exception throw as normal is better for Debug
/// </summary>
[Conditional("RELEASE")]
private void RegisterDispatcherUnhandledException()
{
DispatcherUnhandledException += ErrorReporting.DispatcherUnhandledException;
}
/// <summary>
/// let exception throw as normal is better for Debug
/// </summary>
[Conditional("RELEASE")]
private static void RegisterAppDomainExceptions()
{
AppDomain.CurrentDomain.UnhandledException += ErrorReporting.UnhandledExceptionHandle;
}
public void OnSecondAppStarted()
{
Current.MainWindow.Visibility = Visibility.Visible;
}
protected virtual void Dispose(bool disposing)
{
// Prevent two disposes at the same time.
lock (_disposingLock)
{
if (!disposing)
{
return;
}
if (_disposed)
{
return;
}
_disposed = true;
}
Stopwatch.Normal("App.OnExit - Exit cost", () =>
{
Log.Info("Start PowerToys Run Exit---------------------------------------------------- ", GetType());
if (disposing)
{
API?.SaveAppAllSettings();
PluginManager.Dispose();
// Dispose needs to be called on the main Windows thread, since some resources owned by the thread need to be disposed.
_mainWindow?.Dispatcher.Invoke(Dispose);
_mainVM?.Dispose();
}
Log.Info("End PowerToys Run Exit ---------------------------------------------------- ", GetType());
});
}
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}