From f861cd8c6022a60267d4c8a49fbdb06c51993dcc Mon Sep 17 00:00:00 2001 From: soukoku Date: Thu, 10 Apr 2014 07:30:00 -0400 Subject: [PATCH] Updated string read and fixed sample. --- NTwain/Data/CapReadOut.cs | 29 +++-- NTwain/DataTransferredEventArgs.cs | 41 +++--- NTwain/NTwain.nuspec | 2 +- NTwain/TransferReadyEventArgs.cs | 2 +- .../Triplets/DGImage/DGImage.ExtImageInfo.cs | 5 +- NTwain/Triplets/PInvoke.cs | 4 + NTwain/TwainSession.cs | 122 +++++++++++++++++- NTwain/TwainSessionOld.cs | 2 +- .../DataTransferredEventArgsTests.cs | 26 ---- Tests/NTwain.Tests/NTwain.Tests.csproj | 3 - Tests/Tester.Console/Program.cs | 2 +- Tests/Tester.WPF/TwainVM.cs | 4 +- Tests/Tester.Winform/TestForm.cs | 12 +- 13 files changed, 175 insertions(+), 79 deletions(-) delete mode 100644 Tests/NTwain.Tests/DataTransferredEventArgsTests.cs diff --git a/NTwain/Data/CapReadOut.cs b/NTwain/Data/CapReadOut.cs index 1bd001f..bfd90a7 100644 --- a/NTwain/Data/CapReadOut.cs +++ b/NTwain/Data/CapReadOut.cs @@ -266,16 +266,16 @@ namespace NTwain.Data frame.Bottom = (TWFix32)ReadValue(baseAddr, ref offset, ItemType.Fix32); return frame; // no need to update offset again after reading fix32 case ItemType.String128: - val = ReadString(baseAddr, offset, 128); + val = ReadString(baseAddr, offset, TwainConst.String128 - 2); break; case ItemType.String255: - val = ReadString(baseAddr, offset, 255); + val = ReadString(baseAddr, offset, TwainConst.String255 - 1); break; case ItemType.String32: - val = ReadString(baseAddr, offset, 32); + val = ReadString(baseAddr, offset, TwainConst.String32 - 2); break; case ItemType.String64: - val = ReadString(baseAddr, offset, 64); + val = ReadString(baseAddr, offset, TwainConst.String64 - 2); break; case ItemType.Handle: val = new IntPtr(baseAddr.ToInt64() + offset); @@ -294,16 +294,21 @@ namespace NTwain.Data /// static string ReadString(IntPtr baseAddr, int offset, int maxLength) { - // todo: add support for other platform - - var sb = new StringBuilder(maxLength); - byte bt; - while (sb.Length < maxLength && - (bt = Marshal.ReadByte(baseAddr, offset++)) != 0) + // does this work cross-platform? + var val = Marshal.PtrToStringAnsi(new IntPtr(baseAddr.ToInt64() + offset)); + if (val.Length > maxLength) { - sb.Append((char)bt); + // bad source, whatever } - return sb.ToString(); + return val; + //var sb = new StringBuilder(maxLength); + //byte bt; + //while (sb.Length < maxLength && + // (bt = Marshal.ReadByte(baseAddr, offset++)) != 0) + //{ + // sb.Append((char)bt); + //} + //return sb.ToString(); } diff --git a/NTwain/DataTransferredEventArgs.cs b/NTwain/DataTransferredEventArgs.cs index ef48570..01c7e72 100644 --- a/NTwain/DataTransferredEventArgs.cs +++ b/NTwain/DataTransferredEventArgs.cs @@ -1,4 +1,5 @@ -using System; +using NTwain.Data; +using System; namespace NTwain { @@ -8,30 +9,36 @@ namespace NTwain public class DataTransferredEventArgs : EventArgs { /// - /// Initializes a new instance of the class. - /// - /// The data pointer. - /// The file. - internal DataTransferredEventArgs(IntPtr data, string filePath) - { - Data = data; - FilePath = filePath; - } - /// - /// Gets pointer to the image data if applicable. + /// Gets pointer to the complete data if the transfer was native. /// The data will be freed once the event handler ends - /// so consumers must complete whatever processing - /// required by then. + /// so consumers must complete whatever processing before then. + /// For image type this data is DIB (Windows), PICT (old Mac), and TIFF (Linux/OSX). /// /// The data pointer. - public IntPtr Data { get; private set; } + public IntPtr NativeData { get; internal set; } /// - /// Gets the filepath to the transferrerd data if applicable. + /// Gets the file path to the complete data if the transfer was file or memory-file. /// /// /// The file. /// - public string FilePath { get; private set; } + public string FilePath { get; internal set; } + + /// + /// Gets the memory data if the transfer was memory. + /// + /// + /// The memory data. + /// + public byte[] MemData { get; internal set; } + + /// + /// Gets the final image information if applicable. + /// + /// + /// The final image information. + /// + public TWImageInfo FinalImageInfo { get; internal set; } } } \ No newline at end of file diff --git a/NTwain/NTwain.nuspec b/NTwain/NTwain.nuspec index 979366d..b372e47 100644 --- a/NTwain/NTwain.nuspec +++ b/NTwain/NTwain.nuspec @@ -11,7 +11,7 @@ false $description$ - V0.9 release is updated for TWAIN 2.3 and contains some refactoring that may require updating existing code. + This release supports TWAIN 2.3. $copyright$ twain scan diff --git a/NTwain/TransferReadyEventArgs.cs b/NTwain/TransferReadyEventArgs.cs index 73c7e41..639a11c 100644 --- a/NTwain/TransferReadyEventArgs.cs +++ b/NTwain/TransferReadyEventArgs.cs @@ -39,7 +39,7 @@ namespace NTwain /// /// Gets the tentative image information for the current transfer if applicable. - /// This may differ from the final image depending on the transfer mode used. + /// This may differ from the final image depending on the transfer mode used (mostly when doing mem xfer). /// /// /// The image info. diff --git a/NTwain/Triplets/DGImage/DGImage.ExtImageInfo.cs b/NTwain/Triplets/DGImage/DGImage.ExtImageInfo.cs index bffedb4..64115fe 100644 --- a/NTwain/Triplets/DGImage/DGImage.ExtImageInfo.cs +++ b/NTwain/Triplets/DGImage/DGImage.ExtImageInfo.cs @@ -11,10 +11,11 @@ namespace NTwain.Triplets { internal ExtImageInfo(ITwainStateInternal session) : base(session) { } - public ReturnCode Get(TWExtImageInfo info) + public ReturnCode Get(out TWExtImageInfo info) { Session.VerifyState(7, 7, DataGroups.Image, DataArgumentType.ExtImageInfo, Message.Get); - return PInvoke.DsmEntry(Session.GetAppId(), Session.SourceId, Message.Get, info); + info = new TWExtImageInfo(); + return PInvoke.DsmEntry(Session.GetAppId(), Session.SourceId, Message.Get, info); } } } \ No newline at end of file diff --git a/NTwain/Triplets/PInvoke.cs b/NTwain/Triplets/PInvoke.cs index 1d5aa00..100621c 100644 --- a/NTwain/Triplets/PInvoke.cs +++ b/NTwain/Triplets/PInvoke.cs @@ -31,6 +31,10 @@ namespace NTwain.Triplets File.Exists(path); } + static readonly bool IsWin = Environment.OSVersion.Platform == PlatformID.Win32NT; + static readonly bool IsOSX = Environment.OSVersion.Platform == PlatformID.MacOSX; + static readonly bool IsLinux = Environment.OSVersion.Platform == PlatformID.Unix; + // define sig for each different data type since "object" doesn't work #region wrapped calls diff --git a/NTwain/TwainSession.cs b/NTwain/TwainSession.cs index 1d997a1..250eeae 100644 --- a/NTwain/TwainSession.cs +++ b/NTwain/TwainSession.cs @@ -37,6 +37,7 @@ namespace NTwain object _callbackObj; // kept around so it doesn't get gc'ed TWUserInterface _twui; + static readonly CapabilityId[] _emptyCapList = new CapabilityId[0]; private IList _supportedCaps; /// @@ -53,7 +54,7 @@ namespace NTwain { _supportedCaps = this.GetCapabilities(); } - return _supportedCaps ?? new CapabilityId[0]; + return _supportedCaps ?? _emptyCapList; } private set { @@ -289,6 +290,7 @@ namespace NTwain if (rc == ReturnCode.Success) { _callbackObj = null; + SupportedCaps = null; } return rc; } @@ -776,7 +778,7 @@ namespace NTwain { lockedPtr = MemoryManager.Instance.Lock(dataPtr); } - OnDataTransferred(new DataTransferredEventArgs(lockedPtr, null)); + OnDataTransferred(new DataTransferredEventArgs { NativeData = lockedPtr }); } } finally @@ -808,7 +810,7 @@ namespace NTwain var xrc = DGAudio.AudioFileXfer.Get(); if (xrc == ReturnCode.XferDone) { - OnDataTransferred(new DataTransferredEventArgs(IntPtr.Zero, filePath)); + OnDataTransferred(new DataTransferredEventArgs { FilePath = filePath }); } } @@ -826,11 +828,16 @@ namespace NTwain if (xrc == ReturnCode.XferDone) { State = 7; + TWImageInfo imgInfo; + if (DGImage.ImageInfo.Get(out imgInfo) != ReturnCode.Success) + { + imgInfo = null; + } if (dataPtr != IntPtr.Zero) { lockedPtr = MemoryManager.Instance.Lock(dataPtr); } - OnDataTransferred(new DataTransferredEventArgs(lockedPtr, null)); + OnDataTransferred(new DataTransferredEventArgs { NativeData = lockedPtr, FinalImageInfo = imgInfo }); } } finally @@ -862,13 +869,93 @@ namespace NTwain var xrc = DGImage.ImageFileXfer.Get(); if (xrc == ReturnCode.XferDone) { - OnDataTransferred(new DataTransferredEventArgs(IntPtr.Zero, filePath)); + TWImageInfo imgInfo; + if (DGImage.ImageInfo.Get(out imgInfo) != ReturnCode.Success) + { + imgInfo = null; + } + OnDataTransferred(new DataTransferredEventArgs { FilePath = filePath, FinalImageInfo = imgInfo }); } } private void DoImageMemoryXfer() { throw new NotImplementedException(); + + TWSetupMemXfer memInfo; + if (DGControl.SetupMemXfer.Get(out memInfo) == ReturnCode.Success) + { + TWImageMemXfer xferInfo = new TWImageMemXfer(); + try + { + xferInfo.Memory = new TWMemory + { + Flags = MemoryFlags.AppOwns | MemoryFlags.Pointer, + Length = memInfo.Preferred, + TheMem = MemoryManager.Instance.Allocate(memInfo.Preferred) + }; + + var xrc = ReturnCode.Success; + do + { + xrc = DGImage.ImageMemFileXfer.Get(xferInfo); + + if (xrc == ReturnCode.Success || + xrc == ReturnCode.XferDone) + { + State = 7; + byte[] buffer = new byte[(int)xferInfo.BytesWritten]; + // todo: need lock before use? + IntPtr lockPtr = IntPtr.Zero; + try + { + lockPtr = MemoryManager.Instance.Lock(xferInfo.Memory.TheMem); + Marshal.Copy(lockPtr, buffer, 0, buffer.Length); + } + finally + { + if (lockPtr != IntPtr.Zero) + { + MemoryManager.Instance.Unlock(lockPtr); + } + } + // now what? + + } + } while (xrc == ReturnCode.Success); + + if (xrc == ReturnCode.XferDone) + { + TWImageInfo imgInfo; + //TWExtImageInfo extInfo; + //if (SupportedCaps.Contains(CapabilityId.ICapExtImageInfo)) + //{ + // if (DGImage.ExtImageInfo.Get(out extInfo) != ReturnCode.Success) + // { + // extInfo = null; + // } + //} + if (DGImage.ImageInfo.Get(out imgInfo) == ReturnCode.Success) + { + //OnDataTransferred(new DataTransferredEventArgs(IntPtr.Zero, null)); + } + else + { + Trace.TraceError("Failed to get image info after ImageMemXfer."); + imgInfo = null; + } + } + } + finally + { + State = 6; + if (xferInfo.Memory.TheMem != IntPtr.Zero) + { + MemoryManager.Instance.Free(xferInfo.Memory.TheMem); + } + } + + } } private void DoImageMemoryFileXfer() @@ -886,6 +973,7 @@ namespace NTwain { xferInfo.Memory = new TWMemory { + Flags = MemoryFlags.AppOwns | MemoryFlags.Pointer, Length = memInfo.Preferred, TheMem = MemoryManager.Instance.Allocate(memInfo.Preferred) }; @@ -900,8 +988,22 @@ namespace NTwain if (xrc == ReturnCode.Success || xrc == ReturnCode.XferDone) { + State = 7; byte[] buffer = new byte[(int)xferInfo.BytesWritten]; - Marshal.Copy(xferInfo.Memory.TheMem, buffer, 0, buffer.Length); + // todo: need lock before use? + IntPtr lockPtr = IntPtr.Zero; + try + { + lockPtr = MemoryManager.Instance.Lock(xferInfo.Memory.TheMem); + Marshal.Copy(lockPtr, buffer, 0, buffer.Length); + } + finally + { + if (lockPtr != IntPtr.Zero) + { + MemoryManager.Instance.Unlock(lockPtr); + } + } outStream.Write(buffer, 0, buffer.Length); } } while (xrc == ReturnCode.Success); @@ -962,6 +1064,7 @@ namespace NTwain } finally { + State = 6; if (xferInfo.Memory.TheMem != IntPtr.Zero) { MemoryManager.Instance.Free(xferInfo.Memory.TheMem); @@ -974,7 +1077,12 @@ namespace NTwain if (File.Exists(finalFile)) { - OnDataTransferred(new DataTransferredEventArgs(IntPtr.Zero, finalFile)); + TWImageInfo imgInfo; + if (DGImage.ImageInfo.Get(out imgInfo) != ReturnCode.Success) + { + imgInfo = null; + } + OnDataTransferred(new DataTransferredEventArgs { FilePath = finalFile, FinalImageInfo = imgInfo }); } } } diff --git a/NTwain/TwainSessionOld.cs b/NTwain/TwainSessionOld.cs index ba95e8b..9c157f0 100644 --- a/NTwain/TwainSessionOld.cs +++ b/NTwain/TwainSessionOld.cs @@ -120,7 +120,7 @@ namespace NTwain { lockedPtr = MemoryManager.Instance.Lock(dataPtr); } - OnDataTransferred(new DataTransferredEventArgs(lockedPtr, file)); + OnDataTransferred(new DataTransferredEventArgs { NativeData = lockedPtr, FilePath = file }); } //} //else if (group == DataGroups.Audio) diff --git a/Tests/NTwain.Tests/DataTransferredEventArgsTests.cs b/Tests/NTwain.Tests/DataTransferredEventArgsTests.cs deleted file mode 100644 index 3162e26..0000000 --- a/Tests/NTwain.Tests/DataTransferredEventArgsTests.cs +++ /dev/null @@ -1,26 +0,0 @@ -using NTwain; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using NTwain.Values; -using System.Runtime.Serialization; - -namespace NTwain.Tests -{ - [TestClass] - public class DataTransferredEventArgsTests - { - [TestMethod] - public void Constructor_Sets_Correct_Properties() - { - // just some non-default values to test - IntPtr data = new IntPtr(10); - string file = "THIS IS A TEST."; - - DataTransferredEventArgs target = new DataTransferredEventArgs(data, file); - - Assert.AreEqual(data, target.Data, "Data mismatch."); - Assert.AreEqual(file, target.FilePath, "File mismatch."); - } - - } -} diff --git a/Tests/NTwain.Tests/NTwain.Tests.csproj b/Tests/NTwain.Tests/NTwain.Tests.csproj index 0c2815e..75cdb9f 100644 --- a/Tests/NTwain.Tests/NTwain.Tests.csproj +++ b/Tests/NTwain.Tests/NTwain.Tests.csproj @@ -54,9 +54,6 @@ - - Code - Code diff --git a/Tests/Tester.Console/Program.cs b/Tests/Tester.Console/Program.cs index e9444f0..0ed4cb6 100644 --- a/Tests/Tester.Console/Program.cs +++ b/Tests/Tester.Console/Program.cs @@ -93,7 +93,7 @@ namespace Tester static void twain_DataTransferred(object sender, DataTransferredEventArgs e) { - if (e.Data != IntPtr.Zero) + if (e.NativeData != IntPtr.Zero) { Console.WriteLine("Got twain data on thread {0}", Thread.CurrentThread.ManagedThreadId); } diff --git a/Tests/Tester.WPF/TwainVM.cs b/Tests/Tester.WPF/TwainVM.cs index 3951a71..150dcbb 100644 --- a/Tests/Tester.WPF/TwainVM.cs +++ b/Tests/Tester.WPF/TwainVM.cs @@ -63,9 +63,9 @@ namespace Tester.WPF protected override void OnDataTransferred(DataTransferredEventArgs e) { - if (e.Data != IntPtr.Zero) + if (e.NativeData != IntPtr.Zero) { - Image = e.Data.GetWPFBitmap(); + Image = e.NativeData.GetWPFBitmap(); } else if (!string.IsNullOrEmpty(e.FilePath)) { diff --git a/Tests/Tester.Winform/TestForm.cs b/Tests/Tester.Winform/TestForm.cs index d5929c1..e37f343 100644 --- a/Tests/Tester.Winform/TestForm.cs +++ b/Tests/Tester.Winform/TestForm.cs @@ -69,10 +69,10 @@ namespace Tester.Winform pictureBox1.Image.Dispose(); pictureBox1.Image = null; } - if (e.Data != IntPtr.Zero) + if (e.NativeData != IntPtr.Zero) { //_ptrTest = e.Data; - var img = e.Data.GetDrawingBitmap(); + var img = e.NativeData.GetDrawingBitmap(); if (img != null) pictureBox1.Image = img; } @@ -284,7 +284,7 @@ namespace Tester.Winform { var list = _twain.CapGetSupportedSizes(); comboSize.DataSource = list; - var cur = _twain.GetCurrentCap(CapabilityId.ICapSupportedSizes); + var cur = _twain.GetCurrentCap(CapabilityId.ICapSupportedSizes).ConvertToEnum(); if (list.Contains(cur)) { comboSize.SelectedItem = cur; @@ -293,7 +293,7 @@ namespace Tester.Winform private void LoadDuplex() { - ckDuplex.Checked = _twain.GetCurrentCap(CapabilityId.CapDuplexEnabled) != 0; + ckDuplex.Checked = _twain.GetCurrentCap(CapabilityId.CapDuplexEnabled).ConvertToEnum() != 0; } private void LoadDPI() @@ -301,7 +301,7 @@ namespace Tester.Winform // only allow dpi of certain values for those source that lists everything var list = _twain.CapGetDPIs().Where(dpi => (dpi % 50) == 0).ToList(); comboDPI.DataSource = list; - var cur = _twain.GetCurrentCap(CapabilityId.ICapXResolution); + var cur = (TWFix32)_twain.GetCurrentCap(CapabilityId.ICapXResolution); if (list.Contains(cur)) { comboDPI.SelectedItem = cur; @@ -312,7 +312,7 @@ namespace Tester.Winform { var list = _twain.CapGetPixelTypes(); comboDepth.DataSource = list; - var cur = _twain.GetCurrentCap(CapabilityId.ICapPixelType); + var cur = _twain.GetCurrentCap(CapabilityId.ICapPixelType).ConvertToEnum(); if (list.Contains(cur)) { comboDepth.SelectedItem = cur;