From f015e826820715a906f7101b5055b701af587719 Mon Sep 17 00:00:00 2001 From: Eugene Wang <8755753+soukoku@users.noreply.github.com> Date: Sat, 8 Apr 2023 13:41:20 -0400 Subject: [PATCH] Checked for rc in prepre mem xfer calls now. --- src/NTwain/Data/TWAINH.cs | 6 +- src/NTwain/Data/TWAINH_EXTRAS.cs | 44 +++- src/NTwain/DataTransferredEventArgs.cs | 2 +- src/NTwain/TransferReadyEventArgs.cs | 46 ++-- src/NTwain/TwainAppSession.Xfers.cs | 281 ++++++++++++------------- 5 files changed, 199 insertions(+), 180 deletions(-) diff --git a/src/NTwain/Data/TWAINH.cs b/src/NTwain/Data/TWAINH.cs index 2c79128..3edb9cb 100644 --- a/src/NTwain/Data/TWAINH.cs +++ b/src/NTwain/Data/TWAINH.cs @@ -2299,7 +2299,7 @@ namespace NTwain.Data /// Describes the form of the acquired data being passed from the Source to the application. /// [StructLayout(LayoutKind.Sequential, Pack = 2)] - public struct TW_IMAGEMEMXFER + public partial struct TW_IMAGEMEMXFER { public ushort Compression; public uint BytesPerRow; @@ -2311,7 +2311,7 @@ namespace NTwain.Data public TW_MEMORY Memory; } [StructLayout(LayoutKind.Sequential, Pack = 2)] - public struct TW_IMAGEMEMXFER_LINUX64 + public partial struct TW_IMAGEMEMXFER_LINUX64 { public ushort Compression; public UInt64 BytesPerRow; @@ -2326,7 +2326,7 @@ namespace NTwain.Data public IntPtr MemoryTheMem; } [StructLayout(LayoutKind.Sequential, Pack = 2)] - public struct TW_IMAGEMEMXFER_MACOSX + public partial struct TW_IMAGEMEMXFER_MACOSX { public uint Compression; public uint BytesPerRow; diff --git a/src/NTwain/Data/TWAINH_EXTRAS.cs b/src/NTwain/Data/TWAINH_EXTRAS.cs index db5d492..d1730bd 100644 --- a/src/NTwain/Data/TWAINH_EXTRAS.cs +++ b/src/NTwain/Data/TWAINH_EXTRAS.cs @@ -274,7 +274,7 @@ namespace NTwain.Data IEnumerator IEnumerable.GetEnumerator() { - if (!(MinValue is IConvertible)) + if (MinValue is not IConvertible) throw new NotSupportedException($"The value type {typeof(TValue).Name} is not supported for range enumeration."); return new DynamicEnumerator(MinValue, MaxValue, StepSize); @@ -779,6 +779,48 @@ namespace NTwain.Data } } + partial struct TW_IMAGEMEMXFER + { + /// + /// Get a don't care version for app use. + /// + /// + public static TW_IMAGEMEMXFER DONTCARE() + { + return new TW_IMAGEMEMXFER + { + BytesPerRow = TwainConst.TWON_DONTCARE32, + BytesWritten = TwainConst.TWON_DONTCARE32, + Columns = TwainConst.TWON_DONTCARE32, + Compression = TwainConst.TWON_DONTCARE16, + Rows = TwainConst.TWON_DONTCARE32, + XOffset = TwainConst.TWON_DONTCARE32, + YOffset = TwainConst.TWON_DONTCARE32, + }; + } + } + + partial struct TW_IMAGEMEMXFER_MACOSX + { + /// + /// Get a don't care version for app use. + /// + /// + public static TW_IMAGEMEMXFER_MACOSX DONTCARE() + { + return new TW_IMAGEMEMXFER_MACOSX + { + BytesPerRow = TwainConst.TWON_DONTCARE32, + BytesWritten = TwainConst.TWON_DONTCARE32, + Columns = TwainConst.TWON_DONTCARE32, + Compression = TwainConst.TWON_DONTCARE32, + Rows = TwainConst.TWON_DONTCARE32, + XOffset = TwainConst.TWON_DONTCARE32, + YOffset = TwainConst.TWON_DONTCARE32, + }; + } + } + //partial struct TW_DEVICEEVENT //{ // public TWDE Event { get { return (TWDE)_event; } } diff --git a/src/NTwain/DataTransferredEventArgs.cs b/src/NTwain/DataTransferredEventArgs.cs index 4f39c6e..68d2f44 100644 --- a/src/NTwain/DataTransferredEventArgs.cs +++ b/src/NTwain/DataTransferredEventArgs.cs @@ -19,7 +19,7 @@ namespace NTwain Data = data; } - public DataTransferredEventArgs(TW_IMAGEINFO info, TW_SETUPFILEXFER? fileInfo, byte[] data) + public DataTransferredEventArgs(TW_IMAGEINFO info, TW_SETUPFILEXFER? fileInfo, byte[]? data) { ImageInfo = info; FileInfo = fileInfo; diff --git a/src/NTwain/TransferReadyEventArgs.cs b/src/NTwain/TransferReadyEventArgs.cs index cb1f144..8d6a5f7 100644 --- a/src/NTwain/TransferReadyEventArgs.cs +++ b/src/NTwain/TransferReadyEventArgs.cs @@ -8,9 +8,9 @@ namespace NTwain /// public class TransferReadyEventArgs : EventArgs { - public TransferReadyEventArgs(TwainAppSession twain, int pendingCount, TWEJ endOfJobFlag) + public TransferReadyEventArgs(int pendingCount, TWEJ endOfJobFlag) { - _twain = twain; + //_twain = twain; PendingCount = pendingCount; EndOfJobFlag = endOfJobFlag; } @@ -38,28 +38,28 @@ namespace NTwain /// public int PendingCount { get; private set; } - TW_IMAGEINFO? _imgInfo; - private readonly TwainAppSession _twain; + //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; - } - } + ///// + ///// 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; + // } + //} } diff --git a/src/NTwain/TwainAppSession.Xfers.cs b/src/NTwain/TwainAppSession.Xfers.cs index bd46a0d..b45b871 100644 --- a/src/NTwain/TwainAppSession.Xfers.cs +++ b/src/NTwain/TwainAppSession.Xfers.cs @@ -22,11 +22,6 @@ namespace NTwain // so the array max is made with 32 MB. Typical usage should be a lot less. static readonly ArrayPool XferMemPool = ArrayPool.Create(32 * 1024 * 1024, 8); - internal STS GetImageInfo(out TW_IMAGEINFO info) - { - return WrapInSTS(DGImage.ImageInfo.Get(ref _appIdentity, ref _currentDS, out info)); - } - /// /// Start the transfer loop. @@ -70,7 +65,7 @@ namespace NTwain { do { - var readyArgs = new TransferReadyEventArgs(this, pending.Count, (TWEJ)pending.EOJ); + var readyArgs = new TransferReadyEventArgs(pending.Count, (TWEJ)pending.EOJ); _uiThreadMarshaller.Invoke((ref TW_PENDINGXFERS pending) => { try @@ -214,7 +209,9 @@ namespace NTwain { // assuming user already configured the transfer in transferready event, // get what will be transferred - DGControl.SetupFileXfer.Get(ref _appIdentity, ref _currentDS, out TW_SETUPFILEXFER fileSetup); + var rc = DGControl.SetupFileXfer.Get(ref _appIdentity, ref _currentDS, out TW_SETUPFILEXFER fileSetup); + if (rc != TWRC.SUCCESS) return WrapInSTS(rc); + // and just start it var sts = WrapInSTS(DGAudio.AudioFileXfer.Get(ref _appIdentity, ref _currentDS)); if (sts.RC == TWRC.XFERDONE) @@ -285,84 +282,78 @@ namespace NTwain private STS TransferMemoryImage(ref TW_PENDINGXFERS pending) { var rc = DGControl.SetupMemXfer.Get(ref _appIdentity, ref _currentDS, out TW_SETUPMEMXFER memSetup); - if (rc == TWRC.SUCCESS) + if (rc != TWRC.SUCCESS) return WrapInSTS(rc); + rc = DGImage.ImageInfo.Get(ref _appIdentity, ref _currentDS, out TW_IMAGEINFO info); + if (rc != TWRC.SUCCESS) return WrapInSTS(rc); + rc = DGImage.ImageLayout.Get(ref _appIdentity, ref _currentDS, out TW_IMAGELAYOUT layout); + if (rc != TWRC.SUCCESS) return WrapInSTS(rc); + + uint buffSize = memSetup.DetermineBufferSize(); + var memPtr = Alloc(buffSize); + + TW_IMAGEMEMXFER memXfer = TW_IMAGEMEMXFER.DONTCARE(); + TW_IMAGEMEMXFER_MACOSX memXferOSX = TW_IMAGEMEMXFER_MACOSX.DONTCARE(); + memXfer.Memory = new TW_MEMORY { - uint buffSize = memSetup.DetermineBufferSize(); - var memPtr = Alloc(buffSize); + Flags = (uint)(TWMF.APPOWNS | TWMF.POINTER), + Length = buffSize, + TheMem = memPtr + }; + memXferOSX.Memory = memXfer.Memory; - TW_IMAGEMEMXFER memXfer = new() + byte[] dotnetBuff = XferMemPool.Rent((int)buffSize); + try + { + do { - Memory = new TW_MEMORY - { - Flags = (uint)(TWMF.APPOWNS | TWMF.POINTER), - Length = buffSize, - TheMem = memPtr - } - }; - TW_IMAGEMEMXFER_MACOSX memXferOSX = new() - { - Memory = new TW_MEMORY - { - Flags = (uint)(TWMF.APPOWNS | TWMF.POINTER), - Length = buffSize, - TheMem = memPtr - } - }; + rc = TwainPlatform.IsMacOSX ? + DGImage.ImageMemXfer.Get(ref _appIdentity, ref _currentDS, ref memXferOSX) : + DGImage.ImageMemXfer.Get(ref _appIdentity, ref _currentDS, ref memXfer); - byte[] dotnetBuff = XferMemPool.Rent((int)buffSize); + if (rc == TWRC.SUCCESS || rc == TWRC.XFERDONE) + { + try + { + var written = TwainPlatform.IsMacOSX ? + memXferOSX.BytesWritten : memXfer.BytesWritten; + + IntPtr lockedPtr = Lock(memPtr); + + // assemble! + + //Marshal.Copy(lockedPtr, dotnetBuff, 0, (int)written); + //outStream.Write(dotnetBuff, 0, (int)written); + } + finally + { + Unlock(memPtr); + } + } + } while (rc == TWRC.SUCCESS); + } + finally + { + if (memPtr != IntPtr.Zero) Free(memPtr); + XferMemPool.Return(dotnetBuff); + } + + + if (rc == TWRC.XFERDONE) + { try { - do - { - rc = TwainPlatform.IsMacOSX ? - DGImage.ImageMemFileXfer.Get(ref _appIdentity, ref _currentDS, ref memXferOSX) : - DGImage.ImageMemFileXfer.Get(ref _appIdentity, ref _currentDS, ref memXfer); - - if (rc == TWRC.SUCCESS || rc == TWRC.XFERDONE) - { - try - { - var written = TwainPlatform.IsMacOSX ? - memXferOSX.BytesWritten : memXfer.BytesWritten; - - IntPtr lockedPtr = Lock(memPtr); - - // assemble! - - //Marshal.Copy(lockedPtr, dotnetBuff, 0, (int)written); - //outStream.Write(dotnetBuff, 0, (int)written); - } - finally - { - Unlock(memPtr); - } - } - } while (rc == TWRC.SUCCESS); + DGImage.ImageInfo.Get(ref _appIdentity, ref _currentDS, out info); + //var args = new DataTransferredEventArgs(info, null, outStream.ToArray()); + //DataTransferred?.Invoke(this, args); } - finally + catch { } + + var sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending)); + if (sts.RC == TWRC.SUCCESS) { - if (memPtr != IntPtr.Zero) Free(memPtr); - XferMemPool.Return(dotnetBuff); - } - - - if (rc == TWRC.XFERDONE) - { - try - { - GetImageInfo(out TW_IMAGEINFO info); - //var args = new DataTransferredEventArgs(info, null, outStream.ToArray()); - //DataTransferred?.Invoke(this, args); - } - catch { } - - var sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending)); - if (sts.RC == TWRC.SUCCESS) - { - State = pending.Count == 0 ? STATE.S5 : STATE.S6; - } - return sts; + State = pending.Count == 0 ? STATE.S5 : STATE.S6; } + return sts; } return WrapInSTS(rc); } @@ -370,94 +361,80 @@ namespace NTwain private STS TransferMemoryFileImage(ref TW_PENDINGXFERS pending) { var rc = DGControl.SetupFileXfer.Get(ref _appIdentity, ref _currentDS, out TW_SETUPFILEXFER fileSetup); - if (rc == TWRC.SUCCESS) + if (rc != TWRC.SUCCESS) return WrapInSTS(rc); + rc = DGControl.SetupMemXfer.Get(ref _appIdentity, ref _currentDS, out TW_SETUPMEMXFER memSetup); + if (rc != TWRC.SUCCESS) return WrapInSTS(rc); + + uint buffSize = memSetup.DetermineBufferSize(); + var memPtr = Alloc(buffSize); + + TW_IMAGEMEMXFER memXfer = TW_IMAGEMEMXFER.DONTCARE(); + TW_IMAGEMEMXFER_MACOSX memXferOSX = TW_IMAGEMEMXFER_MACOSX.DONTCARE(); + memXfer.Memory = new TW_MEMORY { - rc = DGControl.SetupMemXfer.Get(ref _appIdentity, ref _currentDS, out TW_SETUPMEMXFER memSetup); - if (rc == TWRC.SUCCESS) + Flags = (uint)(TWMF.APPOWNS | TWMF.POINTER), + Length = buffSize, + TheMem = memPtr + }; + memXferOSX.Memory = memXfer.Memory; + + // TODO: how to get actual file size before hand? Is it imagelayout? + // otherwise will just write to stream with lots of copies + byte[] dotnetBuff = XferMemPool.Rent((int)buffSize); + using var outStream = new MemoryStream(); + try + { + do { - uint buffSize = memSetup.DetermineBufferSize(); - var memPtr = Alloc(buffSize); + rc = TwainPlatform.IsMacOSX ? + DGImage.ImageMemFileXfer.Get(ref _appIdentity, ref _currentDS, ref memXferOSX) : + DGImage.ImageMemFileXfer.Get(ref _appIdentity, ref _currentDS, ref memXfer); - TW_IMAGEMEMXFER memXfer = new() - { - Memory = new TW_MEMORY - { - Flags = (uint)(TWMF.APPOWNS | TWMF.POINTER), - Length = buffSize, - TheMem = memPtr - } - }; - TW_IMAGEMEMXFER_MACOSX memXferOSX = new() - { - Memory = new TW_MEMORY - { - Flags = (uint)(TWMF.APPOWNS | TWMF.POINTER), - Length = buffSize, - TheMem = memPtr - } - }; - - - // TODO: how to get actual file size before hand? - // otherwise will just write to stream with lots of copies - byte[] dotnetBuff = XferMemPool.Rent((int)buffSize); - using var outStream = new MemoryStream(); - try - { - do - { - rc = TwainPlatform.IsMacOSX ? - DGImage.ImageMemFileXfer.Get(ref _appIdentity, ref _currentDS, ref memXferOSX) : - DGImage.ImageMemFileXfer.Get(ref _appIdentity, ref _currentDS, ref memXfer); - - if (rc == TWRC.SUCCESS || rc == TWRC.XFERDONE) - { - try - { - var written = TwainPlatform.IsMacOSX ? - memXferOSX.BytesWritten : memXfer.BytesWritten; - - IntPtr lockedPtr = Lock(memPtr); - Marshal.Copy(lockedPtr, dotnetBuff, 0, (int)written); - outStream.Write(dotnetBuff, 0, (int)written); - } - finally - { - Unlock(memPtr); - } - } - } while (rc == TWRC.SUCCESS); - } - finally - { - if (memPtr != IntPtr.Zero) Free(memPtr); - XferMemPool.Return(dotnetBuff); - } - - if (rc == TWRC.XFERDONE) + if (rc == TWRC.SUCCESS || rc == TWRC.XFERDONE) { try { - GetImageInfo(out TW_IMAGEINFO info); - // ToArray bypasses the XferMemPool but I guess this will have to do for now - var args = new DataTransferredEventArgs(info, fileSetup, outStream.ToArray()); - DataTransferred?.Invoke(this, args); - } - catch { } + var written = TwainPlatform.IsMacOSX ? + memXferOSX.BytesWritten : memXfer.BytesWritten; - var sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending)); - if (sts.RC == TWRC.SUCCESS) - { - State = pending.Count == 0 ? STATE.S5 : STATE.S6; + IntPtr lockedPtr = Lock(memPtr); + Marshal.Copy(lockedPtr, dotnetBuff, 0, (int)written); + outStream.Write(dotnetBuff, 0, (int)written); + } + finally + { + Unlock(memPtr); } - return sts; } + } while (rc == TWRC.SUCCESS); + } + finally + { + if (memPtr != IntPtr.Zero) Free(memPtr); + XferMemPool.Return(dotnetBuff); + } + + if (rc == TWRC.XFERDONE) + { + try + { + DGImage.ImageInfo.Get(ref _appIdentity, ref _currentDS, out TW_IMAGEINFO info); + // ToArray bypasses the XferMemPool but I guess this will have to do for now + var args = new DataTransferredEventArgs(info, fileSetup, outStream.ToArray()); + DataTransferred?.Invoke(this, args); } + catch { } + + var sts = WrapInSTS(DGControl.PendingXfers.EndXfer(ref _appIdentity, ref _currentDS, ref pending)); + if (sts.RC == TWRC.SUCCESS) + { + State = pending.Count == 0 ? STATE.S5 : STATE.S6; + } + return sts; } return WrapInSTS(rc); } - private STS TransferFileImage(ref TW_PENDINGXFERS pending) { // assuming user already configured the transfer in transferready event, @@ -470,7 +447,7 @@ namespace NTwain State = STATE.S7; try { - GetImageInfo(out TW_IMAGEINFO info); + DGImage.ImageInfo.Get(ref _appIdentity, ref _currentDS, out TW_IMAGEINFO info); var args = new DataTransferredEventArgs(info, fileSetup, null); DataTransferred?.Invoke(this, args); } @@ -517,7 +494,7 @@ namespace NTwain { try { - GetImageInfo(out TW_IMAGEINFO info); + DGImage.ImageInfo.Get(ref _appIdentity, ref _currentDS, out TW_IMAGEINFO info); var args = new DataTransferredEventArgs(info, null, data); DataTransferred?.Invoke(this, args); }