From dadfe5b8efc59422f9b66ba74c6bace5530e6ffd Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Mar 2026 18:42:35 +0200 Subject: [PATCH] Guard App.Dispose() against double-invocation and late shutdown (#1499) Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- DiscordChatExporter.Gui/App.axaml.cs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/DiscordChatExporter.Gui/App.axaml.cs b/DiscordChatExporter.Gui/App.axaml.cs index 0673e3f4..bb27f1d6 100644 --- a/DiscordChatExporter.Gui/App.axaml.cs +++ b/DiscordChatExporter.Gui/App.axaml.cs @@ -26,6 +26,8 @@ public class App : Application, IDisposable private readonly SettingsService _settingsService; private readonly MainViewModel _mainViewModel; + private bool _isDisposed; + public App() { var services = new ServiceCollection(); @@ -98,8 +100,24 @@ public class App : Application, IDisposable public override void OnFrameworkInitializationCompleted() { if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { desktop.MainWindow = new MainView { DataContext = _mainViewModel }; + void OnExit(object? sender, ControlledApplicationLifetimeExitEventArgs args) + { + if (sender is IControlledApplicationLifetime lifetime) + lifetime.Exit -= OnExit; + + Dispose(); + } + + // Although `App.Dispose()` is invoked from `Program.Main(...)`, on some platforms + // it may be called too late in the shutdown lifecycle. Attach an exit + // handler to ensure timely disposal as a safeguard. + // https://github.com/Tyrrrz/YoutubeDownloader/issues/795 + desktop.Exit += OnExit; + } + base.OnFrameworkInitializationCompleted(); // Set up custom theme colors @@ -115,6 +133,11 @@ public class App : Application, IDisposable public void Dispose() { + if (_isDisposed) + return; + + _isDisposed = true; + _eventRoot.Dispose(); _services.Dispose(); }