From 47ae473316e8dad09aae6e1ca0d78b9f855a9b7d Mon Sep 17 00:00:00 2001 From: Eugene Wang Date: Fri, 23 Nov 2018 19:39:10 -0500 Subject: [PATCH] Made TwainSession utilize both internal and external thread contexts. --- src/NTwain/Threading/IThreadContext.cs | 10 +++++ src/NTwain/Threading/UIThreadContext.cs | 20 +++++----- src/NTwain/TwainSession.Disposable.cs | 52 ------------------------- src/NTwain/TwainSession.MsgHandling.cs | 2 + src/NTwain/TwainSession.Props.cs | 50 +++++++++++++++++++----- src/NTwain/TwainSession.cs | 22 ++++++----- 6 files changed, 73 insertions(+), 83 deletions(-) delete mode 100644 src/NTwain/TwainSession.Disposable.cs diff --git a/src/NTwain/Threading/IThreadContext.cs b/src/NTwain/Threading/IThreadContext.cs index 52b7e10..e10c9b5 100644 --- a/src/NTwain/Threading/IThreadContext.cs +++ b/src/NTwain/Threading/IThreadContext.cs @@ -7,6 +7,16 @@ namespace NTwain.Threading /// interface IThreadContext { + /// + /// Starts the context if supported. + /// + void Start(); + /// + /// Stops the context if supported. + /// + void Stop(); + + /// /// Runs the action synchronously on the associated thread. /// diff --git a/src/NTwain/Threading/UIThreadContext.cs b/src/NTwain/Threading/UIThreadContext.cs index 1069dcf..c58b19f 100644 --- a/src/NTwain/Threading/UIThreadContext.cs +++ b/src/NTwain/Threading/UIThreadContext.cs @@ -16,15 +16,6 @@ namespace NTwain.Threading { private readonly SynchronizationContext context; - /// - /// Creates a new using - /// the . - /// - public UIThreadContext() : this(SynchronizationContext.Current) - { - - } - /// /// Creates a new using /// the specified . @@ -32,8 +23,7 @@ namespace NTwain.Threading /// public UIThreadContext(SynchronizationContext context) { - this.context = context ?? throw new ArgumentNullException(nameof(context)); - ; + this.context = context; } /// @@ -91,5 +81,13 @@ namespace NTwain.Threading BindingFlags.NonPublic | BindingFlags.Instance)?.Invoke(ex, new object[0]); throw ex; } + + void IThreadContext.Start() + { + } + + void IThreadContext.Stop() + { + } } } diff --git a/src/NTwain/TwainSession.Disposable.cs b/src/NTwain/TwainSession.Disposable.cs deleted file mode 100644 index f038bd7..0000000 --- a/src/NTwain/TwainSession.Disposable.cs +++ /dev/null @@ -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 - -// /// -// /// Handles actual disposal logic. -// /// -// /// -// 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); -// // } - -// /// -// /// Closes any open TWAIN objects. -// /// -// public void Dispose() -// { -// Dispose(true); -// // TODO: uncomment the following line if the finalizer is overridden above. -// // GC.SuppressFinalize(this); -// } -// } -//} diff --git a/src/NTwain/TwainSession.MsgHandling.cs b/src/NTwain/TwainSession.MsgHandling.cs index 7fec341..eb5a680 100644 --- a/src/NTwain/TwainSession.MsgHandling.cs +++ b/src/NTwain/TwainSession.MsgHandling.cs @@ -22,6 +22,8 @@ namespace NTwain ReturnCode Handle32BitCallback(TW_IDENTITY origin, TW_IDENTITY destination, 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})"); InternalBeginInvoke(() => { diff --git a/src/NTwain/TwainSession.Props.cs b/src/NTwain/TwainSession.Props.cs index d0ddd28..6d14953 100644 --- a/src/NTwain/TwainSession.Props.cs +++ b/src/NTwain/TwainSession.Props.cs @@ -54,8 +54,11 @@ namespace NTwain /// internal protected virtual void OnSourceDisabled(SourceDisabledEventArgs e) { - var handler = SourceDisabled; - handler?.Invoke(this, e); + ExternalInvoke(() => + { + var handler = SourceDisabled; + handler?.Invoke(this, e); + }); } /// @@ -69,8 +72,11 @@ namespace NTwain /// protected virtual void OnDeviceEventReceived(DeviceEventArgs e) { - var handler = DeviceEventReceived; - handler?.Invoke(this, e); + ExternalInvoke(() => + { + var handler = DeviceEventReceived; + handler?.Invoke(this, e); + }); } /// @@ -84,8 +90,11 @@ namespace NTwain /// protected virtual void OnTransferReady(TransferReadyEventArgs e) { - var handler = TransferReady; - handler?.Invoke(this, e); + ExternalInvoke(() => + { + var handler = TransferReady; + handler?.Invoke(this, e); + }); } @@ -93,6 +102,21 @@ namespace NTwain ///// Occurs when data has been transferred. ///// //public event EventHandler DataTransferred; + + ///// + ///// Raises the event. + ///// + ///// + //protected virtual void OnDataTransferred(DataTransferredEventArgs e) + //{ + // ExternalInvoke(() => + // { + // var handler = DataTransferred; + // handler?.Invoke(this, e); + // }); + //} + + /// /// Occurs when an error has been encountered during transfer. /// @@ -104,8 +128,11 @@ namespace NTwain /// protected virtual void OnTransferError(TransferErrorEventArgs e) { - var handler = TransferError; - handler?.Invoke(this, e); + ExternalInvoke(() => + { + var handler = TransferError; + handler?.Invoke(this, e); + }); } @@ -121,8 +148,11 @@ namespace NTwain /// Name of the property. protected void RaisePropertyChanged(string propertyName) { - var handler = PropertyChanged; - handler?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + ExternalInvoke(() => + { + var handler = PropertyChanged; + handler?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + }); } } } diff --git a/src/NTwain/TwainSession.cs b/src/NTwain/TwainSession.cs index 3bc8c49..6fed785 100644 --- a/src/NTwain/TwainSession.cs +++ b/src/NTwain/TwainSession.cs @@ -25,10 +25,10 @@ namespace NTwain // need to keep delegate around to prevent GC readonly Callback32 _callback32Delegate; // for windows only - readonly WinMsgLoop _winMsgLoop; + readonly IThreadContext _internalContext; private IntPtr _hWnd; - private IThreadContext _extSyncContext; + private IThreadContext _externalContext; /// @@ -39,12 +39,13 @@ namespace NTwain public TwainSession(TwainConfig config) { Config = config ?? throw new ArgumentNullException(nameof(config)); + SetSynchronizationContext(SynchronizationContext.Current); switch (config.Platform) { case PlatformID.MacOSX: case PlatformID.Unix: default: - _winMsgLoop = new WinMsgLoop(this); + _internalContext = new WinMsgLoop(this); _callback32Delegate = new Callback32(Handle32BitCallback); break; } @@ -59,7 +60,8 @@ namespace NTwain /// Usually you want to use while on the UI thread. public void SetSynchronizationContext(SynchronizationContext context) { - _extSyncContext = new UIThreadContext(context); + if (context == null) _externalContext = null; + else _externalContext = new UIThreadContext(context); } /// @@ -68,7 +70,7 @@ namespace NTwain /// void ExternalInvoke(Action action) { - if (_extSyncContext != null) _extSyncContext.Invoke(action); + if (_externalContext != null) _externalContext.Invoke(action); action(); } @@ -78,7 +80,7 @@ namespace NTwain /// void ExternalBeginInvoke(Action action) { - if (_extSyncContext != null) _extSyncContext.BeginInvoke(action); + if (_externalContext != null) _externalContext.BeginInvoke(action); action(); } @@ -88,7 +90,7 @@ namespace NTwain /// internal void InternalInvoke(Action action) { - if (_winMsgLoop != null) _winMsgLoop.Invoke(action); + if (_internalContext != null) _internalContext.Invoke(action); else action(); } @@ -98,7 +100,7 @@ namespace NTwain /// void InternalBeginInvoke(Action action) { - if (_winMsgLoop != null) _winMsgLoop.BeginInvoke(action); + if (_internalContext != null) _internalContext.BeginInvoke(action); else action(); } @@ -113,7 +115,7 @@ namespace NTwain var rc = DGControl.Parent.OpenDSM(hWnd); if (rc == ReturnCode.Success) { - _winMsgLoop?.Start(); + _internalContext?.Start(); } return rc; } @@ -127,7 +129,7 @@ namespace NTwain var rc = DGControl.Parent.CloseDSM(_hWnd); if (rc == ReturnCode.Success) { - _winMsgLoop?.Stop(); + _internalContext?.Stop(); } return rc; }