Files
ReLibreHardwareMonitor/LibreHardwareMonitor.Windows.WinUI/App.xaml.cs
T
JMR-devandCopilot 3e71e09a25 Invert composition root to DI container
Build the Microsoft.Extensions.DependencyInjection provider in App and resolve the view model and runtime factory from it, replacing the manual new MainWindow(trace) path. MainWindow now takes an injected ctor (view model, tracer, runtime factory, provider); window-tied services are produced by MainWindowRuntimeFactory once the window exists. On real shutdown MainWindow_Closed disposes the provider (which disposes the view model first, then domain services and tracer), while the minimize-to-tray branch returns before any teardown.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-02 15:16:28 -05:00

114 lines
4.3 KiB
C#

// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Copyright (C) LibreHardwareMonitor and Contributors.
using System;
using System.IO;
using System.Threading.Tasks;
using LibreHardwareMonitor.Windows.WinUI.Composition;
using LibreHardwareMonitor.Windows.WinUI.Services.Tracing;
using LibreHardwareMonitor.Windows.WinUI.ViewModels;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Xaml;
using IOPath = System.IO.Path;
namespace LibreHardwareMonitor.Windows.WinUI;
public partial class App : Application
{
private bool _launchStarted;
private readonly IStartupTracer _startupTrace;
private ServiceProvider? _serviceProvider;
private Window? _window;
public App()
{
_startupTrace = StartupTracer.Create();
_startupTrace.Mark("App.Constructor.Begin");
MeasureStartup("App.WireExceptionHandlers", () =>
{
UnhandledException += App_UnhandledException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
});
MeasureStartup("App.InitializeComponent", InitializeComponent);
_startupTrace.Mark("App.Constructor.Complete");
_startupTrace.Flush();
}
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
MeasureStartup("App.OnLaunched", LaunchMainWindow);
}
private void LaunchMainWindow()
{
if (_launchStarted)
return;
_launchStarted = true;
try
{
_startupTrace.Mark("App.LaunchMainWindow.Begin");
_serviceProvider = MeasureStartup("App.BuildServiceProvider", () =>
new ServiceCollection().AddAppServices(_startupTrace).BuildServiceProvider());
MainWindow mainWindow = MeasureStartup("App.CreateMainWindow", () => new MainWindow(
_serviceProvider.GetRequiredService<MainWindowViewModel>(),
_startupTrace,
_serviceProvider.GetRequiredService<IMainWindowRuntimeFactory>(),
_serviceProvider));
_window = mainWindow;
MeasureStartup("App.ActivateWindow", mainWindow.Activate);
MeasureStartup("App.StartMonitoringAfterActivation", mainWindow.StartMonitoringAfterActivation);
_startupTrace.Mark("App.LaunchMainWindow.Complete");
_startupTrace.Flush();
}
catch (Exception ex)
{
_startupTrace.Mark("App.LaunchMainWindow.Exception", $"{ex.GetType().FullName}: {ex.Message}");
_startupTrace.Flush();
WriteExceptionLog("Window launch failed", ex);
throw;
}
}
private void MeasureStartup(string phase, Action action)
{
_startupTrace.Measure(phase, action);
}
private T MeasureStartup<T>(string phase, Func<T> action)
{
return _startupTrace.Measure(phase, action);
}
private static void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs args)
{
WriteExceptionLog("WinUI unhandled exception", args.Exception);
}
private static void CurrentDomain_UnhandledException(object sender, System.UnhandledExceptionEventArgs args)
{
if (args.ExceptionObject is Exception exception)
WriteExceptionLog("AppDomain unhandled exception", exception);
else
WriteMessageLog($"AppDomain unhandled exception: {args.ExceptionObject}");
}
private static void TaskScheduler_UnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs args)
{
WriteExceptionLog("Unobserved task exception", args.Exception);
}
private static void WriteExceptionLog(string context, Exception exception)
{
WriteMessageLog($"{context}{Environment.NewLine}{exception}");
}
private static void WriteMessageLog(string message)
{
string logPath = IOPath.Combine(AppContext.BaseDirectory, "LibreHardwareMonitor.Windows.WinUI.startup.log");
File.AppendAllText(logPath, $"{DateTimeOffset.Now:u} {message}{Environment.NewLine}{Environment.NewLine}");
}
}