diff --git a/LibreHardwareMonitor.Windows.WinUI/MainWindow.cs b/LibreHardwareMonitor.Windows.WinUI/MainWindow.cs index 26f2d47..0d61987 100644 --- a/LibreHardwareMonitor.Windows.WinUI/MainWindow.cs +++ b/LibreHardwareMonitor.Windows.WinUI/MainWindow.cs @@ -456,16 +456,22 @@ public sealed partial class MainWindow : Window } _isShuttingDown = true; - _timer.Stop(); - _columnMeasurer.StopSettleTimer(); - _trayIconService.Dispose(); - _secondaryWindows.CloseAll(); - _placementService.Save(); - - // The container owns the view model and domain services. Disposing the provider runs - // MainWindowViewModel.Dispose first (reverse construction order) to persist settings while the - // hardware monitor and web server are still alive, then disposes those services and the tracer. - (_serviceProvider as IDisposable)?.Dispose(); + try + { + _timer.Stop(); + _columnMeasurer.StopSettleTimer(); + _trayIconService.Dispose(); + _secondaryWindows.CloseAll(); + _placementService.Save(); + } + finally + { + // The container owns the view model and domain services. Disposing the provider runs + // MainWindowViewModel.Dispose first (reverse construction order) to persist settings while the + // hardware monitor and web server are still alive, then disposes those services and the tracer. + // This MUST run even if a teardown step above throws, so the ring0 driver is always unloaded. + (_serviceProvider as IDisposable)?.Dispose(); + } } private void AppWindow_Changed(AppWindow sender, AppWindowChangedEventArgs args) diff --git a/LibreHardwareMonitor.Windows.WinUI/Services/HardwareMonitorService.cs b/LibreHardwareMonitor.Windows.WinUI/Services/HardwareMonitorService.cs index 95df3cb..739d4c3 100644 --- a/LibreHardwareMonitor.Windows.WinUI/Services/HardwareMonitorService.cs +++ b/LibreHardwareMonitor.Windows.WinUI/Services/HardwareMonitorService.cs @@ -28,6 +28,7 @@ public sealed class HardwareMonitorService : IHardwareMonitorService private readonly UpdateVisitor _updateVisitor = new(); private readonly TreeRebuildCoalescer _treeRebuildCoalescer; private bool _isOpen; + private bool _disposed; public HardwareMonitorService(AppSettings settings) { @@ -199,6 +200,11 @@ public sealed class HardwareMonitorService : IHardwareMonitorService public void Dispose() { + if (_disposed) + return; + + _disposed = true; + // Clear before closing so any tree-rebuild task still pending its delay bails instead of rebuilding from a // half-closed Computer. _isOpen = false; diff --git a/LibreHardwareMonitor.Windows.WinUI/ViewModels/MainWindowViewModel.cs b/LibreHardwareMonitor.Windows.WinUI/ViewModels/MainWindowViewModel.cs index 3f6d081..8d7f2f4 100644 --- a/LibreHardwareMonitor.Windows.WinUI/ViewModels/MainWindowViewModel.cs +++ b/LibreHardwareMonitor.Windows.WinUI/ViewModels/MainWindowViewModel.cs @@ -90,7 +90,6 @@ public sealed class MainWindowViewModel : ViewModelBase, IDisposable private readonly IRemoteWebServer _remoteWebServer; private readonly StartupService _startupService; private readonly IStartupTracer _startupTrace; - private readonly bool _ownsServices; private AppThemeMode _themeMode; private int _loggingIntervalIndex; private PlotLocation _plotLocation; @@ -141,32 +140,6 @@ public sealed class MainWindowViewModel : ViewModelBase, IDisposable InitializeFromSettings(settings); } - // Transitional constructor that builds the domain graph the legacy way for callers that do not yet - // resolve the view model from the container. Removed once MainWindow is DI-resolved (di-app-invert). - internal MainWindowViewModel(AppSettings settings, IStartupTracer startupTrace) - { - Settings = settings; - _startupTrace = startupTrace; - _startupTrace.Mark("MainWindowViewModel.Constructor.Begin"); - _dispatcherQueue = DispatcherQueue.GetForCurrentThread(); - HardwareMonitorService hardwareMonitor = new(settings); - _hardwareMonitor = hardwareMonitor; - _logger = new Logger(hardwareMonitor.Computer); - _sensorSelection = new SensorSelectionService(settings); - _remoteWebServer = new RemoteWebServer( - hardwareMonitor.Computer, - hardwareMonitor.SensorReadLock, - settings.GetValue("listenerIp", "?"), - settings.GetValue("listenerPort", 8085), - settings.GetValue("authenticationEnabled", false), - settings.GetValue("authenticationUserName", ""), - settings.GetValue("authenticationPassword", "")); - _plotTracking = new PlotTrackingService(); - _startupService = new StartupService(); - _ownsServices = true; - InitializeFromSettings(settings); - } - private void InitializeFromSettings(AppSettings settings) { _remoteWebServer.SetRootProvider(() => RootItems.FirstOrDefault()); @@ -789,8 +762,6 @@ public sealed class MainWindowViewModel : ViewModelBase, IDisposable Settings.SetValue("authenticationUserName", AuthWebServerUserName); Settings.SetValue("authenticationPassword", _remoteWebServer.PasswordHash); _remoteWebServer.Quit(); - if (_ownsServices) - _hardwareMonitor.Dispose(); Save(); }