mirror of
https://github.com/soukoku/ntwain.git
synced 2025-09-18 17:47:57 +08:00
Made TwainSession utilize both internal and external thread contexts.
This commit is contained in:
@@ -7,6 +7,16 @@ namespace NTwain.Threading
|
||||
/// </summary>
|
||||
interface IThreadContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Starts the context if supported.
|
||||
/// </summary>
|
||||
void Start();
|
||||
/// <summary>
|
||||
/// Stops the context if supported.
|
||||
/// </summary>
|
||||
void Stop();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Runs the action synchronously on the associated thread.
|
||||
/// </summary>
|
||||
|
@@ -16,15 +16,6 @@ namespace NTwain.Threading
|
||||
{
|
||||
private readonly SynchronizationContext context;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="UIThreadContext"/> using
|
||||
/// the <see cref="SynchronizationContext.Current"/>.
|
||||
/// </summary>
|
||||
public UIThreadContext() : this(SynchronizationContext.Current)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="UIThreadContext"/> using
|
||||
/// the specified <see cref="SynchronizationContext"/>.
|
||||
@@ -32,8 +23,7 @@ namespace NTwain.Threading
|
||||
/// <param name="context"></param>
|
||||
public UIThreadContext(SynchronizationContext context)
|
||||
{
|
||||
this.context = context ?? throw new ArgumentNullException(nameof(context));
|
||||
;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -91,5 +81,13 @@ namespace NTwain.Threading
|
||||
BindingFlags.NonPublic | BindingFlags.Instance)?.Invoke(ex, new object[0]);
|
||||
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,
|
||||
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(() =>
|
||||
{
|
||||
|
@@ -54,8 +54,11 @@ namespace NTwain
|
||||
/// <param name="e"></param>
|
||||
internal protected virtual void OnSourceDisabled(SourceDisabledEventArgs e)
|
||||
{
|
||||
var handler = SourceDisabled;
|
||||
handler?.Invoke(this, e);
|
||||
ExternalInvoke(() =>
|
||||
{
|
||||
var handler = SourceDisabled;
|
||||
handler?.Invoke(this, e);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -69,8 +72,11 @@ namespace NTwain
|
||||
/// <param name="e"></param>
|
||||
protected virtual void OnDeviceEventReceived(DeviceEventArgs e)
|
||||
{
|
||||
var handler = DeviceEventReceived;
|
||||
handler?.Invoke(this, e);
|
||||
ExternalInvoke(() =>
|
||||
{
|
||||
var handler = DeviceEventReceived;
|
||||
handler?.Invoke(this, e);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -84,8 +90,11 @@ namespace NTwain
|
||||
/// <param name="e"></param>
|
||||
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.
|
||||
///// </summary>
|
||||
//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>
|
||||
/// Occurs when an error has been encountered during transfer.
|
||||
/// </summary>
|
||||
@@ -104,8 +128,11 @@ namespace NTwain
|
||||
/// <param name="e"></param>
|
||||
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
|
||||
/// <param name="propertyName">Name of the property.</param>
|
||||
protected void RaisePropertyChanged(string propertyName)
|
||||
{
|
||||
var handler = PropertyChanged;
|
||||
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
ExternalInvoke(() =>
|
||||
{
|
||||
var handler = PropertyChanged;
|
||||
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -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
|
||||
/// <param name="context">Usually you want to use <see cref="SynchronizationContext.Current"/> while on the UI thread.</param>
|
||||
public void SetSynchronizationContext(SynchronizationContext context)
|
||||
{
|
||||
_extSyncContext = new UIThreadContext(context);
|
||||
if (context == null) _externalContext = null;
|
||||
else _externalContext = new UIThreadContext(context);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -68,7 +70,7 @@ namespace NTwain
|
||||
/// <param name="action"></param>
|
||||
void ExternalInvoke(Action action)
|
||||
{
|
||||
if (_extSyncContext != null) _extSyncContext.Invoke(action);
|
||||
if (_externalContext != null) _externalContext.Invoke(action);
|
||||
action();
|
||||
}
|
||||
|
||||
@@ -78,7 +80,7 @@ namespace NTwain
|
||||
/// <param name="action"></param>
|
||||
void ExternalBeginInvoke(Action action)
|
||||
{
|
||||
if (_extSyncContext != null) _extSyncContext.BeginInvoke(action);
|
||||
if (_externalContext != null) _externalContext.BeginInvoke(action);
|
||||
action();
|
||||
}
|
||||
|
||||
@@ -88,7 +90,7 @@ namespace NTwain
|
||||
/// <param name="action"></param>
|
||||
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
|
||||
/// <param name="action"></param>
|
||||
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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user