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