From f48c731aad52b058ddac1525e2e0bf785c0de758 Mon Sep 17 00:00:00 2001
From: Eugene Wang <8755753+soukoku@users.noreply.github.com>
Date: Tue, 4 Apr 2023 22:53:05 -0400
Subject: [PATCH] More ready event in xfer logic.
---
src/NTwain/Data/TWAINH.cs | 2 +-
src/NTwain/TransferReadyEventArgs.cs | 85 ++++++++++++++++++++++++
src/NTwain/TwainAppSession.PropEvents.cs | 11 +++
src/NTwain/TwainAppSession.Xfers.cs | 68 +++++++++++++------
4 files changed, 146 insertions(+), 20 deletions(-)
create mode 100644 src/NTwain/TransferReadyEventArgs.cs
diff --git a/src/NTwain/Data/TWAINH.cs b/src/NTwain/Data/TWAINH.cs
index fd5b77a..91977a3 100644
--- a/src/NTwain/Data/TWAINH.cs
+++ b/src/NTwain/Data/TWAINH.cs
@@ -2385,7 +2385,7 @@ namespace NTwain.Data
[StructLayout(LayoutKind.Sequential, Pack = 2)]
public struct TW_PENDINGXFERS
{
- public ushort Count;
+ public short Count;
public uint EOJ;
}
diff --git a/src/NTwain/TransferReadyEventArgs.cs b/src/NTwain/TransferReadyEventArgs.cs
new file mode 100644
index 0000000..cb1f144
--- /dev/null
+++ b/src/NTwain/TransferReadyEventArgs.cs
@@ -0,0 +1,85 @@
+using NTwain.Data;
+using System;
+
+namespace NTwain
+{
+ ///
+ /// Contains event data when a data transfer is ready to be processed.
+ ///
+ public class TransferReadyEventArgs : EventArgs
+ {
+ public TransferReadyEventArgs(TwainAppSession twain, int pendingCount, TWEJ endOfJobFlag)
+ {
+ _twain = twain;
+ PendingCount = pendingCount;
+ EndOfJobFlag = endOfJobFlag;
+ }
+
+
+ ///
+ /// Gets or sets whether the current transfer should be skipped
+ /// and continue next transfer if there are more data.
+ ///
+ public bool SkipCurrent { get; set; }
+
+ ///
+ /// Gets or sets whether to cancel the capture phase.
+ ///
+ public CancelType Cancel { get; set; }
+
+ ///
+ /// Gets the end of job flag value for this transfer if job control is enabled.
+ ///
+ public TWEJ EndOfJobFlag { get; private set; }
+
+ ///
+ /// Gets the known pending transfer count. This may not be appilicable
+ /// for certain scanning modes.
+ ///
+ public int PendingCount { get; private set; }
+
+ TW_IMAGEINFO? _imgInfo;
+ private readonly TwainAppSession _twain;
+
+ ///
+ /// Gets the tentative image information for the current transfer if applicable.
+ /// This may differ from the final image depending on the transfer mode used (mostly when doing mem xfer).
+ ///
+ public TW_IMAGEINFO? PendingImageInfo
+ {
+ get
+ {
+ // only get it if requested since it could be slow
+ if (!_imgInfo.HasValue)
+ {
+ if (_twain.GetImageInfo(out TW_IMAGEINFO info).RC == TWRC.SUCCESS)
+ {
+ _imgInfo = info;
+ }
+ }
+ return _imgInfo;
+ }
+ }
+
+ }
+
+ public enum CancelType
+ {
+ ///
+ /// No cancel.
+ ///
+ None,
+ ///
+ /// Skips current transfer.
+ ///
+ SkipCurrent,
+ ///
+ /// Stops feeder but continue receiving already scanned images in the app.
+ ///
+ Graceful,
+ ///
+ /// Stops feeder and discard any pending images.
+ ///
+ EndNow
+ }
+}
diff --git a/src/NTwain/TwainAppSession.PropEvents.cs b/src/NTwain/TwainAppSession.PropEvents.cs
index 84dd050..3d52095 100644
--- a/src/NTwain/TwainAppSession.PropEvents.cs
+++ b/src/NTwain/TwainAppSession.PropEvents.cs
@@ -140,5 +140,16 @@ namespace NTwain
/// Fires when there's an error during transfer.
///
public event EventHandler? TransferError;
+
+ ///
+ /// Fires when there's an upcoming transfer. App can inspect the image info
+ /// and cancel if needed.
+ ///
+ public event EventHandler? TransferReady;
+
+ ///
+ /// Fires when transferred data is available for app to use.
+ ///
+ public event EventHandler? DataTransferred;
}
}
diff --git a/src/NTwain/TwainAppSession.Xfers.cs b/src/NTwain/TwainAppSession.Xfers.cs
index 850094b..83c9109 100644
--- a/src/NTwain/TwainAppSession.Xfers.cs
+++ b/src/NTwain/TwainAppSession.Xfers.cs
@@ -18,6 +18,11 @@ namespace NTwain
// so the array max is made with 32 MB. Typical usage should be a lot less.
static readonly ArrayPool XferMemPool = ArrayPool.Create(32505856, 4);
+ public STS GetImageInfo(out TW_IMAGEINFO info)
+ {
+ return WrapInSTS(DGImage.ImageInfo.Get(ref _appIdentity, ref _currentDS, out info));
+ }
+
///
/// Start the transfer loop.
@@ -49,14 +54,22 @@ namespace NTwain
}
}
- //if (xferImage)
- //{
- // imgXferMech = session.CurrentSource.Capabilities.ICapXferMech.GetCurrent();
- //}
- //if (xferAudio)
- //{
- // audXferMech = session.CurrentSource.Capabilities.ACapXferMech.GetCurrent();
- //}
+ if (xferImage)
+ {
+ if (GetCapCurrent(CAP.ICAP_XFERMECH, out TW_CAPABILITY cap).RC == TWRC.SUCCESS)
+ {
+ // todo:
+ cap.Free(this);
+ }
+ }
+ else if (xferAudio)
+ {
+ if (GetCapCurrent(CAP.ACAP_XFERMECH, out TW_CAPABILITY cap).RC == TWRC.SUCCESS)
+ {
+ // todo:
+ cap.Free(this);
+ }
+ }
TW_PENDINGXFERS pending = default;
var rc = DGControl.PendingXfers.Get(ref _appIdentity, ref _currentDS, ref pending);
@@ -64,20 +77,37 @@ namespace NTwain
{
do
{
- // cancel for now
- //rc = DGControl.PendingXfers.Reset(ref _appIdentity, ref _currentDS, ref pending);
+ var readyArgs = new TransferReadyEventArgs(this, pending.Count, (TWEJ)pending.EOJ);
+ _uiThreadMarshaller.Invoke(() =>
+ {
+ TransferReady?.Invoke(this, readyArgs);
+ });
+ switch (readyArgs.Cancel)
+ {
+ case CancelType.SkipCurrent:
+ rc = DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending);
+ break;
+ case CancelType.EndNow:
+ rc = DGControl.PendingXfers.Reset(ref _appIdentity, ref _currentDS, ref pending);
+ break;
+ case CancelType.Graceful:
+ //??? oh boy
+ rc = DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending);
+ break;
+ default:
+ // normal capture
+ if (xferImage)
+ {
- rc = DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending);
+ }
+ else if (xferAudio)
+ {
- //if (xferType.HasFlag(DG.AUDIO))
- //{
- // DoTransferAudio();
- //}
- //else // just defaults to image
- //{
- // DoTransferImage();
- //}
+ }
+ rc = DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending);
+ break;
+ }
} while (rc == TWRC.SUCCESS && pending.Count != 0);
}