From dda69255c4c3f667ec4025a038678f89111dcb41 Mon Sep 17 00:00:00 2001 From: Jay Wang Date: Fri, 28 Aug 2026 16:22:58 +0800 Subject: [PATCH 1/3] Handle disposed AsyncWaitHandle during BeginInvoke completion --- .../Windows/Forms/Control.ThreadMethodEntry.cs | 9 ++++++++- .../System/Windows/Forms/ControlTests.Methods.cs | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/System.Windows.Forms/System/Windows/Forms/Control.ThreadMethodEntry.cs b/src/System.Windows.Forms/System/Windows/Forms/Control.ThreadMethodEntry.cs index 9d7acffbc59..1c90650afd5 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Control.ThreadMethodEntry.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Control.ThreadMethodEntry.cs @@ -76,7 +76,14 @@ internal void Complete() lock (_invokeSyncObject) { IsCompleted = true; - _resetEvent?.Set(); + try + { + _resetEvent?.Set(); + } + catch (ObjectDisposedException) + { + // AsyncWaitHandle exposes the event and allows callers to dispose it before completion. + } } } } diff --git a/src/test/unit/System.Windows.Forms/System/Windows/Forms/ControlTests.Methods.cs b/src/test/unit/System.Windows.Forms/System/Windows/Forms/ControlTests.Methods.cs index b9f3ad3682b..ddb5e68978c 100644 --- a/src/test/unit/System.Windows.Forms/System/Windows/Forms/ControlTests.Methods.cs +++ b/src/test/unit/System.Windows.Forms/System/Windows/Forms/ControlTests.Methods.cs @@ -3850,6 +3850,21 @@ await Task.Run(() => Assert.Equal(0, createdCallCount); } + [WinFormsFact] + public void Control_BeginInvoke_DisposedAsyncWaitHandle_CompletesCallback() + { + using Control control = new(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + bool callbackInvoked = false; + IAsyncResult asyncResult = control.BeginInvoke(() => callbackInvoked = true); + asyncResult.AsyncWaitHandle.Dispose(); + + control.TestAccessor.Dynamic.InvokeMarshaledCallbacks(); + + Assert.True(callbackInvoked); + Assert.True(asyncResult.IsCompleted); + } + [WinFormsFact] public void Control_Invoke_Action_calls_correct_method() { From 280bc58e42eb420b6134b33f23eb4d5de5b5284c Mon Sep 17 00:00:00 2001 From: Jay Wang Date: Mon, 31 Aug 2026 13:48:27 +0800 Subject: [PATCH 2/3] Adapt AsyncWaitHandle test to fork message loop --- .../System/Windows/Forms/ControlTests.Methods.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/unit/System.Windows.Forms/System/Windows/Forms/ControlTests.Methods.cs b/src/test/unit/System.Windows.Forms/System/Windows/Forms/ControlTests.Methods.cs index ddb5e68978c..12fa688aaf2 100644 --- a/src/test/unit/System.Windows.Forms/System/Windows/Forms/ControlTests.Methods.cs +++ b/src/test/unit/System.Windows.Forms/System/Windows/Forms/ControlTests.Methods.cs @@ -3859,7 +3859,7 @@ public void Control_BeginInvoke_DisposedAsyncWaitHandle_CompletesCallback() IAsyncResult asyncResult = control.BeginInvoke(() => callbackInvoked = true); asyncResult.AsyncWaitHandle.Dispose(); - control.TestAccessor.Dynamic.InvokeMarshaledCallbacks(); + Application.DoEvents(); Assert.True(callbackInvoked); Assert.True(asyncResult.IsCompleted); From 992027738851cf2de62838b3f1a5ac478295f3e0 Mon Sep 17 00:00:00 2001 From: Jay Wang Date: Mon, 31 Aug 2026 14:24:47 +0800 Subject: [PATCH 3/3] update the package description --- .../System.Windows.Forms.Package.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Windows.Forms.Legacy/System.Windows.Forms.Package/System.Windows.Forms.Package.csproj b/src/System.Windows.Forms.Legacy/System.Windows.Forms.Package/System.Windows.Forms.Package.csproj index c7a32613da9..875d39dba57 100644 --- a/src/System.Windows.Forms.Legacy/System.Windows.Forms.Package/System.Windows.Forms.Package.csproj +++ b/src/System.Windows.Forms.Legacy/System.Windows.Forms.Package/System.Windows.Forms.Package.csproj @@ -10,7 +10,7 @@ 0.1.0 $(WtgPackageVersionPrefix)-dev WiseTech Global forked version of System.Windows.Forms that includes controls that were deprecated in .NET Core 3.1 and .NET 5, like DataGrid, Menu, ToolBar and StatusBar. - Fix the accessibility access on DataGrid components, PR link: https://github.com/WiseTechGlobal/winforms/pull/41 + Handle disposed AsyncWaitHandle during BeginInvoke completion, version 0.2.17, PR link: https://github.com/WiseTechGlobal/winforms/pull/42 WiseTech Global © WiseTech Global Limited. All rights reserved. README.md