Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libraries/Common/src/Interop/Windows/User32/Interop.Constants.cs1
-rw-r--r--src/libraries/Common/src/Interop/Windows/User32/Interop.GetMessage.cs (renamed from src/libraries/Common/src/Interop/Windows/User32/Interop.PeekMessage.cs)2
-rw-r--r--src/libraries/Common/src/Interop/Windows/User32/Interop.PostQuitMessage.cs14
-rw-r--r--src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj8
-rw-r--r--src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs56
-rw-r--r--src/libraries/Microsoft.Win32.SystemEvents/tests/Microsoft.Win32.SystemEvents.Tests.csproj1
-rw-r--r--src/libraries/Microsoft.Win32.SystemEvents/tests/ShutdownTest.cs33
7 files changed, 75 insertions, 40 deletions
diff --git a/src/libraries/Common/src/Interop/Windows/User32/Interop.Constants.cs b/src/libraries/Common/src/Interop/Windows/User32/Interop.Constants.cs
index 7a1574155a7..e1a9bc4cce2 100644
--- a/src/libraries/Common/src/Interop/Windows/User32/Interop.Constants.cs
+++ b/src/libraries/Common/src/Interop/Windows/User32/Interop.Constants.cs
@@ -198,6 +198,7 @@ internal static partial class Interop
public const int WAIT_TIMEOUT = 0x00000102;
+ public const int WM_DESTROY = 0x0002;
public const int WM_CLOSE = 0x0010;
public const int WM_QUERYENDSESSION = 0x0011;
public const int WM_QUIT = 0x0012;
diff --git a/src/libraries/Common/src/Interop/Windows/User32/Interop.PeekMessage.cs b/src/libraries/Common/src/Interop/Windows/User32/Interop.GetMessage.cs
index 45710968dba..3f4a12dfa66 100644
--- a/src/libraries/Common/src/Interop/Windows/User32/Interop.PeekMessage.cs
+++ b/src/libraries/Common/src/Interop/Windows/User32/Interop.GetMessage.cs
@@ -9,6 +9,6 @@ internal static partial class Interop
internal static partial class User32
{
[DllImport(Libraries.User32, CharSet = CharSet.Unicode, ExactSpelling = true)]
- public static extern bool PeekMessageW([In, Out] ref MSG msg, IntPtr hwnd, int msgMin, int msgMax, int remove);
+ public static extern int GetMessageW(ref MSG msg, IntPtr hwnd, int msgMin, int msgMax);
}
}
diff --git a/src/libraries/Common/src/Interop/Windows/User32/Interop.PostQuitMessage.cs b/src/libraries/Common/src/Interop/Windows/User32/Interop.PostQuitMessage.cs
new file mode 100644
index 00000000000..b7595f9dcfb
--- /dev/null
+++ b/src/libraries/Common/src/Interop/Windows/User32/Interop.PostQuitMessage.cs
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+ internal static partial class User32
+ {
+ [DllImport(Libraries.User32, CharSet = CharSet.Unicode, ExactSpelling = true)]
+ public static extern void PostQuitMessage(int exitCode);
+ }
+}
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 068e9ed7954..f529ae32889 100644
--- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj
+++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft.Win32.SystemEvents.csproj
@@ -5,6 +5,8 @@
Commonly Used Types:
Microsoft.Win32.SystemEvents</PackageDescription>
+ <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
+ <ServicingVersion>1</ServicingVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Nullable>enable</Nullable>
<TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent);netcoreapp3.1-windows;netcoreapp3.1;netstandard2.0;net461</TargetFrameworks>
@@ -35,6 +37,8 @@ Microsoft.Win32.SystemEvents</PackageDescription>
Link="Common\Interop\Windows\User32\Interop.DispatchMessage.cs" />
<Compile Include="$(CommonPath)Interop\Windows\User32\Interop.GetClassInfo.cs"
Link="Common\Interop\Windows\User32\Interop.GetClassInfo.cs" />
+ <Compile Include="$(CommonPath)Interop\Windows\User32\Interop.GetMessage.cs"
+ Link="Common\Interop\Windows\User32\Interop.GetMessage.cs" />
<Compile Include="$(CommonPath)Interop\Windows\User32\Interop.GetProcessWindowStation.cs"
Link="Common\Interop\Windows\User32\Interop.GetProcessWindowStation.cs" />
<Compile Include="$(CommonPath)Interop\Windows\User32\Interop.GetUserObjectInformation.cs"
@@ -49,10 +53,10 @@ Microsoft.Win32.SystemEvents</PackageDescription>
Link="Common\Interop\Windows\User32\Interop.MSG.cs" />
<Compile Include="$(CommonPath)Interop\Windows\User32\Interop.MsgWaitForMultipleObjectsEx.cs"
Link="Common\Interop\Windows\User32\Interop.MsgWaitForMultipleObjectsEx.cs" />
- <Compile Include="$(CommonPath)Interop\Windows\User32\Interop.PeekMessage.cs"
- Link="Common\Interop\Windows\User32\Interop.PeekMessage.cs" />
<Compile Include="$(CommonPath)Interop\Windows\User32\Interop.PostMessage.cs"
Link="Common\Interop\Windows\User32\Interop.PostMessage.cs" />
+ <Compile Include="$(CommonPath)Interop\Windows\User32\Interop.PostQuitMessage.cs"
+ Link="Common\Interop\Windows\User32\Interop.PostQuitMessage.cs" />
<Compile Include="$(CommonPath)Interop\Windows\User32\Interop.RegisterClass.cs"
Link="Common\Interop\Windows\User32\Interop.RegisterClass.cs" />
<Compile Include="$(CommonPath)Interop\Windows\User32\Interop.RegisterWindowMessage.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 2192c517f81..6e3fc69ef48 100644
--- a/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs
+++ b/src/libraries/Microsoft.Win32.SystemEvents/src/Microsoft/Win32/SystemEvents.cs
@@ -35,7 +35,6 @@ namespace Microsoft.Win32
// cross-thread marshaling
private static volatile Queue<Delegate>? s_threadCallbackList; // list of Delegates
private static volatile int s_threadCallbackMessage;
- private static volatile ManualResetEvent? s_eventThreadTerminated;
// Per-instance data that is isolated to the window thread.
private volatile IntPtr _windowHandle;
@@ -1071,7 +1070,7 @@ namespace Microsoft.Win32
private static void Shutdown()
{
- if (s_systemEvents != null && s_systemEvents._windowHandle != IntPtr.Zero)
+ if (s_systemEvents != null)
{
lock (s_procLockObject)
{
@@ -1080,17 +1079,22 @@ namespace Microsoft.Win32
// If we are using system events from another thread, request that it terminate
if (s_windowThread != null)
{
- s_eventThreadTerminated = new ManualResetEvent(false);
-
#if DEBUG
int pid;
int thread = Interop.User32.GetWindowThreadProcessId(new HandleRef(s_systemEvents, s_systemEvents._windowHandle), out pid);
Debug.Assert(thread != Interop.Kernel32.GetCurrentThreadId(), "Don't call Shutdown on the system events thread");
#endif
- Interop.User32.PostMessageW(new HandleRef(s_systemEvents, s_systemEvents._windowHandle), Interop.User32.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
- s_eventThreadTerminated.WaitOne();
- s_windowThread.Join(); // avoids an AppDomainUnloaded exception on our background thread.
+ // 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(new HandleRef(s_systemEvents, s_systemEvents._windowHandle), Interop.User32.WM_QUIT, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ s_windowThread.Join();
}
else
{
@@ -1218,6 +1222,11 @@ namespace Microsoft.Win32
OnTimerElapsed(wParam);
break;
+ case Interop.User32.WM_DESTROY:
+ Interop.User32.PostQuitMessage(0);
+ _windowHandle = IntPtr.Zero;
+ break;
+
default:
// If we received a thread execute message, then execute it.
if (msg == s_threadCallbackMessage && msg != 0)
@@ -1248,33 +1257,10 @@ namespace Microsoft.Win32
{
Interop.User32.MSG msg = default(Interop.User32.MSG);
- bool keepRunning = true;
-
- // Blocking on a GetMessage() call prevents the EE from being able to unwind
- // this thread properly (e.g. during AppDomainUnload). So, we use PeekMessage()
- // and sleep so we always block in managed code instead.
- while (keepRunning)
+ while (Interop.User32.GetMessageW(ref msg, _windowHandle, 0, 0) > 0)
{
- int ret = Interop.User32.MsgWaitForMultipleObjectsEx(0, IntPtr.Zero, 100, Interop.User32.QS_ALLINPUT, Interop.User32.MWMO_INPUTAVAILABLE);
-
- if (ret == Interop.User32.WAIT_TIMEOUT)
- {
- Thread.Sleep(1);
- }
- else
- {
- while (Interop.User32.PeekMessageW(ref msg, IntPtr.Zero, 0, 0, Interop.User32.PM_REMOVE))
- {
- if (msg.message == Interop.User32.WM_QUIT)
- {
- keepRunning = false;
- break;
- }
-
- Interop.User32.TranslateMessage(ref msg);
- Interop.User32.DispatchMessageW(ref msg);
- }
- }
+ Interop.User32.TranslateMessage(ref msg);
+ Interop.User32.DispatchMessageW(ref msg);
}
}
@@ -1293,10 +1279,6 @@ namespace Microsoft.Win32
}
Dispose();
- if (s_eventThreadTerminated != null)
- {
- s_eventThreadTerminated.Set();
- }
}
// A class that helps fire events on the right thread.
diff --git a/src/libraries/Microsoft.Win32.SystemEvents/tests/Microsoft.Win32.SystemEvents.Tests.csproj b/src/libraries/Microsoft.Win32.SystemEvents/tests/Microsoft.Win32.SystemEvents.Tests.csproj
index 83d774de464..1341ae4f701 100644
--- a/src/libraries/Microsoft.Win32.SystemEvents/tests/Microsoft.Win32.SystemEvents.Tests.csproj
+++ b/src/libraries/Microsoft.Win32.SystemEvents/tests/Microsoft.Win32.SystemEvents.Tests.csproj
@@ -23,6 +23,7 @@
<Compile Include="SystemEvents.SessionSwitch.cs" />
<Compile Include="SystemEvents.PowerMode.cs" />
<Compile Include="SystemEvents.TimeChanged.cs" />
+ <Compile Include="ShutdownTest.cs" />
<Compile Include="SystemEventsTest.cs" />
<Compile Include="SystemEvents.DisplaySettings.cs" />
<Compile Include="SystemEvents.CreateTimer.cs" />
diff --git a/src/libraries/Microsoft.Win32.SystemEvents/tests/ShutdownTest.cs b/src/libraries/Microsoft.Win32.SystemEvents/tests/ShutdownTest.cs
new file mode 100644
index 00000000000..d8012da78db
--- /dev/null
+++ b/src/libraries/Microsoft.Win32.SystemEvents/tests/ShutdownTest.cs
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// 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
+{
+ public abstract class ShutdownTest : SystemEventsTest
+ {
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoNorServerCore))]
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
+ public void ShutdownThroughRestartManager()
+ {
+ RemoteExecutor.Invoke(() =>
+ {
+ // 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();
+ }
+ }
+}