MessagePumpStrategy
using System;
using System.Security;
using System.Threading;
using System.Windows.Forms;
using System.Windows.Threading;
namespace NUnit.Framework.Internal
{
internal abstract class MessagePumpStrategy
{
private sealed class NoMessagePumpStrategy : MessagePumpStrategy
{
public static readonly NoMessagePumpStrategy Instance = new NoMessagePumpStrategy();
private NoMessagePumpStrategy()
{
}
public override void WaitForCompletion(AwaitAdapter awaitable)
{
awaitable.BlockUntilCompleted();
}
}
private sealed class WindowsFormsMessagePumpStrategy : MessagePumpStrategy
{
public static readonly WindowsFormsMessagePumpStrategy Instance = new WindowsFormsMessagePumpStrategy();
private WindowsFormsMessagePumpStrategy()
{
}
[SecuritySafeCritical]
public override void WaitForCompletion(AwaitAdapter awaitable)
{
SynchronizationContext current = SynchronizationContext.Current;
if (!(current is WindowsFormsSynchronizationContext))
throw new InvalidOperationException("This strategy must only be used from a WindowsFormsSynchronizationContext.");
if (!awaitable.IsCompleted) {
current.Post(delegate(object state) {
ContinueOnSameSynchronizationContext((AwaitAdapter)state, (Action)Application.Exit);
}, awaitable);
try {
Application.Run();
} finally {
SynchronizationContext.SetSynchronizationContext(current);
}
}
}
}
private sealed class WpfMessagePumpStrategy : MessagePumpStrategy
{
public static readonly WpfMessagePumpStrategy Instance = new WpfMessagePumpStrategy();
private WpfMessagePumpStrategy()
{
}
public override void WaitForCompletion(AwaitAdapter awaitable)
{
SynchronizationContext current = SynchronizationContext.Current;
if (!(current is DispatcherSynchronizationContext))
throw new InvalidOperationException("This strategy must only be used from a DispatcherSynchronizationContext.");
if (!awaitable.IsCompleted) {
current.Post(delegate(object state) {
ContinueOnSameSynchronizationContext((AwaitAdapter)state, (Action)Dispatcher.ExitAllFrames);
}, awaitable);
Dispatcher.Run();
}
}
}
private sealed class SingleThreadedTestMessagePumpStrategy : MessagePumpStrategy
{
public static readonly SingleThreadedTestMessagePumpStrategy Instance = new SingleThreadedTestMessagePumpStrategy();
private SingleThreadedTestMessagePumpStrategy()
{
}
public override void WaitForCompletion(AwaitAdapter awaitable)
{
SingleThreadedTestSynchronizationContext context = SynchronizationContext.Current as SingleThreadedTestSynchronizationContext;
if (context == null)
throw new InvalidOperationException("This strategy must only be used from a SingleThreadedTestSynchronizationContext.");
if (!awaitable.IsCompleted) {
context.Post(delegate(object state) {
ContinueOnSameSynchronizationContext((AwaitAdapter)state, context.ShutDown);
}, awaitable);
context.Run();
}
}
}
public abstract void WaitForCompletion(AwaitAdapter awaitable);
public static MessagePumpStrategy FromCurrentSynchronizationContext()
{
SynchronizationContext current = SynchronizationContext.Current;
if (current is SingleThreadedTestSynchronizationContext)
return SingleThreadedTestMessagePumpStrategy.Instance;
if (current is WindowsFormsSynchronizationContext)
return WindowsFormsMessagePumpStrategy.Instance;
if (current is DispatcherSynchronizationContext)
return WpfMessagePumpStrategy.Instance;
return NoMessagePumpStrategy.Instance;
}
private static void ContinueOnSameSynchronizationContext(AwaitAdapter adapter, Action continuation)
{
if (adapter == null)
throw new ArgumentNullException("adapter");
if (continuation == null)
throw new ArgumentNullException("continuation");
SynchronizationContext context = SynchronizationContext.Current;
adapter.OnCompleted(delegate {
if (SynchronizationContext.Current == context)
continuation();
else
context.Post(delegate(object state) {
((Action)state)();
}, continuation);
});
}
}
}