mirror of
https://github.com/soukoku/ntwain.git
synced 2025-09-19 01:57:56 +08:00
Made TwainSession utilize both internal and external thread contexts.
This commit is contained in:
@@ -7,6 +7,16 @@ namespace NTwain.Threading
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
interface IThreadContext
|
interface IThreadContext
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Starts the context if supported.
|
||||||
|
/// </summary>
|
||||||
|
void Start();
|
||||||
|
/// <summary>
|
||||||
|
/// Stops the context if supported.
|
||||||
|
/// </summary>
|
||||||
|
void Stop();
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs the action synchronously on the associated thread.
|
/// Runs the action synchronously on the associated thread.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@@ -16,15 +16,6 @@ namespace NTwain.Threading
|
|||||||
{
|
{
|
||||||
private readonly SynchronizationContext context;
|
private readonly SynchronizationContext context;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new <see cref="UIThreadContext"/> using
|
|
||||||
/// the <see cref="SynchronizationContext.Current"/>.
|
|
||||||
/// </summary>
|
|
||||||
public UIThreadContext() : this(SynchronizationContext.Current)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="UIThreadContext"/> using
|
/// Creates a new <see cref="UIThreadContext"/> using
|
||||||
/// the specified <see cref="SynchronizationContext"/>.
|
/// the specified <see cref="SynchronizationContext"/>.
|
||||||
@@ -32,8 +23,7 @@ namespace NTwain.Threading
|
|||||||
/// <param name="context"></param>
|
/// <param name="context"></param>
|
||||||
public UIThreadContext(SynchronizationContext context)
|
public UIThreadContext(SynchronizationContext context)
|
||||||
{
|
{
|
||||||
this.context = context ?? throw new ArgumentNullException(nameof(context));
|
this.context = context;
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -91,5 +81,13 @@ namespace NTwain.Threading
|
|||||||
BindingFlags.NonPublic | BindingFlags.Instance)?.Invoke(ex, new object[0]);
|
BindingFlags.NonPublic | BindingFlags.Instance)?.Invoke(ex, new object[0]);
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IThreadContext.Start()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void IThreadContext.Stop()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,52 +0,0 @@
|
|||||||
//using NTwain.Data;
|
|
||||||
//using NTwain.Triplets;
|
|
||||||
//using System;
|
|
||||||
//using System.Collections.Generic;
|
|
||||||
//using System.ComponentModel;
|
|
||||||
//using System.Linq;
|
|
||||||
//using System.Text;
|
|
||||||
|
|
||||||
//namespace NTwain
|
|
||||||
//{
|
|
||||||
// partial class TwainSession : IDisposable
|
|
||||||
// {
|
|
||||||
// private bool disposedValue = false; // To detect redundant calls
|
|
||||||
|
|
||||||
// /// <summary>
|
|
||||||
// /// Handles actual disposal logic.
|
|
||||||
// /// </summary>
|
|
||||||
// /// <param name="disposing"></param>
|
|
||||||
// protected virtual void Dispose(bool disposing)
|
|
||||||
// {
|
|
||||||
// if (!disposedValue)
|
|
||||||
// {
|
|
||||||
// if (disposing)
|
|
||||||
// {
|
|
||||||
// StepDown(TwainState.DsmLoaded);
|
|
||||||
// // TODO: dispose managed state (managed objects).
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
|
|
||||||
// // TODO: set large fields to null.
|
|
||||||
|
|
||||||
// disposedValue = true;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
|
|
||||||
// // ~TwainSession() {
|
|
||||||
// // // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
|
||||||
// // Dispose(false);
|
|
||||||
// // }
|
|
||||||
|
|
||||||
// /// <summary>
|
|
||||||
// /// Closes any open TWAIN objects.
|
|
||||||
// /// </summary>
|
|
||||||
// public void Dispose()
|
|
||||||
// {
|
|
||||||
// Dispose(true);
|
|
||||||
// // TODO: uncomment the following line if the finalizer is overridden above.
|
|
||||||
// // GC.SuppressFinalize(this);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
@@ -22,6 +22,8 @@ namespace NTwain
|
|||||||
ReturnCode Handle32BitCallback(TW_IDENTITY origin, TW_IDENTITY destination,
|
ReturnCode Handle32BitCallback(TW_IDENTITY origin, TW_IDENTITY destination,
|
||||||
DataGroups dg, DataArgumentType dat, Message msg, IntPtr data)
|
DataGroups dg, DataArgumentType dat, Message msg, IntPtr data)
|
||||||
{
|
{
|
||||||
|
// from the docs this needs to return Success
|
||||||
|
// before handling the msg thus BeginInvoke is used.
|
||||||
Debug.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: {nameof(Handle32BitCallback)}({dg}, {dat}, {msg}, {data})");
|
Debug.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: {nameof(Handle32BitCallback)}({dg}, {dat}, {msg}, {data})");
|
||||||
InternalBeginInvoke(() =>
|
InternalBeginInvoke(() =>
|
||||||
{
|
{
|
||||||
|
@@ -54,8 +54,11 @@ namespace NTwain
|
|||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
internal protected virtual void OnSourceDisabled(SourceDisabledEventArgs e)
|
internal protected virtual void OnSourceDisabled(SourceDisabledEventArgs e)
|
||||||
{
|
{
|
||||||
var handler = SourceDisabled;
|
ExternalInvoke(() =>
|
||||||
handler?.Invoke(this, e);
|
{
|
||||||
|
var handler = SourceDisabled;
|
||||||
|
handler?.Invoke(this, e);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -69,8 +72,11 @@ namespace NTwain
|
|||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
protected virtual void OnDeviceEventReceived(DeviceEventArgs e)
|
protected virtual void OnDeviceEventReceived(DeviceEventArgs e)
|
||||||
{
|
{
|
||||||
var handler = DeviceEventReceived;
|
ExternalInvoke(() =>
|
||||||
handler?.Invoke(this, e);
|
{
|
||||||
|
var handler = DeviceEventReceived;
|
||||||
|
handler?.Invoke(this, e);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -84,8 +90,11 @@ namespace NTwain
|
|||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
protected virtual void OnTransferReady(TransferReadyEventArgs e)
|
protected virtual void OnTransferReady(TransferReadyEventArgs e)
|
||||||
{
|
{
|
||||||
var handler = TransferReady;
|
ExternalInvoke(() =>
|
||||||
handler?.Invoke(this, e);
|
{
|
||||||
|
var handler = TransferReady;
|
||||||
|
handler?.Invoke(this, e);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -93,6 +102,21 @@ namespace NTwain
|
|||||||
///// Occurs when data has been transferred.
|
///// Occurs when data has been transferred.
|
||||||
///// </summary>
|
///// </summary>
|
||||||
//public event EventHandler<DataTransferredEventArgs> DataTransferred;
|
//public event EventHandler<DataTransferredEventArgs> DataTransferred;
|
||||||
|
|
||||||
|
///// <summary>
|
||||||
|
///// Raises the <see cref="DataTransferred"/> event.
|
||||||
|
///// </summary>
|
||||||
|
///// <param name="e"></param>
|
||||||
|
//protected virtual void OnDataTransferred(DataTransferredEventArgs e)
|
||||||
|
//{
|
||||||
|
// ExternalInvoke(() =>
|
||||||
|
// {
|
||||||
|
// var handler = DataTransferred;
|
||||||
|
// handler?.Invoke(this, e);
|
||||||
|
// });
|
||||||
|
//}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when an error has been encountered during transfer.
|
/// Occurs when an error has been encountered during transfer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -104,8 +128,11 @@ namespace NTwain
|
|||||||
/// <param name="e"></param>
|
/// <param name="e"></param>
|
||||||
protected virtual void OnTransferError(TransferErrorEventArgs e)
|
protected virtual void OnTransferError(TransferErrorEventArgs e)
|
||||||
{
|
{
|
||||||
var handler = TransferError;
|
ExternalInvoke(() =>
|
||||||
handler?.Invoke(this, e);
|
{
|
||||||
|
var handler = TransferError;
|
||||||
|
handler?.Invoke(this, e);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -121,8 +148,11 @@ namespace NTwain
|
|||||||
/// <param name="propertyName">Name of the property.</param>
|
/// <param name="propertyName">Name of the property.</param>
|
||||||
protected void RaisePropertyChanged(string propertyName)
|
protected void RaisePropertyChanged(string propertyName)
|
||||||
{
|
{
|
||||||
var handler = PropertyChanged;
|
ExternalInvoke(() =>
|
||||||
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
{
|
||||||
|
var handler = PropertyChanged;
|
||||||
|
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,10 +25,10 @@ namespace NTwain
|
|||||||
// need to keep delegate around to prevent GC
|
// need to keep delegate around to prevent GC
|
||||||
readonly Callback32 _callback32Delegate;
|
readonly Callback32 _callback32Delegate;
|
||||||
// for windows only
|
// for windows only
|
||||||
readonly WinMsgLoop _winMsgLoop;
|
readonly IThreadContext _internalContext;
|
||||||
|
|
||||||
private IntPtr _hWnd;
|
private IntPtr _hWnd;
|
||||||
private IThreadContext _extSyncContext;
|
private IThreadContext _externalContext;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -39,12 +39,13 @@ namespace NTwain
|
|||||||
public TwainSession(TwainConfig config)
|
public TwainSession(TwainConfig config)
|
||||||
{
|
{
|
||||||
Config = config ?? throw new ArgumentNullException(nameof(config));
|
Config = config ?? throw new ArgumentNullException(nameof(config));
|
||||||
|
SetSynchronizationContext(SynchronizationContext.Current);
|
||||||
switch (config.Platform)
|
switch (config.Platform)
|
||||||
{
|
{
|
||||||
case PlatformID.MacOSX:
|
case PlatformID.MacOSX:
|
||||||
case PlatformID.Unix:
|
case PlatformID.Unix:
|
||||||
default:
|
default:
|
||||||
_winMsgLoop = new WinMsgLoop(this);
|
_internalContext = new WinMsgLoop(this);
|
||||||
_callback32Delegate = new Callback32(Handle32BitCallback);
|
_callback32Delegate = new Callback32(Handle32BitCallback);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -59,7 +60,8 @@ namespace NTwain
|
|||||||
/// <param name="context">Usually you want to use <see cref="SynchronizationContext.Current"/> while on the UI thread.</param>
|
/// <param name="context">Usually you want to use <see cref="SynchronizationContext.Current"/> while on the UI thread.</param>
|
||||||
public void SetSynchronizationContext(SynchronizationContext context)
|
public void SetSynchronizationContext(SynchronizationContext context)
|
||||||
{
|
{
|
||||||
_extSyncContext = new UIThreadContext(context);
|
if (context == null) _externalContext = null;
|
||||||
|
else _externalContext = new UIThreadContext(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -68,7 +70,7 @@ namespace NTwain
|
|||||||
/// <param name="action"></param>
|
/// <param name="action"></param>
|
||||||
void ExternalInvoke(Action action)
|
void ExternalInvoke(Action action)
|
||||||
{
|
{
|
||||||
if (_extSyncContext != null) _extSyncContext.Invoke(action);
|
if (_externalContext != null) _externalContext.Invoke(action);
|
||||||
action();
|
action();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +80,7 @@ namespace NTwain
|
|||||||
/// <param name="action"></param>
|
/// <param name="action"></param>
|
||||||
void ExternalBeginInvoke(Action action)
|
void ExternalBeginInvoke(Action action)
|
||||||
{
|
{
|
||||||
if (_extSyncContext != null) _extSyncContext.BeginInvoke(action);
|
if (_externalContext != null) _externalContext.BeginInvoke(action);
|
||||||
action();
|
action();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +90,7 @@ namespace NTwain
|
|||||||
/// <param name="action"></param>
|
/// <param name="action"></param>
|
||||||
internal void InternalInvoke(Action action)
|
internal void InternalInvoke(Action action)
|
||||||
{
|
{
|
||||||
if (_winMsgLoop != null) _winMsgLoop.Invoke(action);
|
if (_internalContext != null) _internalContext.Invoke(action);
|
||||||
else action();
|
else action();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +100,7 @@ namespace NTwain
|
|||||||
/// <param name="action"></param>
|
/// <param name="action"></param>
|
||||||
void InternalBeginInvoke(Action action)
|
void InternalBeginInvoke(Action action)
|
||||||
{
|
{
|
||||||
if (_winMsgLoop != null) _winMsgLoop.BeginInvoke(action);
|
if (_internalContext != null) _internalContext.BeginInvoke(action);
|
||||||
else action();
|
else action();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +115,7 @@ namespace NTwain
|
|||||||
var rc = DGControl.Parent.OpenDSM(hWnd);
|
var rc = DGControl.Parent.OpenDSM(hWnd);
|
||||||
if (rc == ReturnCode.Success)
|
if (rc == ReturnCode.Success)
|
||||||
{
|
{
|
||||||
_winMsgLoop?.Start();
|
_internalContext?.Start();
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -127,7 +129,7 @@ namespace NTwain
|
|||||||
var rc = DGControl.Parent.CloseDSM(_hWnd);
|
var rc = DGControl.Parent.CloseDSM(_hWnd);
|
||||||
if (rc == ReturnCode.Success)
|
if (rc == ReturnCode.Success)
|
||||||
{
|
{
|
||||||
_winMsgLoop?.Stop();
|
_internalContext?.Stop();
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user