App.xaml.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using ManagedCommon; 6 using Microsoft.CmdPal.Core.Common; 7 using Microsoft.CmdPal.Core.Common.Helpers; 8 using Microsoft.CmdPal.Core.Common.Services; 9 using Microsoft.CmdPal.Core.ViewModels; 10 using Microsoft.CmdPal.Ext.Apps; 11 using Microsoft.CmdPal.Ext.Bookmarks; 12 using Microsoft.CmdPal.Ext.Calc; 13 using Microsoft.CmdPal.Ext.ClipboardHistory; 14 using Microsoft.CmdPal.Ext.Indexer; 15 using Microsoft.CmdPal.Ext.Registry; 16 using Microsoft.CmdPal.Ext.RemoteDesktop; 17 using Microsoft.CmdPal.Ext.Shell; 18 using Microsoft.CmdPal.Ext.System; 19 using Microsoft.CmdPal.Ext.TimeDate; 20 using Microsoft.CmdPal.Ext.WebSearch; 21 using Microsoft.CmdPal.Ext.WindowsServices; 22 using Microsoft.CmdPal.Ext.WindowsSettings; 23 using Microsoft.CmdPal.Ext.WindowsTerminal; 24 using Microsoft.CmdPal.Ext.WindowWalker; 25 using Microsoft.CmdPal.Ext.WinGet; 26 using Microsoft.CmdPal.UI.Helpers; 27 using Microsoft.CmdPal.UI.Services; 28 using Microsoft.CmdPal.UI.ViewModels; 29 using Microsoft.CmdPal.UI.ViewModels.BuiltinCommands; 30 using Microsoft.CmdPal.UI.ViewModels.Models; 31 using Microsoft.CmdPal.UI.ViewModels.Services; 32 using Microsoft.CommandPalette.Extensions; 33 using Microsoft.Extensions.DependencyInjection; 34 using Microsoft.PowerToys.Telemetry; 35 using Microsoft.UI.Dispatching; 36 using Microsoft.UI.Xaml; 37 38 // To learn more about WinUI, the WinUI project structure, 39 // and more about our project templates, see: http://aka.ms/winui-project-info. 40 namespace Microsoft.CmdPal.UI; 41 42 /// <summary> 43 /// Provides application-specific behavior to supplement the default Application class. 44 /// </summary> 45 public partial class App : Application, IDisposable 46 { 47 private readonly GlobalErrorHandler _globalErrorHandler = new(); 48 49 /// <summary> 50 /// Gets the current <see cref="App"/> instance in use. 51 /// </summary> 52 public static new App Current => (App)Application.Current; 53 54 public Window? AppWindow { get; private set; } 55 56 public ETWTrace EtwTrace { get; private set; } = new ETWTrace(); 57 58 /// <summary> 59 /// Gets the <see cref="IServiceProvider"/> instance to resolve application services. 60 /// </summary> 61 public IServiceProvider Services { get; } 62 63 /// <summary> 64 /// Initializes a new instance of the <see cref="App"/> class. 65 /// Initializes the singleton application object. This is the first line of authored code 66 /// executed, and as such is the logical equivalent of main() or WinMain(). 67 /// </summary> 68 public App() 69 { 70 #if !CMDPAL_DISABLE_GLOBAL_ERROR_HANDLER 71 _globalErrorHandler.Register(this, GlobalErrorHandler.Options.Default); 72 #endif 73 74 Services = ConfigureServices(); 75 76 IconCacheProvider.Initialize(Services); 77 78 this.InitializeComponent(); 79 80 // Ensure types used in XAML are preserved for AOT compilation 81 TypePreservation.PreserveTypes(); 82 83 NativeEventWaiter.WaitForEventLoop( 84 "Local\\PowerToysCmdPal-ExitEvent-eb73f6be-3f22-4b36-aee3-62924ba40bfd", () => 85 { 86 EtwTrace?.Dispose(); 87 AppWindow?.Close(); 88 Environment.Exit(0); 89 }); 90 91 // Connect the PT logging to the core project's logging. 92 // This way, log statements from the core project will be captured by the PT logs 93 var logWrapper = new LogWrapper(); 94 CoreLogger.InitializeLogger(logWrapper); 95 } 96 97 /// <summary> 98 /// Invoked when the application is launched. 99 /// </summary> 100 /// <param name="args">Details about the launch request and process.</param> 101 protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args) 102 { 103 AppWindow = new MainWindow(); 104 105 var activatedEventArgs = Microsoft.Windows.AppLifecycle.AppInstance.GetCurrent().GetActivatedEventArgs(); 106 ((MainWindow)AppWindow).HandleLaunchNonUI(activatedEventArgs); 107 } 108 109 /// <summary> 110 /// Configures the services for the application 111 /// </summary> 112 private static ServiceProvider ConfigureServices() 113 { 114 // TODO: It's in the Labs feed, but we can use Sergio's AOT-friendly source generator for this: https://github.com/CommunityToolkit/Labs-Windows/discussions/463 115 ServiceCollection services = new(); 116 117 // Root services 118 services.AddSingleton(TaskScheduler.FromCurrentSynchronizationContext()); 119 var dispatcherQueue = DispatcherQueue.GetForCurrentThread(); 120 121 AddBuiltInCommands(services); 122 123 AddCoreServices(services); 124 125 AddUIServices(services, dispatcherQueue); 126 127 return services.BuildServiceProvider(); 128 } 129 130 private static void AddBuiltInCommands(ServiceCollection services) 131 { 132 // Built-in Commands. Order matters - this is the order they'll be presented by default. 133 var allApps = new AllAppsCommandProvider(); 134 var files = new IndexerCommandsProvider(); 135 files.SuppressFallbackWhen(ShellCommandsProvider.SuppressFileFallbackIf); 136 services.AddSingleton<ICommandProvider>(allApps); 137 138 services.AddSingleton<ICommandProvider, ShellCommandsProvider>(); 139 services.AddSingleton<ICommandProvider, CalculatorCommandProvider>(); 140 services.AddSingleton<ICommandProvider>(files); 141 services.AddSingleton<ICommandProvider, BookmarksCommandProvider>(_ => BookmarksCommandProvider.CreateWithDefaultStore()); 142 143 services.AddSingleton<ICommandProvider, WindowWalkerCommandsProvider>(); 144 services.AddSingleton<ICommandProvider, WebSearchCommandsProvider>(); 145 services.AddSingleton<ICommandProvider, ClipboardHistoryCommandsProvider>(); 146 147 // GH #38440: Users might not have WinGet installed! Or they might have 148 // a ridiculously old version. Or might be running as admin. 149 // We shouldn't explode in the App ctor if we fail to instantiate an 150 // instance of PackageManager, which will happen in the static ctor 151 // for WinGetStatics 152 try 153 { 154 var winget = new WinGetExtensionCommandsProvider(); 155 winget.SetAllLookup( 156 query => allApps.LookupAppByPackageFamilyName(query, requireSingleMatch: true), 157 query => allApps.LookupAppByProductCode(query, requireSingleMatch: true)); 158 services.AddSingleton<ICommandProvider>(winget); 159 } 160 catch (Exception ex) 161 { 162 Logger.LogError("Couldn't load winget"); 163 Logger.LogError(ex.ToString()); 164 } 165 166 services.AddSingleton<ICommandProvider, WindowsTerminalCommandsProvider>(); 167 services.AddSingleton<ICommandProvider, WindowsSettingsCommandsProvider>(); 168 services.AddSingleton<ICommandProvider, RegistryCommandsProvider>(); 169 services.AddSingleton<ICommandProvider, WindowsServicesCommandsProvider>(); 170 services.AddSingleton<ICommandProvider, BuiltInsCommandProvider>(); 171 services.AddSingleton<ICommandProvider, TimeDateCommandsProvider>(); 172 services.AddSingleton<ICommandProvider, SystemCommandExtensionProvider>(); 173 services.AddSingleton<ICommandProvider, RemoteDesktopCommandProvider>(); 174 } 175 176 private static void AddUIServices(ServiceCollection services, DispatcherQueue dispatcherQueue) 177 { 178 // Models 179 var sm = SettingsModel.LoadSettings(); 180 services.AddSingleton(sm); 181 var state = AppStateModel.LoadState(); 182 services.AddSingleton(state); 183 184 // Services 185 services.AddSingleton<ICommandProviderCache, DefaultCommandProviderCache>(); 186 services.AddSingleton<TopLevelCommandManager>(); 187 services.AddSingleton<AliasManager>(); 188 services.AddSingleton<HotkeyManager>(); 189 190 services.AddSingleton<MainWindowViewModel>(); 191 services.AddSingleton<TrayIconService>(); 192 193 services.AddSingleton<IThemeService, ThemeService>(); 194 services.AddSingleton<ResourceSwapper>(); 195 196 services.AddIconServices(dispatcherQueue); 197 } 198 199 private static void AddCoreServices(ServiceCollection services) 200 { 201 // Core services 202 services.AddSingleton<IExtensionService, ExtensionService>(); 203 services.AddSingleton<IRunHistoryService, RunHistoryService>(); 204 205 services.AddSingleton<IRootPageService, PowerToysRootPageService>(); 206 services.AddSingleton<IAppHostService, PowerToysAppHostService>(); 207 services.AddSingleton<ITelemetryService, TelemetryForwarder>(); 208 209 // ViewModels 210 services.AddSingleton<ShellViewModel>(); 211 services.AddSingleton<IPageViewModelFactoryService, CommandPalettePageViewModelFactory>(); 212 } 213 214 public void Dispose() 215 { 216 _globalErrorHandler.Dispose(); 217 EtwTrace.Dispose(); 218 GC.SuppressFinalize(this); 219 } 220 }