Made TwainSession utilize both internal and external thread contexts.

This commit is contained in:
Eugene Wang
2018-11-23 19:39:10 -05:00
parent 59adf25d2a
commit 47ae473316
6 changed files with 73 additions and 83 deletions

View File

@@ -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>

View File

@@ -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()
{
}
} }
} }

View File

@@ -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);
// }
// }
//}

View File

@@ -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(() =>
{ {

View File

@@ -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));
});
} }
} }
} }

View File

@@ -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;
} }