mirror of
https://github.com/soukoku/ntwain.git
synced 2026-02-25 13:04:07 +08:00
Updated with SynchronizationContext.
This commit is contained in:
@@ -1,9 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using System.Text;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Windows.Win32;
|
using Windows.Win32;
|
||||||
using Windows.Win32.Foundation;
|
using Windows.Win32.Foundation;
|
||||||
using Windows.Win32.Graphics.Gdi;
|
using Windows.Win32.Graphics.Gdi;
|
||||||
@@ -11,6 +9,7 @@ using Windows.Win32.UI.WindowsAndMessaging;
|
|||||||
|
|
||||||
namespace NTwain.Native;
|
namespace NTwain.Native;
|
||||||
|
|
||||||
|
|
||||||
#if !NETFRAMEWORK
|
#if !NETFRAMEWORK
|
||||||
[SupportedOSPlatform("windows5.1.2600")]
|
[SupportedOSPlatform("windows5.1.2600")]
|
||||||
#endif
|
#endif
|
||||||
@@ -35,6 +34,9 @@ internal sealed class Win32MessagePump : IDisposable
|
|||||||
private readonly List<IWin32MessageFilter> _messageFilters = new();
|
private readonly List<IWin32MessageFilter> _messageFilters = new();
|
||||||
private readonly object _messageFiltersLock = new();
|
private readonly object _messageFiltersLock = new();
|
||||||
|
|
||||||
|
// SynchronizationContext
|
||||||
|
private Win32SynchronizationContext? _synchronizationContext;
|
||||||
|
|
||||||
public Win32MessagePump()
|
public Win32MessagePump()
|
||||||
{
|
{
|
||||||
_hInstance = PInvoke.GetModuleHandle((string?)null);
|
_hInstance = PInvoke.GetModuleHandle((string?)null);
|
||||||
@@ -48,6 +50,11 @@ internal sealed class Win32MessagePump : IDisposable
|
|||||||
|
|
||||||
public bool InvokeRequired => PInvoke.GetCurrentThreadId() != _threadId;
|
public bool InvokeRequired => PInvoke.GetCurrentThreadId() != _threadId;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the SynchronizationContext associated with this message pump.
|
||||||
|
/// </summary>
|
||||||
|
public SynchronizationContext? SynchronizationContext => _synchronizationContext;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a message filter to the application's message pump.
|
/// Adds a message filter to the application's message pump.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -83,8 +90,15 @@ internal sealed class Win32MessagePump : IDisposable
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create and install the SynchronizationContext
|
||||||
|
_synchronizationContext = new Win32SynchronizationContext(this);
|
||||||
|
SynchronizationContext.SetSynchronizationContext(_synchronizationContext);
|
||||||
|
|
||||||
int exitCode = RunMessageLoop();
|
int exitCode = RunMessageLoop();
|
||||||
|
|
||||||
|
// Clear the SynchronizationContext
|
||||||
|
SynchronizationContext.SetSynchronizationContext(null);
|
||||||
|
|
||||||
Dispose();
|
Dispose();
|
||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
@@ -300,6 +314,87 @@ internal sealed class Win32MessagePump : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SynchronizationContext implementation for Win32MessagePump that integrates
|
||||||
|
/// with async/await and other .NET frameworks.
|
||||||
|
/// </summary>
|
||||||
|
#if !NETFRAMEWORK
|
||||||
|
[SupportedOSPlatform("windows5.1.2600")]
|
||||||
|
#endif
|
||||||
|
internal sealed class Win32SynchronizationContext : SynchronizationContext
|
||||||
|
{
|
||||||
|
private readonly Win32MessagePump _messagePump;
|
||||||
|
|
||||||
|
public Win32SynchronizationContext(Win32MessagePump messagePump)
|
||||||
|
{
|
||||||
|
_messagePump = messagePump ?? throw new ArgumentNullException(nameof(messagePump));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dispatches an asynchronous message to the message pump thread.
|
||||||
|
/// </summary>
|
||||||
|
public override void Post(SendOrPostCallback d, object? state)
|
||||||
|
{
|
||||||
|
if (d == null) return;
|
||||||
|
|
||||||
|
_messagePump.PostToUIThread(() =>
|
||||||
|
{
|
||||||
|
d(state);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dispatches a synchronous message to the message pump thread.
|
||||||
|
/// This is not recommended for general use as it can cause deadlocks.
|
||||||
|
/// </summary>
|
||||||
|
public override void Send(SendOrPostCallback d, object? state)
|
||||||
|
{
|
||||||
|
if (d == null) return;
|
||||||
|
|
||||||
|
if (!_messagePump.InvokeRequired)
|
||||||
|
{
|
||||||
|
// Already on the UI thread
|
||||||
|
d(state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send is synchronous - we need to block until the callback completes
|
||||||
|
// This is dangerous and can cause deadlocks, but it's part of the contract
|
||||||
|
using var completed = new ManualResetEventSlim(false);
|
||||||
|
Exception? exception = null;
|
||||||
|
|
||||||
|
_messagePump.PostToUIThread(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
d(state);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
exception = ex;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
completed.Set();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
completed.Wait();
|
||||||
|
|
||||||
|
if (exception != null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Exception occurred in Send operation", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a copy of the synchronization context.
|
||||||
|
/// </summary>
|
||||||
|
public override SynchronizationContext CreateCopy()
|
||||||
|
{
|
||||||
|
return new Win32SynchronizationContext(_messagePump);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines a message filter interface that allows external code to participate
|
/// Defines a message filter interface that allows external code to participate
|
||||||
|
|||||||
Reference in New Issue
Block a user