From 80348b211660726bfe3e757038694f27cebe90ac Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Wed, 8 Jul 2026 23:31:22 +0200 Subject: [PATCH 1/2] Fix WindowCollection RemoveAt (#11610) --- .../System/Windows/WindowCollection.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/WindowCollection.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/WindowCollection.cs index 7ec6cb0ea27..82bf22860b8 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/WindowCollection.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/WindowCollection.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // @@ -167,11 +167,11 @@ internal void RemoveAt(int index) { lock (_list.SyncRoot) { - _list.Remove(index); + _list.RemoveAt(index); } } - internal int Add (Window win) + internal int Add(Window win) { lock (_list.SyncRoot) { @@ -201,7 +201,7 @@ internal bool HasItem(Window win) // //------------------------------------------------------ #region Private Fields - private ArrayList _list; + private readonly ArrayList _list; #endregion Private Fields } From e1415ff02d5d433e3b2eef5d7a71203ac173b2f7 Mon Sep 17 00:00:00 2001 From: h3xds1nz Date: Wed, 8 Jul 2026 23:31:51 +0200 Subject: [PATCH 2/2] Fix hanging window objects (#4204) --- .../System/Windows/Application.cs | 2 +- .../System/Windows/Window.cs | 39 ++++++++++++++----- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs index 545d4bd06a6..000dbbe097c 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Application.cs @@ -1591,7 +1591,7 @@ internal virtual void DoShutdown() // in the function that calls us. // We use a while loop like this because closing a window will modify the windows list. - while(WindowsInternal.Count > 0) + while (WindowsInternal.Count > 0) { if (!WindowsInternal[0].IsDisposed) { diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs index aedc66a4e76..dd5d7432bdd 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs @@ -4511,16 +4511,9 @@ private void UpdateWindowListsOnClose() App.WindowsInternal.Remove(this); // Check to see if app should shut down--this behavior really belongs in Application - if (!_appShuttingDown) + if (!_appShuttingDown && ShouldCloseApplication()) { - // If this is the last window that's closing and shutdownmode is onlastwindowclose, or - // if this is the main window closing and shutdownmode is onmainwindowclose, shutdown - // the app - if (((App.Windows.Count == 0) && (App.ShutdownMode == ShutdownMode.OnLastWindowClose)) - || ((App.MainWindow == this) && (App.ShutdownMode == ShutdownMode.OnMainWindowClose))) - { - App.CriticalShutdown(0); - } + App.CriticalShutdown(0); } TryClearingMainWindow(); @@ -4530,7 +4523,33 @@ private void UpdateWindowListsOnClose() App.NonAppWindowsInternal.Remove(this); } } -} + } + + private bool ShouldCloseApplication() + { + if (App.ShutdownMode is ShutdownMode.OnLastWindowClose) + { + // 1) If this is the last window and shutdown mode is OnLastWindowClose, then we can close the app + // 2) We should also close the app if all of the remaining windows are windows that were created, + // -- but never shown (excludes inits via EnsureHandle via WindowInteropHelper, such windows are considered shown). + lock (App.WindowsInternal.SyncRoot) + { + for (int i = App.WindowsInternal.Count - 1; i >= 0; i--) + { + if (!App.WindowsInternal[i].IsSourceWindowNull) + { + return false; + } + } + } + + return true; + } + + // If this is the main window and shutdown mode is OnMainWindowClose, then we can close the app + return App.ShutdownMode is ShutdownMode.OnMainWindowClose && App.MainWindow == this; + } + private bool WmDestroy() { // For WS_CHILD window, WM_SIZE, WM_MOVE (and maybe others) are called