From f15fdf26b4452229a8fdeec4e9cc41660954d1c5 Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Mon, 30 Sep 2024 14:56:25 -0700 Subject: [PATCH 01/20] Add switch to enable legacy Thread.Join in SystemEvents.Shutdown and obsolete EventsThreadShutdown --- .../src/Microsoft.Win32.SystemEvents.csproj | 3 +++ .../Microsoft/Win32/LocalAppContextSwitches.cs | 17 +++++++++++++++++ .../src/Microsoft/Win32/SystemEvents.cs | 6 +++++- 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/LocalAppContextSwitches.cs diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj index b6921f386a31d..7938fdfe65a8e 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj @@ -104,6 +104,9 @@ Microsoft.Win32.SystemEvents Link="Common\Interop\Windows\WtsApi32\Interop.WTSUnRegisterSessionNotification.cs" /> + + diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/LocalAppContextSwitches.cs b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/LocalAppContextSwitches.cs new file mode 100644 index 0000000000000..be3adef3bf0bb --- /dev/null +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/LocalAppContextSwitches.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; + +namespace System; + +internal static partial class LocalAppContextSwitches +{ + private static int s_enableLegacySystemEventsShutdownThreadJoin; + + public static bool EnableLegacySystemEventsShutdownThreadJoin + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => GetCachedSwitchValue("Switch.SystemEvents.EnableLegacySystemEventsShutdownThreadJoin", ref s_enableLegacySystemEventsShutdownThreadJoin); + } +} diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs index 3067cd053bb4c..bedd57359c19d 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs @@ -130,6 +130,7 @@ public static event EventHandler? DisplaySettingsChanged /// Occurs before the thread that listens for system events is terminated. /// Delegates will be invoked on the events thread. /// + [Obsolete("Callbacks are not guaranteed to run before process exits. Use AppDomain.ProcessExit instead.")] public static event EventHandler? EventsThreadShutdown { // Really only here for GDI+ initialization and shut down @@ -1103,7 +1104,10 @@ private static void Shutdown() GC.KeepAlive(s_systemEvents); } - s_windowThread.Join(); + if (LocalAppContextSwitches.EnableLegacySystemEventsShutdownThreadJoin) + { + s_windowThread.Join(); + } } else { From 2434963f4c43402ec9092b8c43059109184aa70e Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Tue, 1 Oct 2024 10:05:57 -0700 Subject: [PATCH 02/20] code cleanup --- .../src/Microsoft/Win32/SystemEvents.cs | 87 ++++++++++--------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs index bedd57359c19d..b880e1a61c838 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs @@ -134,14 +134,8 @@ public static event EventHandler? DisplaySettingsChanged public static event EventHandler? EventsThreadShutdown { // Really only here for GDI+ initialization and shut down - add - { - AddEventHandler(s_onEventsThreadShutdownEvent, value); - } - remove - { - RemoveEventHandler(s_onEventsThreadShutdownEvent, value); - } + add => AddEventHandler(s_onEventsThreadShutdownEvent, value); + remove => RemoveEventHandler(s_onEventsThreadShutdownEvent, value); } /// @@ -1076,46 +1070,59 @@ private static void RemoveEventHandler(object key, Delegate? value) private static void Shutdown() { - if (s_systemEvents != null) + if (s_systemEvents is null) { - lock (s_procLockObject) + return; + } + + lock (s_procLockObject) + { + if (s_systemEvents is null) + { + return; + } + + // If we are using system events from another thread, request that it terminate + if (s_windowThread is not null) { - if (s_systemEvents != null) - { - // If we are using system events from another thread, request that it terminate - if (s_windowThread != null) - { #if DEBUG - unsafe - { - int pid; - int thread = Interop.User32.GetWindowThreadProcessId(s_systemEvents._windowHandle, &pid); - Debug.Assert(thread != Interop.Kernel32.GetCurrentThreadId(), "Don't call Shutdown on the system events thread"); + unsafe + { + int pid; + int thread = Interop.User32.GetWindowThreadProcessId(s_systemEvents._windowHandle, &pid); + Debug.Assert(thread != Interop.Kernel32.GetCurrentThreadId(), "Don't call Shutdown on the system events thread"); - } + } #endif - // The handle could be valid, Zero or invalid depending on the state of the thread - // that is processing the messages. We optimistically expect it to be valid to - // notify the thread to shutdown. The Zero or invalid values should be present - // only when the thread is already shutting down due to external factors. - if (s_systemEvents._windowHandle != IntPtr.Zero) - { - Interop.User32.PostMessageW(s_systemEvents._windowHandle, Interop.User32.WM_QUIT, IntPtr.Zero, IntPtr.Zero); - GC.KeepAlive(s_systemEvents); - } + // The handle could be valid, Zero or invalid depending on the state of the thread + // that is processing the messages. We optimistically expect it to be valid to + // notify the thread to shutdown. The Zero or invalid values should be present + // only when the thread is already shutting down due to external factors. + if (s_systemEvents._windowHandle != IntPtr.Zero) + { + Interop.User32.PostMessageW(s_systemEvents._windowHandle, Interop.User32.WM_QUIT, IntPtr.Zero, IntPtr.Zero); + GC.KeepAlive(s_systemEvents); + } - if (LocalAppContextSwitches.EnableLegacySystemEventsShutdownThreadJoin) - { - s_windowThread.Join(); - } - } - else - { - s_systemEvents.Dispose(); - s_systemEvents = null; - } + // When the main thread kicks off shutdown, the Finalizer thread will raise a ProcessExit event, + // which will callback to here waiting for this method to finish. + // This occurs before AppDomain.IsFinalizingForUnload or Environment.HasShutdownStarted is set to true. + // Because of this, any code that needs a response from the main thread will not know main thread will not respond. + // This can cause synchronous callbacks to deadlock. For example, in https://github.com/dotnet/winforms/issues/11944, + // WindowsFormsSynchronizationContext will block the SystemEvents thread to wait for tasks to complete on the main thread. + // It cannot see that main thread is trying to shut down, but is stuck waiting for the Finalizer thread to finish, + // which is waiting for SystemEvents thread to finish. Avoid blocking the Finalizer thread on shutdown by skipping + // waiting for the SystemEvents thread to finish. + if (LocalAppContextSwitches.EnableLegacySystemEventsShutdownThreadJoin) + { + s_windowThread.Join(); } } + else + { + s_systemEvents.Dispose(); + s_systemEvents = null; + } } } From 52fc6ed8fc4abe02bf2e61c9753435df70f87503 Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Wed, 2 Oct 2024 09:39:53 -0700 Subject: [PATCH 03/20] Add regression test --- .../tests/ShutdownTest.cs | 49 ++++++++++++------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/libraries/Microsoft.Win32.SystemEvents/tests/ShutdownTest.cs b/src/libraries/Microsoft.Win32.SystemEvents/tests/ShutdownTest.cs index d8012da78db70..4f1550bb396ae 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/tests/ShutdownTest.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/tests/ShutdownTest.cs @@ -2,32 +2,45 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Threading; using Microsoft.DotNet.RemoteExecutor; using Xunit; using static Interop; -namespace Microsoft.Win32.SystemEventsTests +namespace Microsoft.Win32.SystemEventsTests; + +public class ShutdownTest : SystemEventsTest { - public abstract class ShutdownTest : SystemEventsTest + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoNorServerCore))] + [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] + public void ShutdownThroughRestartManager() { - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoNorServerCore))] - [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] - public void ShutdownThroughRestartManager() + RemoteExecutor.Invoke(() => { - RemoteExecutor.Invoke(() => - { - // Register any event to ensure that SystemEvents get initialized - SystemEvents.TimeChanged += (o, e) => { }; + // Register any event to ensure that SystemEvents get initialized + SystemEvents.TimeChanged += (o, e) => { }; + + // Fake Restart Manager behavior by sending external WM_CLOSE message + SendMessage(Interop.User32.WM_CLOSE, IntPtr.Zero, IntPtr.Zero); + + // Emulate calling the Shutdown event + var shutdownMethod = typeof(SystemEvents).GetMethod("Shutdown", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic, null, new Type[0], null); + Assert.NotNull(shutdownMethod); + shutdownMethod.Invoke(null, null); + }).Dispose(); + } - // Fake Restart Manager behavior by sending external WM_CLOSE message - SendMessage(Interop.User32.WM_CLOSE, IntPtr.Zero, IntPtr.Zero); + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoNorServerCore))] + [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] + public void ShutdownSuccessDespiteThreadBlock() + { + AppContext.TryGetSwitch("Switch.SystemEvents.EnableLegacySystemEventsShutdownThreadJoin", out bool isEnabled); + Assert.False(isEnabled); - // Emulate calling the Shutdown event - var shutdownMethod = typeof(SystemEvents).GetMethod("Shutdown", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic, null, new Type[0], null); - Assert.NotNull(shutdownMethod); - shutdownMethod.Invoke(null, null); - }).Dispose(); - } + RemoteExecutor.Invoke(() => + { + // Block the SystemEvents thread. Regression test for https://github.com/dotnet/winforms/issues/11944 + SystemEvents.UserPreferenceChanged += (o, e) => { while (true) { } }; + SendMessage(User32.WM_SETTINGCHANGE, IntPtr.Zero, IntPtr.Zero); + }).Dispose(); } } From 13d2c4f163c5fec7981317936c6dfa4cb71a6223 Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Wed, 2 Oct 2024 10:08:23 -0700 Subject: [PATCH 04/20] Call PostQuitMessage instead of PostMessage(WM_QUIT) --- .../src/Microsoft/Win32/SystemEvents.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs index b880e1a61c838..c029653c53b16 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs @@ -1100,7 +1100,7 @@ private static void Shutdown() // only when the thread is already shutting down due to external factors. if (s_systemEvents._windowHandle != IntPtr.Zero) { - Interop.User32.PostMessageW(s_systemEvents._windowHandle, Interop.User32.WM_QUIT, IntPtr.Zero, IntPtr.Zero); + Interop.User32.PostQuitMessage(0); GC.KeepAlive(s_systemEvents); } From dc8813ceb6dd49c611bad08d1c857df0728d64e8 Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Wed, 2 Oct 2024 14:38:39 -0700 Subject: [PATCH 05/20] Remove compat switch and address PR feedback --- .../src/Microsoft.Win32.SystemEvents.csproj | 3 --- .../Microsoft/Win32/LocalAppContextSwitches.cs | 17 ----------------- .../src/Microsoft/Win32/SystemEvents.cs | 17 ++++++----------- .../tests/ShutdownTest.cs | 3 --- 4 files changed, 6 insertions(+), 34 deletions(-) delete mode 100644 src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/LocalAppContextSwitches.cs diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj index 7938fdfe65a8e..b6921f386a31d 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj @@ -104,9 +104,6 @@ Microsoft.Win32.SystemEvents Link="Common\Interop\Windows\WtsApi32\Interop.WTSUnRegisterSessionNotification.cs" /> - - diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/LocalAppContextSwitches.cs b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/LocalAppContextSwitches.cs deleted file mode 100644 index be3adef3bf0bb..0000000000000 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/LocalAppContextSwitches.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.CompilerServices; - -namespace System; - -internal static partial class LocalAppContextSwitches -{ - private static int s_enableLegacySystemEventsShutdownThreadJoin; - - public static bool EnableLegacySystemEventsShutdownThreadJoin - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => GetCachedSwitchValue("Switch.SystemEvents.EnableLegacySystemEventsShutdownThreadJoin", ref s_enableLegacySystemEventsShutdownThreadJoin); - } -} diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs index c029653c53b16..84f8862bc43bc 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs @@ -1101,22 +1101,17 @@ private static void Shutdown() if (s_systemEvents._windowHandle != IntPtr.Zero) { Interop.User32.PostQuitMessage(0); - GC.KeepAlive(s_systemEvents); } + // Don't wait for the SystemEvents thread to finish to avoid blocking the Finalizer thread. // When the main thread kicks off shutdown, the Finalizer thread will raise a ProcessExit event, // which will callback to here waiting for this method to finish. // This occurs before AppDomain.IsFinalizingForUnload or Environment.HasShutdownStarted is set to true. - // Because of this, any code that needs a response from the main thread will not know main thread will not respond. - // This can cause synchronous callbacks to deadlock. For example, in https://github.com/dotnet/winforms/issues/11944, - // WindowsFormsSynchronizationContext will block the SystemEvents thread to wait for tasks to complete on the main thread. - // It cannot see that main thread is trying to shut down, but is stuck waiting for the Finalizer thread to finish, - // which is waiting for SystemEvents thread to finish. Avoid blocking the Finalizer thread on shutdown by skipping - // waiting for the SystemEvents thread to finish. - if (LocalAppContextSwitches.EnableLegacySystemEventsShutdownThreadJoin) - { - s_windowThread.Join(); - } + // Because of this, any code that needs a response from the main thread will not know main thread will not respond + // since it is in the middle of shutdown. This can cause synchronous callbacks to deadlock. + // For example, in https://github.com/dotnet/winforms/issues/11944, WindowsFormsSynchronizationContext will block the + // SystemEvents thread to wait for tasks to complete on the main thread. It cannot see that main thread is trying to + // shut down, but is stuck waiting for the Finalizer thread to finish, which is waiting for SystemEvents thread to finish. } else { diff --git a/src/libraries/Microsoft.Win32.SystemEvents/tests/ShutdownTest.cs b/src/libraries/Microsoft.Win32.SystemEvents/tests/ShutdownTest.cs index 4f1550bb396ae..fa2e9f8a67286 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/tests/ShutdownTest.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/tests/ShutdownTest.cs @@ -33,9 +33,6 @@ public void ShutdownThroughRestartManager() [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)] public void ShutdownSuccessDespiteThreadBlock() { - AppContext.TryGetSwitch("Switch.SystemEvents.EnableLegacySystemEventsShutdownThreadJoin", out bool isEnabled); - Assert.False(isEnabled); - RemoteExecutor.Invoke(() => { // Block the SystemEvents thread. Regression test for https://github.com/dotnet/winforms/issues/11944 From 7694fa7ed3f3e5fd8193cc2e8e3a44fdc7033cca Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Wed, 2 Oct 2024 14:41:27 -0700 Subject: [PATCH 06/20] rebuild with /p:ApiCompatGenerateSuppressionFile=true --- .../src/CompatibilitySuppressions.xml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml b/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml index 038640c945743..88aed7ad003f4 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml @@ -7,4 +7,22 @@ lib/netstandard2.0/Microsoft.Win32.SystemEvents.dll lib/net462/Microsoft.Win32.SystemEvents.dll + + CP0016 + E:Microsoft.Win32.SystemEvents.EventsThreadShutdown:[T:System.ObsoleteAttribute] + ref/net10.0/Microsoft.Win32.SystemEvents.dll + runtimes/win/lib/net10.0/Microsoft.Win32.SystemEvents.dll + + + CP0016 + E:Microsoft.Win32.SystemEvents.EventsThreadShutdown:[T:System.ObsoleteAttribute] + ref/net8.0/Microsoft.Win32.SystemEvents.dll + runtimes/win/lib/net8.0/Microsoft.Win32.SystemEvents.dll + + + CP0016 + E:Microsoft.Win32.SystemEvents.EventsThreadShutdown:[T:System.ObsoleteAttribute] + ref/net9.0/Microsoft.Win32.SystemEvents.dll + runtimes/win/lib/net9.0/Microsoft.Win32.SystemEvents.dll + \ No newline at end of file From 13a6d3725bb28f40c579ea3803eb7d511681a372 Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Thu, 3 Oct 2024 10:39:59 -0700 Subject: [PATCH 07/20] Call PostQuitMessage on SystemEvents thread --- .../src/Microsoft/Win32/SystemEvents.cs | 68 ++++++++++--------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs index 84f8862bc43bc..2f9233f6dcaaa 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs @@ -459,39 +459,43 @@ private void Dispose() /// private static void EnsureSystemEvents(bool requireHandle) { - if (s_systemEvents == null) + if (s_systemEvents is not null) { - lock (s_procLockObject) + return; + } + + lock (s_procLockObject) + { + if (s_systemEvents is not null) { - if (s_systemEvents == null) - { - // Create a new pumping thread. We always create one even if the current thread - // is STA, as there are no guarantees this thread will pump nor still be alive - // for the desired duration. + return; + } - s_eventWindowReady = new ManualResetEvent(false); - SystemEvents systemEvents = new SystemEvents(); - s_windowThread = new Thread(new ThreadStart(systemEvents.WindowThreadProc)) - { - IsBackground = true, - Name = ".NET System Events" - }; - s_windowThread.Start(); - s_eventWindowReady.WaitOne(); + // Create a new pumping thread. We always create one even if the current thread + // is STA, as there are no guarantees this thread will pump nor still be alive + // for the desired duration. - // ensure this is initialized last as that will force concurrent threads calling - // this method to block until after we've initialized. - s_systemEvents = systemEvents; + s_eventWindowReady = new ManualResetEvent(false); + SystemEvents systemEvents = new SystemEvents(); + s_windowThread = new Thread(new ThreadStart(systemEvents.WindowThreadProc)) + { + IsBackground = true, + Name = ".NET System Events" + }; + s_windowThread.Start(); + s_eventWindowReady.WaitOne(); - if (requireHandle && s_systemEvents._windowHandle == IntPtr.Zero) - { - // In theory, it's not the end of the world that - // we don't get system events. Unfortunately, the main reason windowHandle == 0 - // is CreateWindowEx failed for mysterious reasons, and when that happens, - // subsequent (and more important) CreateWindowEx calls also fail. - throw new ExternalException(SR.ErrorCreateSystemEvents); - } - } + // Ensure this is initialized last as that will force concurrent threads calling + // this method to block until after we've initialized. + s_systemEvents = systemEvents; + + if (requireHandle && s_systemEvents._windowHandle == IntPtr.Zero) + { + // In theory, it's not the end of the world that + // we don't get system events. Unfortunately, the main reason windowHandle == 0 + // is CreateWindowEx failed for mysterious reasons, and when that happens, + // subsequent (and more important) CreateWindowEx calls also fail. + throw new ExternalException(SR.ErrorCreateSystemEvents); } } } @@ -754,16 +758,15 @@ public static void InvokeOnEventsThread(Delegate method) { int pid; int thread = Interop.User32.GetWindowThreadProcessId(s_systemEvents!._windowHandle, &pid); - GC.KeepAlive(s_systemEvents); Debug.Assert(s_windowThread == null || thread != Interop.Kernel32.GetCurrentThreadId(), "Don't call MarshaledInvoke on the system events thread"); } #endif - if (s_threadCallbackList == null) + if (s_threadCallbackList is null) { lock (s_eventLockObject) { - if (s_threadCallbackList == null) + if (s_threadCallbackList is null) { s_threadCallbackMessage = Interop.User32.RegisterWindowMessageW("SystemEventsThreadCallbackMessage"); s_threadCallbackList = new Queue(); @@ -779,7 +782,6 @@ public static void InvokeOnEventsThread(Delegate method) } Interop.User32.PostMessageW(s_systemEvents!._windowHandle, s_threadCallbackMessage, IntPtr.Zero, IntPtr.Zero); - GC.KeepAlive(s_systemEvents); } /// @@ -1100,7 +1102,7 @@ private static void Shutdown() // only when the thread is already shutting down due to external factors. if (s_systemEvents._windowHandle != IntPtr.Zero) { - Interop.User32.PostQuitMessage(0); + InvokeOnEventsThread(() => Interop.User32.PostQuitMessage(0)); } // Don't wait for the SystemEvents thread to finish to avoid blocking the Finalizer thread. From 25a247bd5b2ae18d052c4b4ffa517457e594f934 Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Thu, 3 Oct 2024 10:40:31 -0700 Subject: [PATCH 08/20] Try removing left/right on compatbilitysuppression.xml --- .../src/CompatibilitySuppressions.xml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml b/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml index 88aed7ad003f4..3a544153b835b 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml @@ -10,19 +10,13 @@ CP0016 E:Microsoft.Win32.SystemEvents.EventsThreadShutdown:[T:System.ObsoleteAttribute] - ref/net10.0/Microsoft.Win32.SystemEvents.dll - runtimes/win/lib/net10.0/Microsoft.Win32.SystemEvents.dll CP0016 E:Microsoft.Win32.SystemEvents.EventsThreadShutdown:[T:System.ObsoleteAttribute] - ref/net8.0/Microsoft.Win32.SystemEvents.dll - runtimes/win/lib/net8.0/Microsoft.Win32.SystemEvents.dll CP0016 E:Microsoft.Win32.SystemEvents.EventsThreadShutdown:[T:System.ObsoleteAttribute] - ref/net9.0/Microsoft.Win32.SystemEvents.dll - runtimes/win/lib/net9.0/Microsoft.Win32.SystemEvents.dll - \ No newline at end of file + From 428aa3b2734e381bbd110abfd01cb9b273f16390 Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Mon, 7 Oct 2024 09:36:43 -0700 Subject: [PATCH 09/20] Obsolete EventsThreadShutdown --- docs/project/list-of-diagnostics.md | 1 + src/libraries/Common/src/System/Obsoletions.cs | 3 +++ .../src/Microsoft.Win32.SystemEvents.csproj | 2 ++ .../src/Microsoft/Win32/SystemEvents.cs | 2 +- 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/project/list-of-diagnostics.md b/docs/project/list-of-diagnostics.md index 79a3af43ed29c..c3ba987dd0198 100644 --- a/docs/project/list-of-diagnostics.md +++ b/docs/project/list-of-diagnostics.md @@ -113,6 +113,7 @@ The PR that reveals the implementation of the ` Link="Common\Interop\Windows\WtsApi32\Interop.WTSUnRegisterSessionNotification.cs" /> + diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs index 2f9233f6dcaaa..1f4fe8443ec06 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs @@ -130,7 +130,7 @@ public static event EventHandler? DisplaySettingsChanged /// Occurs before the thread that listens for system events is terminated. /// Delegates will be invoked on the events thread. /// - [Obsolete("Callbacks are not guaranteed to run before process exits. Use AppDomain.ProcessExit instead.")] + [Obsolete(Obsoletions.SystemEventsEventsThreadShutdownMessage, DiagnosticId = Obsoletions.SystemEventsEventsThreadShutdownDiagId, UrlFormat = Obsoletions.SharedUrlFormat)] public static event EventHandler? EventsThreadShutdown { // Really only here for GDI+ initialization and shut down From c4817f242babb43e03425d14fe1b03068f9d9565 Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Mon, 7 Oct 2024 10:45:06 -0700 Subject: [PATCH 10/20] Remove shutdown handling to make behavior deterministic --- .../src/Microsoft/Win32/SystemEvents.cs | 73 ++----------------- .../tests/ShutdownTest.cs | 5 -- 2 files changed, 5 insertions(+), 73 deletions(-) diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs index 1f4fe8443ec06..786ab50e0742b 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs @@ -693,8 +693,6 @@ private unsafe void Initialize() hInstance, IntPtr.Zero); } } - - AppDomain.CurrentDomain.ProcessExit += new EventHandler(Shutdown); } /// @@ -1070,67 +1068,6 @@ private static void RemoveEventHandler(object key, Delegate? value) } } - private static void Shutdown() - { - if (s_systemEvents is null) - { - return; - } - - lock (s_procLockObject) - { - if (s_systemEvents is null) - { - return; - } - - // If we are using system events from another thread, request that it terminate - if (s_windowThread is not null) - { -#if DEBUG - unsafe - { - int pid; - int thread = Interop.User32.GetWindowThreadProcessId(s_systemEvents._windowHandle, &pid); - Debug.Assert(thread != Interop.Kernel32.GetCurrentThreadId(), "Don't call Shutdown on the system events thread"); - - } -#endif - // The handle could be valid, Zero or invalid depending on the state of the thread - // that is processing the messages. We optimistically expect it to be valid to - // notify the thread to shutdown. The Zero or invalid values should be present - // only when the thread is already shutting down due to external factors. - if (s_systemEvents._windowHandle != IntPtr.Zero) - { - InvokeOnEventsThread(() => Interop.User32.PostQuitMessage(0)); - } - - // Don't wait for the SystemEvents thread to finish to avoid blocking the Finalizer thread. - // When the main thread kicks off shutdown, the Finalizer thread will raise a ProcessExit event, - // which will callback to here waiting for this method to finish. - // This occurs before AppDomain.IsFinalizingForUnload or Environment.HasShutdownStarted is set to true. - // Because of this, any code that needs a response from the main thread will not know main thread will not respond - // since it is in the middle of shutdown. This can cause synchronous callbacks to deadlock. - // For example, in https://github.com/dotnet/winforms/issues/11944, WindowsFormsSynchronizationContext will block the - // SystemEvents thread to wait for tasks to complete on the main thread. It cannot see that main thread is trying to - // shut down, but is stuck waiting for the Finalizer thread to finish, which is waiting for SystemEvents thread to finish. - } - else - { - s_systemEvents.Dispose(); - s_systemEvents = null; - } - } - } - -#if FEATURE_CER - [PrePrepareMethod] -#endif - private static void Shutdown(object? sender, EventArgs e) - { - Shutdown(); - } - /// /// A standard Win32 window proc for our broadcast window. /// @@ -1258,8 +1195,8 @@ private IntPtr WindowProc(IntPtr hWnd, int msg, nint wParam, nint lParam) } /// - /// This is the method that runs our window thread. This method - /// creates a window and spins up a message loop. The window + /// This is the method that runs our window thread. This method + /// creates a window and spins up a message loop. The window /// is made visible with a size of 0, 0, so that it will trap /// global broadcast messages. /// @@ -1272,7 +1209,7 @@ private void WindowThreadProc() if (_windowHandle != IntPtr.Zero) { - Interop.User32.MSG msg = default(Interop.User32.MSG); + Interop.User32.MSG msg = default; while (Interop.User32.GetMessageW(ref msg, _windowHandle, 0, 0) > 0) { @@ -1285,11 +1222,11 @@ private void WindowThreadProc() } catch (Exception e) { - // In case something very very wrong happend during the creation action. + // In case something very very wrong happened during the creation action. // This will unblock the calling thread. s_eventWindowReady!.Set(); - if (!((e is ThreadInterruptedException) || (e is ThreadAbortException))) + if (e is not (ThreadInterruptedException or ThreadAbortException)) { Debug.Fail("Unexpected thread exception in system events window thread proc", e.ToString()); } diff --git a/src/libraries/Microsoft.Win32.SystemEvents/tests/ShutdownTest.cs b/src/libraries/Microsoft.Win32.SystemEvents/tests/ShutdownTest.cs index fa2e9f8a67286..f2febc7942398 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/tests/ShutdownTest.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/tests/ShutdownTest.cs @@ -21,11 +21,6 @@ public void ShutdownThroughRestartManager() // Fake Restart Manager behavior by sending external WM_CLOSE message SendMessage(Interop.User32.WM_CLOSE, IntPtr.Zero, IntPtr.Zero); - - // Emulate calling the Shutdown event - var shutdownMethod = typeof(SystemEvents).GetMethod("Shutdown", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic, null, new Type[0], null); - Assert.NotNull(shutdownMethod); - shutdownMethod.Invoke(null, null); }).Dispose(); } From b11670eaeeeaeb58da9a34bb98807ad358b33526 Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Tue, 8 Oct 2024 08:54:55 -0700 Subject: [PATCH 11/20] Adjust obsolete message Co-authored-by: Jan Kotas --- docs/project/list-of-diagnostics.md | 2 +- src/libraries/Common/src/System/Obsoletions.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/project/list-of-diagnostics.md b/docs/project/list-of-diagnostics.md index c3ba987dd0198..2da7cb8ce6672 100644 --- a/docs/project/list-of-diagnostics.md +++ b/docs/project/list-of-diagnostics.md @@ -113,7 +113,7 @@ The PR that reveals the implementation of the ` Date: Thu, 24 Oct 2024 10:13:56 -0700 Subject: [PATCH 12/20] Add obsoletion to refs --- docs/project/list-of-diagnostics.md | 2 +- src/libraries/Common/src/System/Obsoletions.cs | 2 +- .../ref/Microsoft.Win32.SystemEvents.cs | 1 + .../ref/Microsoft.Win32.SystemEvents.csproj | 1 + .../src/CompatibilitySuppressions.xml | 14 ++++++++++---- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/docs/project/list-of-diagnostics.md b/docs/project/list-of-diagnostics.md index 2da7cb8ce6672..7c4927642b07a 100644 --- a/docs/project/list-of-diagnostics.md +++ b/docs/project/list-of-diagnostics.md @@ -113,7 +113,7 @@ The PR that reveals the implementation of the ` + \ No newline at end of file diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml b/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml index 3a544153b835b..2dbbb47cd5992 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml @@ -8,15 +8,21 @@ lib/net462/Microsoft.Win32.SystemEvents.dll - CP0016 + CP0015 E:Microsoft.Win32.SystemEvents.EventsThreadShutdown:[T:System.ObsoleteAttribute] + ref/net10.0/Microsoft.Win32.SystemEvents.dll + runtimes/win/lib/net10.0/Microsoft.Win32.SystemEvents.dll - CP0016 + CP0015 E:Microsoft.Win32.SystemEvents.EventsThreadShutdown:[T:System.ObsoleteAttribute] + ref/net8.0/Microsoft.Win32.SystemEvents.dll + runtimes/win/lib/net8.0/Microsoft.Win32.SystemEvents.dll - CP0016 + CP0015 E:Microsoft.Win32.SystemEvents.EventsThreadShutdown:[T:System.ObsoleteAttribute] + ref/net9.0/Microsoft.Win32.SystemEvents.dll + runtimes/win/lib/net9.0/Microsoft.Win32.SystemEvents.dll - + \ No newline at end of file From 46354205fc3473bd81f9cc4e9566467f690f618a Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Thu, 24 Oct 2024 11:50:34 -0700 Subject: [PATCH 13/20] Set IncludeInternalObsoleteAttribute in ref project --- .../ref/Microsoft.Win32.SystemEvents.cs | 4 +++- .../ref/Microsoft.Win32.SystemEvents.csproj | 2 +- .../src/CompatibilitySuppressions.xml | 20 +------------------ 3 files changed, 5 insertions(+), 21 deletions(-) diff --git a/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.cs b/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.cs index 050968412a308..88b38bfb61428 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.cs @@ -4,6 +4,8 @@ // Changes to this file must follow the https://aka.ms/api-review process. // ------------------------------------------------------------------------------ +using System; + namespace Microsoft.Win32 { public partial class PowerModeChangedEventArgs : System.EventArgs @@ -59,7 +61,7 @@ public sealed partial class SystemEvents internal SystemEvents() { } public static event System.EventHandler? DisplaySettingsChanged { add { } remove { } } public static event System.EventHandler? DisplaySettingsChanging { add { } remove { } } - [System.Obsolete("SystemEvents.EventsThreadShutdown callbacks are not run before process exits. Use AppDomain.ProcessExit instead.")] + [Obsolete(Obsoletions.SystemEventsEventsThreadShutdownMessage, DiagnosticId = Obsoletions.SystemEventsEventsThreadShutdownDiagId, UrlFormat = Obsoletions.SharedUrlFormat)] public static event System.EventHandler? EventsThreadShutdown { add { } remove { } } public static event System.EventHandler? InstalledFontsChanged { add { } remove { } } [System.ComponentModel.BrowsableAttribute(false)] diff --git a/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj b/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj index 9f0c84882c9ce..fa337d8f62393 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj +++ b/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj @@ -1,11 +1,11 @@ $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) + true - \ No newline at end of file diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml b/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml index 2dbbb47cd5992..4b45bb7dd0e32 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml @@ -7,22 +7,4 @@ lib/netstandard2.0/Microsoft.Win32.SystemEvents.dll lib/net462/Microsoft.Win32.SystemEvents.dll - - CP0015 - E:Microsoft.Win32.SystemEvents.EventsThreadShutdown:[T:System.ObsoleteAttribute] - ref/net10.0/Microsoft.Win32.SystemEvents.dll - runtimes/win/lib/net10.0/Microsoft.Win32.SystemEvents.dll - - - CP0015 - E:Microsoft.Win32.SystemEvents.EventsThreadShutdown:[T:System.ObsoleteAttribute] - ref/net8.0/Microsoft.Win32.SystemEvents.dll - runtimes/win/lib/net8.0/Microsoft.Win32.SystemEvents.dll - - - CP0015 - E:Microsoft.Win32.SystemEvents.EventsThreadShutdown:[T:System.ObsoleteAttribute] - ref/net9.0/Microsoft.Win32.SystemEvents.dll - runtimes/win/lib/net9.0/Microsoft.Win32.SystemEvents.dll - - \ No newline at end of file + From 134aca81a519aa6ca7c42b29272be7d67e95b2ae Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Thu, 24 Oct 2024 13:24:31 -0700 Subject: [PATCH 14/20] re-include Obsoletions.cs in ref project --- .../ref/Microsoft.Win32.SystemEvents.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj b/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj index fa337d8f62393..904ff353366da 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj +++ b/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj @@ -7,5 +7,6 @@ + \ No newline at end of file From aeb1008aeb52f25a68c93af23ee723df89c7e4dc Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Mon, 28 Oct 2024 10:43:32 -0700 Subject: [PATCH 15/20] revert 134aca8 and hardcode obsoletion --- .../ref/Microsoft.Win32.SystemEvents.cs | 4 +--- .../ref/Microsoft.Win32.SystemEvents.csproj | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.cs b/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.cs index 88b38bfb61428..46e1ab94247f0 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.cs @@ -4,8 +4,6 @@ // Changes to this file must follow the https://aka.ms/api-review process. // ------------------------------------------------------------------------------ -using System; - namespace Microsoft.Win32 { public partial class PowerModeChangedEventArgs : System.EventArgs @@ -61,7 +59,7 @@ public sealed partial class SystemEvents internal SystemEvents() { } public static event System.EventHandler? DisplaySettingsChanged { add { } remove { } } public static event System.EventHandler? DisplaySettingsChanging { add { } remove { } } - [Obsolete(Obsoletions.SystemEventsEventsThreadShutdownMessage, DiagnosticId = Obsoletions.SystemEventsEventsThreadShutdownDiagId, UrlFormat = Obsoletions.SharedUrlFormat)] + [System.Obsolete("SystemEvents.EventsThreadShutdown callbacks are not run before process exits. Use AppDomain.ProcessExit instead.", DiagnosticId = "SYSLIB0059", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public static event System.EventHandler? EventsThreadShutdown { add { } remove { } } public static event System.EventHandler? InstalledFontsChanged { add { } remove { } } [System.ComponentModel.BrowsableAttribute(false)] diff --git a/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj b/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj index 904ff353366da..fa337d8f62393 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj +++ b/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.csproj @@ -7,6 +7,5 @@ - \ No newline at end of file From f70c8b6bc6a50e6cccf32af16c77fb3c1ee1be30 Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Mon, 28 Oct 2024 11:38:00 -0700 Subject: [PATCH 16/20] Add IncludeInternalObsoleteAttribute to System.Events project --- .../src/Microsoft.Win32.SystemEvents.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj index 52c4e4bcda644..411c1132b65ca 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj @@ -6,6 +6,7 @@ true false true + true Provides access to Windows system event notifications. Commonly Used Types: From 452146d76bce8cdf69223cc541104c3504fdc7da Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Mon, 28 Oct 2024 11:43:04 -0700 Subject: [PATCH 17/20] remove Obsoletions.cs from compile include --- .../src/Microsoft.Win32.SystemEvents.csproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj index 411c1132b65ca..77818c7d8cc3a 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj @@ -105,8 +105,6 @@ Microsoft.Win32.SystemEvents Link="Common\Interop\Windows\WtsApi32\Interop.WTSUnRegisterSessionNotification.cs" /> - From 787aa6a4eaa70f8df4a4009059e2004f117217f6 Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Mon, 28 Oct 2024 12:28:47 -0700 Subject: [PATCH 18/20] Revert "remove Obsoletions.cs from compile include" This reverts commit 452146d76bce8cdf69223cc541104c3504fdc7da. --- .../src/Microsoft.Win32.SystemEvents.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj index 77818c7d8cc3a..411c1132b65ca 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj @@ -105,6 +105,8 @@ Microsoft.Win32.SystemEvents Link="Common\Interop\Windows\WtsApi32\Interop.WTSUnRegisterSessionNotification.cs" /> + From 5a28279a172badae2b0cd270ed2bf51ae3e6be22 Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Fri, 8 Nov 2024 13:05:26 +0100 Subject: [PATCH 19/20] Update suppression file --- .../ref/Microsoft.Win32.SystemEvents.cs | 2 +- .../src/CompatibilitySuppressions.xml | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.cs b/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.cs index 46e1ab94247f0..a94a24bea5724 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.cs +++ b/src/libraries/Microsoft.Win32.SystemEvents/ref/Microsoft.Win32.SystemEvents.cs @@ -59,7 +59,7 @@ public sealed partial class SystemEvents internal SystemEvents() { } public static event System.EventHandler? DisplaySettingsChanged { add { } remove { } } public static event System.EventHandler? DisplaySettingsChanging { add { } remove { } } - [System.Obsolete("SystemEvents.EventsThreadShutdown callbacks are not run before process exits. Use AppDomain.ProcessExit instead.", DiagnosticId = "SYSLIB0059", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] + [System.ObsoleteAttribute("SystemEvents.EventsThreadShutdown callbacks are not run before process exits. Use AppDomain.ProcessExit instead.", DiagnosticId = "SYSLIB0059", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] public static event System.EventHandler? EventsThreadShutdown { add { } remove { } } public static event System.EventHandler? InstalledFontsChanged { add { } remove { } } [System.ComponentModel.BrowsableAttribute(false)] diff --git a/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml b/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml index 4b45bb7dd0e32..c12a83ef6de8a 100644 --- a/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml +++ b/src/libraries/Microsoft.Win32.SystemEvents/src/CompatibilitySuppressions.xml @@ -1,10 +1,17 @@  + + CP0014 + E:Microsoft.Win32.SystemEvents.LowMemory:[T:System.ObsoleteAttribute] + lib/netstandard2.0/Microsoft.Win32.SystemEvents.dll + lib/netstandard2.0/Microsoft.Win32.SystemEvents.dll + true + CP0015 E:Microsoft.Win32.SystemEvents.LowMemory:[T:System.ObsoleteAttribute] lib/netstandard2.0/Microsoft.Win32.SystemEvents.dll lib/net462/Microsoft.Win32.SystemEvents.dll - + \ No newline at end of file From 92f78ef170426d5f9dd79e45764f08b4bd38dce6 Mon Sep 17 00:00:00 2001 From: Loni Tra Date: Fri, 8 Nov 2024 09:58:26 -0800 Subject: [PATCH 20/20] Update obsolete message Co-authored-by: Stephen Toub --- docs/project/list-of-diagnostics.md | 2 +- src/libraries/Common/src/System/Obsoletions.cs | 2 +- .../ref/Microsoft.Win32.SystemEvents.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/project/list-of-diagnostics.md b/docs/project/list-of-diagnostics.md index cf0d7c0b30b31..0e3f10d2df6c3 100644 --- a/docs/project/list-of-diagnostics.md +++ b/docs/project/list-of-diagnostics.md @@ -113,7 +113,7 @@ The PR that reveals the implementation of the `