mirror of
https://github.com/soukoku/ntwain.git
synced 2026-01-02 04:17:08 +08:00
Added experimental option to sync events to UI thread.
This commit is contained in:
@@ -15,7 +15,6 @@ namespace NTwain
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
class MessageLoop
|
class MessageLoop
|
||||||
{
|
{
|
||||||
// mostly wraps around a dispatcher?
|
|
||||||
static MessageLoop _instance = new MessageLoop();
|
static MessageLoop _instance = new MessageLoop();
|
||||||
public static MessageLoop Instance { get { return _instance; } }
|
public static MessageLoop Instance { get { return _instance; } }
|
||||||
|
|
||||||
@@ -24,6 +23,7 @@ namespace NTwain
|
|||||||
HwndSource _dummyWindow;
|
HwndSource _dummyWindow;
|
||||||
|
|
||||||
private MessageLoop() { }
|
private MessageLoop() { }
|
||||||
|
|
||||||
public void EnsureStarted()
|
public void EnsureStarted()
|
||||||
{
|
{
|
||||||
if (!_started)
|
if (!_started)
|
||||||
@@ -42,8 +42,9 @@ namespace NTwain
|
|||||||
// CS_NOCLOSE, WS_DISABLED, and WS_EX_NOACTIVATE
|
// CS_NOCLOSE, WS_DISABLED, and WS_EX_NOACTIVATE
|
||||||
_dummyWindow = new HwndSource(0x0200, 0x8000000, 0x8000000, 0, 0, "NTWAIN_LOOPER", IntPtr.Zero);
|
_dummyWindow = new HwndSource(0x0200, 0x8000000, 0x8000000, 0, 0, "NTWAIN_LOOPER", IntPtr.Zero);
|
||||||
}
|
}
|
||||||
hack.Set();
|
hack.Set();
|
||||||
Dispatcher.Run();
|
Dispatcher.Run();
|
||||||
|
_started = false;
|
||||||
}));
|
}));
|
||||||
loopThread.IsBackground = true;
|
loopThread.IsBackground = true;
|
||||||
loopThread.SetApartmentState(ApartmentState.STA);
|
loopThread.SetApartmentState(ApartmentState.STA);
|
||||||
|
|||||||
@@ -14,6 +14,6 @@ namespace NTwain
|
|||||||
// keep this same in majors releases
|
// keep this same in majors releases
|
||||||
public const string Release = "0.11.0.0";
|
public const string Release = "0.11.0.0";
|
||||||
// change this for each nuget release
|
// change this for each nuget release
|
||||||
public const string Build = "0.11.1";
|
public const string Build = "0.11.2";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,6 +65,16 @@ namespace NTwain
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// EXPERIMENTAL. Gets or sets the optional synchronization context.
|
||||||
|
/// This allows events to be raised on the thread
|
||||||
|
/// associated with the context.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The synchronization context.
|
||||||
|
/// </value>
|
||||||
|
public SynchronizationContext SynchronizationContext { get; set; }
|
||||||
|
|
||||||
|
|
||||||
#region ITwainStateInternal Members
|
#region ITwainStateInternal Members
|
||||||
|
|
||||||
@@ -88,7 +98,7 @@ namespace NTwain
|
|||||||
if (notifyChange)
|
if (notifyChange)
|
||||||
{
|
{
|
||||||
RaisePropertyChanged("State");
|
RaisePropertyChanged("State");
|
||||||
OnStateChanged();
|
SafeAsyncSyncableRaiseOnEvent(OnStateChanged, StateChanged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +111,7 @@ namespace NTwain
|
|||||||
{
|
{
|
||||||
SourceId = sourceId;
|
SourceId = sourceId;
|
||||||
RaisePropertyChanged("SourceId");
|
RaisePropertyChanged("SourceId");
|
||||||
OnSourceChanged();
|
SafeAsyncSyncableRaiseOnEvent(OnSourceChanged, SourceChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -132,7 +142,7 @@ namespace NTwain
|
|||||||
{
|
{
|
||||||
_state = value;
|
_state = value;
|
||||||
RaisePropertyChanged("State");
|
RaisePropertyChanged("State");
|
||||||
OnStateChanged();
|
SafeAsyncSyncableRaiseOnEvent(OnStateChanged, StateChanged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,8 +205,27 @@ 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 hand = PropertyChanged;
|
if (SynchronizationContext == null)
|
||||||
if (hand != null) { hand(this, new PropertyChangedEventArgs(propertyName)); }
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var hand = PropertyChanged;
|
||||||
|
if (hand != null) { hand(this, new PropertyChangedEventArgs(propertyName)); }
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SynchronizationContext.Post(o =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var hand = PropertyChanged;
|
||||||
|
if (hand != null) { hand(this, new PropertyChangedEventArgs(propertyName)); }
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -389,7 +418,7 @@ namespace NTwain
|
|||||||
{
|
{
|
||||||
_callbackObj = null;
|
_callbackObj = null;
|
||||||
}
|
}
|
||||||
OnSourceDisabled();
|
SafeAsyncSyncableRaiseOnEvent(OnSourceDisabled, SourceDisabled);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return rc;
|
return rc;
|
||||||
@@ -483,123 +512,108 @@ namespace NTwain
|
|||||||
public event EventHandler<TransferErrorEventArgs> TransferError;
|
public event EventHandler<TransferErrorEventArgs> TransferError;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when <see cref="State"/> changed
|
/// Raises event and if applicable marshal it synchronously to the <see cref="SynchronizationContext" /> thread.
|
||||||
/// and raises the <see cref="StateChanged" /> event.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnStateChanged()
|
/// <typeparam name="TEventArgs">The type of the event arguments.</typeparam>
|
||||||
|
/// <param name="onEventFunc">The on event function.</param>
|
||||||
|
/// <param name="handler">The handler.</param>
|
||||||
|
/// <param name="e">The <see cref="TEventArgs"/> instance containing the event data.</param>
|
||||||
|
void SafeSyncableRaiseOnEvent<TEventArgs>(Action<TEventArgs> onEventFunc, EventHandler<TEventArgs> handler, TEventArgs e) where TEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
var hand = StateChanged;
|
var syncer = SynchronizationContext;
|
||||||
if (hand != null)
|
if (syncer == null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
hand(this, EventArgs.Empty);
|
onEventFunc(e);
|
||||||
|
if (handler != null) { handler(this, e); }
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
syncer.Send(o =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
onEventFunc(e);
|
||||||
|
if (handler != null) { handler(this, e); }
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when <see cref="SourceId"/> changed
|
/// Raises event and if applicable marshal it asynchronously to the <see cref="SynchronizationContext"/> thread.
|
||||||
/// and raises the <see cref="SourceChanged" /> event.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnSourceChanged()
|
/// <param name="onEventFunc">The on event function.</param>
|
||||||
|
/// <param name="handler">The handler.</param>
|
||||||
|
void SafeAsyncSyncableRaiseOnEvent(Action onEventFunc, EventHandler handler)
|
||||||
{
|
{
|
||||||
var hand = SourceChanged;
|
var syncer = SynchronizationContext;
|
||||||
if (hand != null)
|
if (syncer == null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
hand(this, EventArgs.Empty);
|
onEventFunc();
|
||||||
|
if (handler != null) { handler(this, EventArgs.Empty); }
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
syncer.Post(o =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
onEventFunc();
|
||||||
|
if (handler != null) { handler(this, EventArgs.Empty); }
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when source has been disabled (back to state 4)
|
/// Called when <see cref="State"/> changed.
|
||||||
/// and raises the <see cref="SourceDisabled" /> event.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnSourceDisabled()
|
protected virtual void OnStateChanged() { }
|
||||||
{
|
|
||||||
var hand = SourceDisabled;
|
|
||||||
if (hand != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
hand(this, EventArgs.Empty);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raises the <see cref="E:DeviceEvent" /> event.
|
/// Called when <see cref="SourceId"/> changed.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnSourceChanged() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when source has been disabled (back to state 4).
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnSourceDisabled() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the source has generated an event.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="e">The <see cref="DeviceEventArgs"/> instance containing the event data.</param>
|
/// <param name="e">The <see cref="DeviceEventArgs"/> instance containing the event data.</param>
|
||||||
protected virtual void OnDeviceEvent(DeviceEventArgs e)
|
protected virtual void OnDeviceEvent(DeviceEventArgs e) { }
|
||||||
{
|
|
||||||
var hand = DeviceEvent;
|
|
||||||
if (hand != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
hand(this, e);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raises the <see cref="E:TransferReady" /> event.
|
/// Called when a data transfer is ready.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="e">The <see cref="TransferReadyEventArgs"/> instance containing the event data.</param>
|
/// <param name="e">The <see cref="TransferReadyEventArgs"/> instance containing the event data.</param>
|
||||||
protected virtual void OnTransferReady(TransferReadyEventArgs e)
|
protected virtual void OnTransferReady(TransferReadyEventArgs e) { }
|
||||||
{
|
|
||||||
var hand = TransferReady;
|
|
||||||
if (hand != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
hand(this, e);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raises the <see cref="E:DataTransferred" /> event.
|
/// Called when data has been transferred.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="e">The <see cref="DataTransferredEventArgs"/> instance containing the event data.</param>
|
/// <param name="e">The <see cref="DataTransferredEventArgs"/> instance containing the event data.</param>
|
||||||
protected virtual void OnDataTransferred(DataTransferredEventArgs e)
|
protected virtual void OnDataTransferred(DataTransferredEventArgs e) { }
|
||||||
{
|
|
||||||
var hand = DataTransferred;
|
|
||||||
if (hand != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
hand(this, e);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raises the <see cref="E:TransferError" /> event.
|
/// Called when an error has been encountered during transfer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="e">The <see cref="TransferErrorEventArgs"/> instance containing the event data.</param>
|
/// <param name="e">The <see cref="TransferErrorEventArgs"/> instance containing the event data.</param>
|
||||||
protected virtual void OnTransferError(TransferErrorEventArgs e)
|
protected virtual void OnTransferError(TransferErrorEventArgs e) { }
|
||||||
{
|
|
||||||
var hand = TransferError;
|
|
||||||
if (hand != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
hand(this, e);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region TWAIN logic during xfer work
|
#region TWAIN logic during xfer work
|
||||||
@@ -671,7 +685,7 @@ namespace NTwain
|
|||||||
var rc = DGControl.DeviceEvent.Get(out de);
|
var rc = DGControl.DeviceEvent.Get(out de);
|
||||||
if (rc == ReturnCode.Success)
|
if (rc == ReturnCode.Success)
|
||||||
{
|
{
|
||||||
OnDeviceEvent(new DeviceEventArgs(de));
|
SafeSyncableRaiseOnEvent(OnDeviceEvent, DeviceEvent, new DeviceEventArgs(de));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Message.CloseDSReq:
|
case Message.CloseDSReq:
|
||||||
@@ -726,7 +740,7 @@ namespace NTwain
|
|||||||
EndOfJob = pending.EndOfJob == 0
|
EndOfJob = pending.EndOfJob == 0
|
||||||
};
|
};
|
||||||
|
|
||||||
OnTransferReady(preXferArgs);
|
SafeSyncableRaiseOnEvent(OnTransferReady, TransferReady, preXferArgs);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -805,16 +819,17 @@ namespace NTwain
|
|||||||
{
|
{
|
||||||
lockedPtr = MemoryManager.Instance.Lock(dataPtr);
|
lockedPtr = MemoryManager.Instance.Lock(dataPtr);
|
||||||
}
|
}
|
||||||
OnDataTransferred(new DataTransferredEventArgs { NativeData = lockedPtr });
|
|
||||||
|
SafeSyncableRaiseOnEvent(OnDataTransferred, DataTransferred, new DataTransferredEventArgs { NativeData = lockedPtr });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OnTransferError(new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = this.GetSourceStatus() });
|
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = this.GetSourceStatus() });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
OnTransferError(new TransferErrorEventArgs { Exception = ex });
|
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { Exception = ex });
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -845,11 +860,11 @@ namespace NTwain
|
|||||||
var xrc = DGAudio.AudioFileXfer.Get();
|
var xrc = DGAudio.AudioFileXfer.Get();
|
||||||
if (xrc == ReturnCode.XferDone)
|
if (xrc == ReturnCode.XferDone)
|
||||||
{
|
{
|
||||||
OnDataTransferred(new DataTransferredEventArgs { FileDataPath = filePath });
|
SafeSyncableRaiseOnEvent(OnDataTransferred, DataTransferred, new DataTransferredEventArgs { FileDataPath = filePath });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OnTransferError(new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = this.GetSourceStatus() });
|
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = this.GetSourceStatus() });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -876,16 +891,16 @@ namespace NTwain
|
|||||||
{
|
{
|
||||||
lockedPtr = MemoryManager.Instance.Lock(dataPtr);
|
lockedPtr = MemoryManager.Instance.Lock(dataPtr);
|
||||||
}
|
}
|
||||||
OnDataTransferred(new DataTransferredEventArgs { NativeData = lockedPtr, ImageInfo = imgInfo });
|
SafeSyncableRaiseOnEvent(OnDataTransferred, DataTransferred, new DataTransferredEventArgs { NativeData = lockedPtr, ImageInfo = imgInfo });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OnTransferError(new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = this.GetSourceStatus() });
|
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = this.GetSourceStatus() });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
OnTransferError(new TransferErrorEventArgs { Exception = ex });
|
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { Exception = ex });
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -921,11 +936,11 @@ namespace NTwain
|
|||||||
{
|
{
|
||||||
imgInfo = null;
|
imgInfo = null;
|
||||||
}
|
}
|
||||||
OnDataTransferred(new DataTransferredEventArgs { FileDataPath = filePath, ImageInfo = imgInfo });
|
SafeSyncableRaiseOnEvent(OnDataTransferred, DataTransferred, new DataTransferredEventArgs { FileDataPath = filePath, ImageInfo = imgInfo });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OnTransferError(new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = this.GetSourceStatus() });
|
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = this.GetSourceStatus() });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -995,7 +1010,7 @@ namespace NTwain
|
|||||||
//}
|
//}
|
||||||
if (DGImage.ImageInfo.Get(out imgInfo) == ReturnCode.Success)
|
if (DGImage.ImageInfo.Get(out imgInfo) == ReturnCode.Success)
|
||||||
{
|
{
|
||||||
OnDataTransferred(new DataTransferredEventArgs { MemData = xferredData.ToArray(), ImageInfo = imgInfo });
|
SafeSyncableRaiseOnEvent(OnDataTransferred, DataTransferred, new DataTransferredEventArgs { MemData = xferredData.ToArray(), ImageInfo = imgInfo });
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1004,13 +1019,13 @@ namespace NTwain
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OnTransferError(new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = this.GetSourceStatus() });
|
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = this.GetSourceStatus() });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
OnTransferError(new TransferErrorEventArgs { Exception = ex });
|
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { Exception = ex });
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -1130,12 +1145,12 @@ namespace NTwain
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OnTransferError(new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = this.GetSourceStatus() });
|
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { ReturnCode = xrc, SourceStatus = this.GetSourceStatus() });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
OnTransferError(new TransferErrorEventArgs { Exception = ex });
|
SafeSyncableRaiseOnEvent(OnTransferError, TransferError, new TransferErrorEventArgs { Exception = ex });
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -1157,7 +1172,7 @@ namespace NTwain
|
|||||||
{
|
{
|
||||||
imgInfo = null;
|
imgInfo = null;
|
||||||
}
|
}
|
||||||
OnDataTransferred(new DataTransferredEventArgs { FileDataPath = finalFile, ImageInfo = imgInfo });
|
SafeSyncableRaiseOnEvent(OnDataTransferred, DataTransferred, new DataTransferredEventArgs { FileDataPath = finalFile, ImageInfo = imgInfo });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,9 +20,15 @@ and how it works in general. Except for certain "important" calls that drive the
|
|||||||
TWAIN state change, most triplet operations are only availble as-is so you will need to know
|
TWAIN state change, most triplet operations are only availble as-is so you will need to know
|
||||||
when and how to use them. There are no high-level, single-line scan-a-page-for-me-now functions.
|
when and how to use them. There are no high-level, single-line scan-a-page-for-me-now functions.
|
||||||
|
|
||||||
At the moment this lib does not provide ways to parse transferred image data and require
|
|
||||||
consumers to do the conversion. The winform project contains one such
|
|
||||||
example for handling DIB image in native transfer.
|
|
||||||
|
|
||||||
The main class to use is TwainSession. New it up, hook into the events, and start calling
|
The main class to use is TwainSession. New it up, hook into the events, and start calling
|
||||||
all the TWAIN functions provided through it.
|
all the TWAIN functions provided through it.
|
||||||
|
|
||||||
|
Caveats
|
||||||
|
--------------------------------------
|
||||||
|
At the moment this lib does not provide ways to parse transferred image data and require
|
||||||
|
consumers to do the conversion themselves. The winform project contains one such
|
||||||
|
example for handling DIB image in native transfer using the CommonWin32 lib.
|
||||||
|
|
||||||
|
Because it hosts its own message thread, the event callbacks will likely be from another thread.
|
||||||
|
If you would like things marshalled to a "UI" thread then set the SynchronizationContext property
|
||||||
|
to the one from the UI thread. This part is highly experimental.
|
||||||
@@ -11,6 +11,7 @@ using System.Windows.Media.Imaging;
|
|||||||
using CommonWin32;
|
using CommonWin32;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using GalaSoft.MvvmLight.Messaging;
|
using GalaSoft.MvvmLight.Messaging;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Tester.WPF
|
namespace Tester.WPF
|
||||||
{
|
{
|
||||||
@@ -22,7 +23,7 @@ namespace Tester.WPF
|
|||||||
public TwainVM()
|
public TwainVM()
|
||||||
: base(TWIdentity.CreateFromAssembly(DataGroups.Image | DataGroups.Audio, Assembly.GetEntryAssembly()))
|
: base(TWIdentity.CreateFromAssembly(DataGroups.Image | DataGroups.Audio, Assembly.GetEntryAssembly()))
|
||||||
{
|
{
|
||||||
|
this.SynchronizationContext = SynchronizationContext.Current;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImageSource _image;
|
private ImageSource _image;
|
||||||
@@ -63,7 +64,6 @@ namespace Tester.WPF
|
|||||||
Button = System.Windows.MessageBoxButton.OK
|
Button = System.Windows.MessageBoxButton.OK
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
base.OnTransferError(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnTransferReady(TransferReadyEventArgs e)
|
protected override void OnTransferReady(TransferReadyEventArgs e)
|
||||||
@@ -82,24 +82,22 @@ namespace Tester.WPF
|
|||||||
};
|
};
|
||||||
var rc = this.DGControl.SetupFileXfer.Set(fileSetup);
|
var rc = this.DGControl.SetupFileXfer.Set(fileSetup);
|
||||||
}
|
}
|
||||||
base.OnTransferReady(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDataTransferred(DataTransferredEventArgs e)
|
protected override void OnDataTransferred(DataTransferredEventArgs e)
|
||||||
{
|
{
|
||||||
App.Current.Dispatcher.Invoke(new Action(() =>
|
//App.Current.Dispatcher.Invoke(new Action(() =>
|
||||||
|
//{
|
||||||
|
if (e.NativeData != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
if (e.NativeData != IntPtr.Zero)
|
Image = e.NativeData.GetWPFBitmap();
|
||||||
{
|
}
|
||||||
Image = e.NativeData.GetWPFBitmap();
|
else if (!string.IsNullOrEmpty(e.FileDataPath))
|
||||||
}
|
{
|
||||||
else if (!string.IsNullOrEmpty(e.FileDataPath))
|
var img = new BitmapImage(new Uri(e.FileDataPath));
|
||||||
{
|
Image = img;
|
||||||
var img = new BitmapImage(new Uri(e.FileDataPath));
|
}
|
||||||
Image = img;
|
//}));
|
||||||
}
|
|
||||||
}));
|
|
||||||
base.OnDataTransferred(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void TestCapture(IntPtr hwnd)
|
public void TestCapture(IntPtr hwnd)
|
||||||
|
|||||||
@@ -61,10 +61,21 @@ namespace Tester.Winform
|
|||||||
{
|
{
|
||||||
var appId = TWIdentity.CreateFromAssembly(DataGroups.Image, Assembly.GetEntryAssembly());
|
var appId = TWIdentity.CreateFromAssembly(DataGroups.Image, Assembly.GetEntryAssembly());
|
||||||
_twain = new TwainSession(appId);
|
_twain = new TwainSession(appId);
|
||||||
|
// either set this and don't worry about threads during events,
|
||||||
|
// or don't and invoke during the events yourselv
|
||||||
|
_twain.SynchronizationContext = SynchronizationContext.Current;
|
||||||
|
_twain.StateChanged += (s, e) =>
|
||||||
|
{
|
||||||
|
Debug.WriteLine("State change on thread " + Thread.CurrentThread.ManagedThreadId);
|
||||||
|
//this.BeginInvoke(new Action(() =>
|
||||||
|
//{
|
||||||
|
// Debug.WriteLine("State change marshaled to thread " + Thread.CurrentThread.ManagedThreadId);
|
||||||
|
//}));
|
||||||
|
};
|
||||||
_twain.DataTransferred += (s, e) =>
|
_twain.DataTransferred += (s, e) =>
|
||||||
{
|
{
|
||||||
this.Invoke(new Action(() =>
|
//this.Invoke(new Action(() =>
|
||||||
{
|
//{
|
||||||
if (pictureBox1.Image != null)
|
if (pictureBox1.Image != null)
|
||||||
{
|
{
|
||||||
pictureBox1.Image.Dispose();
|
pictureBox1.Image.Dispose();
|
||||||
@@ -72,7 +83,6 @@ namespace Tester.Winform
|
|||||||
}
|
}
|
||||||
if (e.NativeData != IntPtr.Zero)
|
if (e.NativeData != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
//_ptrTest = e.Data;
|
|
||||||
var img = e.NativeData.GetDrawingBitmap();
|
var img = e.NativeData.GetDrawingBitmap();
|
||||||
if (img != null)
|
if (img != null)
|
||||||
pictureBox1.Image = img;
|
pictureBox1.Image = img;
|
||||||
@@ -82,17 +92,17 @@ namespace Tester.Winform
|
|||||||
var img = new Bitmap(e.FileDataPath);
|
var img = new Bitmap(e.FileDataPath);
|
||||||
pictureBox1.Image = img;
|
pictureBox1.Image = img;
|
||||||
}
|
}
|
||||||
}));
|
//}));
|
||||||
};
|
};
|
||||||
_twain.SourceDisabled += (s, e) =>
|
_twain.SourceDisabled += (s, e) =>
|
||||||
{
|
{
|
||||||
this.Invoke(new Action(() =>
|
//this.Invoke(new Action(() =>
|
||||||
{
|
//{
|
||||||
btnStopScan.Enabled = false;
|
btnStopScan.Enabled = false;
|
||||||
btnStartCapture.Enabled = true;
|
btnStartCapture.Enabled = true;
|
||||||
panelOptions.Enabled = true;
|
panelOptions.Enabled = true;
|
||||||
LoadSourceCaps();
|
LoadSourceCaps();
|
||||||
}));
|
//}));
|
||||||
};
|
};
|
||||||
_twain.TransferReady += (s, e) =>
|
_twain.TransferReady += (s, e) =>
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user