Skip to content

Commit

Permalink
Always spawn message loop thread for SystemEvents (#53467)
Browse files Browse the repository at this point in the history
* Always spawn message loop thread for SystemEvents

* Update src/libraries/Microsoft.Win32.SystemEvents/tests/SystemEvents.InvokeOnEventsThread.cs

Co-authored-by: Jan Kotas <jkotas@microsoft.com>

Co-authored-by: Jan Kotas <jkotas@microsoft.com>
  • Loading branch information
stephentoub and jkotas committed May 30, 2021
1 parent b5c91e4 commit a961e08
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -469,33 +469,23 @@ private static void EnsureSystemEvents(bool requireHandle)
{
if (s_systemEvents == null)
{
// If we are creating system events on a thread declared as STA, then
// just share the thread.
if (!UserInteractive || Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
{
SystemEvents systemEvents = new SystemEvents();
systemEvents.Initialize();
// 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;
}
else
s_eventWindowReady = new ManualResetEvent(false);
SystemEvents systemEvents = new SystemEvents();
s_windowThread = new Thread(new ThreadStart(systemEvents.WindowThreadProc))
{
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();

// ensure this is initialized last as that will force concurrent threads calling
// this method to block until after we've initialized.
s_systemEvents = systemEvents;
}
IsBackground = true,
Name = ".NET System Events"
};
s_windowThread.Start();
s_eventWindowReady.WaitOne();

// 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)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent)-windows;net461-windows</TargetFrameworks>
<IncludeRemoteExecutor>true</IncludeRemoteExecutor>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(CommonPath)Interop\Windows\Interop.Libraries.cs"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.DotNet.RemoteExecutor;
using Xunit;
using static Interop;

Expand Down Expand Up @@ -53,5 +51,30 @@ public void InvokeOnEventsThreadRunsOnSameThreadAsOtherEvents()
invoked.Dispose();
}
}

[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoNorServerCore))]
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework)]
public void RegisterFromSTAThreadThatGoesAway_MessageStillDelivered()
{
RemoteExecutor.Invoke(() => // to ensure no one has registered for any events before
{
bool changing = false, changed = false;
// Register for the events on an STA thread that then immediately exits
var thread = new Thread(() =>
{
SystemEvents.DisplaySettingsChanging += (o, e) => changing = true;
SystemEvents.DisplaySettingsChanged += (o, e) => changed = true;
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
SendMessage(User32.WM_REFLECT + User32.WM_DISPLAYCHANGE, IntPtr.Zero, IntPtr.Zero);
Assert.True(changing);
Assert.True(changed);
});
}
}
}

0 comments on commit a961e08

Please sign in to comment.