From 4c3e2a50b33fd08b6c34e7933900f9e7b7d61df8 Mon Sep 17 00:00:00 2001 From: soukoku Date: Sat, 5 Apr 2014 21:54:08 -0400 Subject: [PATCH] Updated samples to new twain sessions. --- NTwain/NTwain.csproj | 2 +- .../{TwainSessionBase.cs => TwainSession.cs} | 170 +++++++++++++++++- NTwain/TwainSessionExtensions.cs | 46 ++--- NTwain/TwainSessionOld.cs | 2 +- NTwain/TwainSessionWPF.cs | 2 +- NTwain/TwainSessionWinform.cs | 2 +- Tests/Tester.WPF/MainWindow.xaml.cs | 15 +- Tests/Tester.Winform/TestForm.cs | 9 +- 8 files changed, 197 insertions(+), 51 deletions(-) rename NTwain/{TwainSessionBase.cs => TwainSession.cs} (77%) diff --git a/NTwain/NTwain.csproj b/NTwain/NTwain.csproj index 769302c..22bc771 100644 --- a/NTwain/NTwain.csproj +++ b/NTwain/NTwain.csproj @@ -75,7 +75,7 @@ - + diff --git a/NTwain/TwainSessionBase.cs b/NTwain/TwainSession.cs similarity index 77% rename from NTwain/TwainSessionBase.cs rename to NTwain/TwainSession.cs index eca15d9..baabea5 100644 --- a/NTwain/TwainSessionBase.cs +++ b/NTwain/TwainSession.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; +using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; @@ -13,16 +14,16 @@ using System.Threading; namespace NTwain { /// - /// Base class for interfacing with TWAIN. + /// Basic class for interfacing with TWAIN. /// - public class TwainSessionBase : ITwainStateInternal, ITwainOperation + public class TwainSession : ITwainStateInternal, ITwainOperation { /// /// Initializes a new instance of the class. /// /// The app id. /// - public TwainSessionBase(TWIdentity appId) + public TwainSession(TWIdentity appId) { if (appId == null) { throw new ArgumentNullException("appId"); } _appId = appId; @@ -578,6 +579,7 @@ namespace NTwain evt.pEvent = msgPtr; if (handled = DGControl.Event.ProcessEvent(evt) == ReturnCode.DSEvent) { + Debug.WriteLine(string.Format("Thread {0}: HandleWndProcMessage at state {1} with MSG={2}.", Thread.CurrentThread.ManagedThreadId, State, evt.TWMessage)); HandleSourceMsg(evt.TWMessage); } } @@ -593,7 +595,7 @@ namespace NTwain { if (origin != null && SourceId != null && origin.Id == SourceId.Id) { - Debug.WriteLine(string.Format("Thread {0}: CallbackHandler at state {1} with DG={2} DAT={3} MSG={4}.", Thread.CurrentThread.ManagedThreadId, State, dg, dat, msg)); + Debug.WriteLine(string.Format("Thread {0}: CallbackHandler at state {1} with MSG={2}.", Thread.CurrentThread.ManagedThreadId, State, msg)); // spec says we must handle this on the thread that enabled the DS, // but it's usually already the same thread and doesn't work (failure + seqError) w/o jumping to another thread and back. // My guess is the DS needs to see the Success return code first before letting transfer happen @@ -624,8 +626,6 @@ namespace NTwain // method that handles msg from the source, whether it's from wndproc or callbacks void HandleSourceMsg(Message msg) { - Debug.WriteLine(string.Format("Thread {0}: HandleSourceMsg at state {1} with MSG={2}.", Thread.CurrentThread.ManagedThreadId, State, msg)); - switch (msg) { case Message.XferReady: @@ -665,10 +665,164 @@ namespace NTwain /// /// Does the TWAIN transfer routine at state 6. /// - /// protected virtual void DoTransferRoutine() { - throw new NotImplementedException(); + TWPendingXfers pending = new TWPendingXfers(); + var rc = ReturnCode.Success; + + do + { + IList formats = Enumerable.Empty().ToList(); + IList compressions = Enumerable.Empty().ToList(); + bool canDoFileXfer = this.CapGetImageXferMech().Contains(XferMech.File); + var curFormat = this.GetCurrentCap(CapabilityId.ICapImageFileFormat); + var curComp = this.GetCurrentCap(CapabilityId.ICapCompression); + TWImageInfo imgInfo; + bool skip = false; + if (DGImage.ImageInfo.Get(out imgInfo) != ReturnCode.Success) + { + // bad! + skip = true; + } + + try + { + formats = this.CapGetImageFileFormat(); + } + catch { } + try + { + compressions = this.CapGetCompression(); + } + catch { } + + // ask consumer for cancel in case of non-ui multi-page transfers + TransferReadyEventArgs args = new TransferReadyEventArgs(pending, formats, curFormat, compressions, + curComp, canDoFileXfer, imgInfo); + args.CancelCurrent = skip; + + OnTransferReady(args); + + + if (!args.CancelAll && !args.CancelCurrent) + { + Values.XferMech mech = this.GetCurrentCap(CapabilityId.ICapXferMech); + + if (args.CanDoFileXfer && !string.IsNullOrEmpty(args.OutputFile)) + { + var setXferRC = DGControl.SetupFileXfer.Set(new TWSetupFileXfer + { + FileName = args.OutputFile, + Format = args.ImageFormat + }); + if (setXferRC == ReturnCode.Success) + { + mech = XferMech.File; + } + } + + // I don't know how this is supposed to work so it probably doesn't + //this.CapSetImageFormat(args.ImageFormat); + //this.CapSetImageCompression(args.ImageCompression); + + #region do xfer + + // TODO: expose all swallowed exceptions somehow later + + IntPtr dataPtr = IntPtr.Zero; + IntPtr lockedPtr = IntPtr.Zero; + string file = null; + try + { + ReturnCode xrc = ReturnCode.Cancel; + switch (mech) + { + case Values.XferMech.Native: + xrc = DGImage.ImageNativeXfer.Get(ref dataPtr); + break; + case Values.XferMech.File: + xrc = DGImage.ImageFileXfer.Get(); + if (File.Exists(args.OutputFile)) + { + file = args.OutputFile; + } + break; + case Values.XferMech.MemFile: + // not supported yet + //TWImageMemXfer memxfer = new TWImageMemXfer(); + //xrc = DGImage.ImageMemXfer.Get(memxfer); + break; + } + if (xrc == ReturnCode.XferDone) + { + State = 7; + if (dataPtr != IntPtr.Zero) + { + lockedPtr = MemoryManager.Instance.Lock(dataPtr); + } + OnDataTransferred(new DataTransferredEventArgs(lockedPtr, file)); + } + //} + //else if (group == DataGroups.Audio) + //{ + // var xrc = DGAudio.AudioNativeXfer.Get(ref dataPtr); + // if (xrc == ReturnCode.XferDone) + // { + // State = 7; + // try + // { + // var dtHand = DataTransferred; + // if (dtHand != null) + // { + // lockedPtr = MemoryManager.Instance.MemLock(dataPtr); + // dtHand(this, new DataTransferredEventArgs(lockedPtr)); + // } + // } + // catch { } + // } + //} + } + finally + { + State = 6; + // data here is allocated by source so needs to use shared mem calls + if (lockedPtr != IntPtr.Zero) + { + MemoryManager.Instance.Unlock(lockedPtr); + lockedPtr = IntPtr.Zero; + } + if (dataPtr != IntPtr.Zero) + { + MemoryManager.Instance.Free(dataPtr); + dataPtr = IntPtr.Zero; + } + } + #endregion + } + + if (args.CancelAll) + { + rc = DGControl.PendingXfers.Reset(pending); + if (rc == ReturnCode.Success) + { + // if audio exit here + //if (group == DataGroups.Audio) + //{ + // //??? + // return; + //} + + } + } + else + { + rc = DGControl.PendingXfers.EndXfer(pending); + } + } while (rc == ReturnCode.Success && pending.Count != 0); + + State = 5; + DisableSource(); + } #endregion diff --git a/NTwain/TwainSessionExtensions.cs b/NTwain/TwainSessionExtensions.cs index e21d54b..6f236ff 100644 --- a/NTwain/TwainSessionExtensions.cs +++ b/NTwain/TwainSessionExtensions.cs @@ -18,7 +18,7 @@ namespace NTwain /// /// The session. /// - public static TWStatus GetManagerStatus(this TwainSessionBase session) + public static TWStatus GetManagerStatus(this TwainSession session) { TWStatus stat; session.DGControl.Status.GetManager(out stat); @@ -29,7 +29,7 @@ namespace NTwain /// /// The session. /// - public static TWStatus GetSourceStatus(this TwainSessionBase session) + public static TWStatus GetSourceStatus(this TwainSession session) { TWStatus stat; session.DGControl.Status.GetSource(out stat); @@ -42,7 +42,7 @@ namespace NTwain /// /// The session. /// - public static IList GetSources(this TwainSessionBase session) + public static IList GetSources(this TwainSession session) { List list = new List(); @@ -93,7 +93,7 @@ namespace NTwain /// The session. /// The cap id. /// - public static T GetCurrentCap(this TwainSessionBase session, CapabilityId capId) where T : struct,IConvertible + public static T GetCurrentCap(this TwainSession session, CapabilityId capId) where T : struct,IConvertible { using (TWCapability cap = new TWCapability(capId)) { @@ -237,7 +237,7 @@ namespace NTwain /// The capability unique identifier. /// if set to true then apply to workaround for certain bad sources. /// - public static IList GetCapabilityValues(this TwainSessionBase session, CapabilityId capabilityId, bool tryUpperWord) where TCapVal : struct,IConvertible + public static IList GetCapabilityValues(this TwainSession session, CapabilityId capabilityId, bool tryUpperWord) where TCapVal : struct,IConvertible { var list = new List(); using (TWCapability cap = new TWCapability(capabilityId)) @@ -257,7 +257,7 @@ namespace NTwain /// /// The session. /// - internal static IList GetCapabilities(this TwainSessionBase session) + internal static IList GetCapabilities(this TwainSession session) { return session.GetCapabilityValues(CapabilityId.CapSupportedCaps, false); } @@ -270,7 +270,7 @@ namespace NTwain /// /// The session. /// - public static IList CapGetImageXferMech(this TwainSessionBase session) + public static IList CapGetImageXferMech(this TwainSession session) { return session.GetCapabilityValues(CapabilityId.ICapXferMech, true); } @@ -285,7 +285,7 @@ namespace NTwain /// /// The session. /// - public static IList CapGetCompression(this TwainSessionBase session) + public static IList CapGetCompression(this TwainSession session) { return session.GetCapabilityValues(CapabilityId.ICapCompression, true); } @@ -296,7 +296,7 @@ namespace NTwain /// The session. /// The compression. /// - public static ReturnCode CapSetImageCompression(this TwainSessionBase session, Compression compression) + public static ReturnCode CapSetImageCompression(this TwainSession session, Compression compression) { using (TWCapability compressCap = new TWCapability(CapabilityId.ICapCompression, new TWOneValue { Item = (uint)compression, ItemType = Values.ItemType.UInt16 })) { @@ -314,7 +314,7 @@ namespace NTwain /// /// The session. /// - public static IList CapGetImageFileFormat(this TwainSessionBase session) + public static IList CapGetImageFileFormat(this TwainSession session) { return session.GetCapabilityValues(CapabilityId.ICapImageFileFormat, true); } @@ -325,7 +325,7 @@ namespace NTwain /// The session. /// The format. /// - public static ReturnCode CapSetImageFormat(this TwainSessionBase session, FileFormat format) + public static ReturnCode CapSetImageFormat(this TwainSession session, FileFormat format) { using (TWCapability formatCap = new TWCapability(CapabilityId.ICapImageFileFormat, new TWOneValue { Item = (uint)format, ItemType = Values.ItemType.UInt16 })) { @@ -343,7 +343,7 @@ namespace NTwain /// /// The session. /// - public static IList CapGetPixelTypes(this TwainSessionBase session) + public static IList CapGetPixelTypes(this TwainSession session) { return session.GetCapabilityValues(CapabilityId.ICapPixelType, true); } @@ -354,7 +354,7 @@ namespace NTwain /// The session. /// The type. /// - public static ReturnCode CapSetPixelType(this TwainSessionBase session, PixelType type) + public static ReturnCode CapSetPixelType(this TwainSession session, PixelType type) { var one = new TWOneValue(); one.Item = (uint)type; @@ -375,7 +375,7 @@ namespace NTwain /// /// The session. /// - public static IList CapGetDPIs(this TwainSessionBase session) + public static IList CapGetDPIs(this TwainSession session) { return session.GetCapabilityValues(CapabilityId.ICapXResolution, true); } @@ -386,7 +386,7 @@ namespace NTwain /// The session. /// The DPI. /// - public static ReturnCode CapSetDPI(this TwainSessionBase session, int dpi) + public static ReturnCode CapSetDPI(this TwainSession session, int dpi) { return CapSetDPI(session, dpi, dpi); } @@ -398,7 +398,7 @@ namespace NTwain /// The x DPI. /// The y DPI. /// - public static ReturnCode CapSetDPI(this TwainSessionBase session, int xDPI, int yDPI) + public static ReturnCode CapSetDPI(this TwainSession session, int xDPI, int yDPI) { TWOneValue one = new TWOneValue(); one.Item = (uint)xDPI;// ((uint)dpi) << 16; @@ -429,7 +429,7 @@ namespace NTwain /// /// The session. /// - public static IList CapGetSupportedSizes(this TwainSessionBase session) + public static IList CapGetSupportedSizes(this TwainSession session) { return session.GetCapabilityValues(CapabilityId.ICapSupportedSizes, true); } @@ -440,7 +440,7 @@ namespace NTwain /// The session. /// The size. /// - public static ReturnCode CapSetSupportedSize(this TwainSessionBase session, SupportedSize size) + public static ReturnCode CapSetSupportedSize(this TwainSession session, SupportedSize size) { var one = new TWOneValue(); one.Item = (uint)size; @@ -463,7 +463,7 @@ namespace NTwain /// The session. /// if set to true [use it]. /// - public static ReturnCode CapSetAutoDeskew(this TwainSessionBase session, bool useIt) + public static ReturnCode CapSetAutoDeskew(this TwainSession session, bool useIt) { var rc = ReturnCode.Failure; if (session.SupportedCaps.Contains(CapabilityId.ICapAutomaticDeskew)) @@ -503,7 +503,7 @@ namespace NTwain /// The session. /// if set to true [use it]. /// - public static ReturnCode CapSetAutoRotate(this TwainSessionBase session, bool useIt) + public static ReturnCode CapSetAutoRotate(this TwainSession session, bool useIt) { var rc = ReturnCode.Failure; if (session.SupportedCaps.Contains(CapabilityId.ICapAutomaticRotate)) @@ -541,7 +541,7 @@ namespace NTwain /// The session. /// if set to true [use it]. /// - public static ReturnCode CapSetBorderDetection(this TwainSessionBase session, bool useIt) + public static ReturnCode CapSetBorderDetection(this TwainSession session, bool useIt) { var rc = ReturnCode.Failure; if (session.SupportedCaps.Contains(CapabilityId.ICapAutomaticBorderDetection)) @@ -589,7 +589,7 @@ namespace NTwain /// The session. /// if set to true [use it]. /// - public static ReturnCode CapSetDuplex(this TwainSessionBase session, bool useIt) + public static ReturnCode CapSetDuplex(this TwainSession session, bool useIt) { if (session.SourceId.ProtocolMajor >= 2) { @@ -623,7 +623,7 @@ namespace NTwain /// The session. /// if set to true [use it]. /// - public static ReturnCode CapSetFeeder(this TwainSessionBase session, bool useIt) + public static ReturnCode CapSetFeeder(this TwainSession session, bool useIt) { var rc = ReturnCode.Failure; if (session.SupportedCaps.Contains(CapabilityId.CapFeederEnabled)) diff --git a/NTwain/TwainSessionOld.cs b/NTwain/TwainSessionOld.cs index 9217cf7..131d995 100644 --- a/NTwain/TwainSessionOld.cs +++ b/NTwain/TwainSessionOld.cs @@ -20,7 +20,7 @@ namespace NTwain /// This is the old implementation for reference purposes only. /// [Obsolete("For reference purposes only.")] - public class TwainSessionOld : TwainSessionBase, IMessageFilter + public class TwainSessionOld : TwainSession, IMessageFilter { /// /// Initializes a new instance of the class. diff --git a/NTwain/TwainSessionWPF.cs b/NTwain/TwainSessionWPF.cs index f8b8b72..1deef70 100644 --- a/NTwain/TwainSessionWPF.cs +++ b/NTwain/TwainSessionWPF.cs @@ -12,7 +12,7 @@ namespace NTwain /// A customized TWAIN session for use in WPF environment. /// Use this by using method as the target of delegate. /// - public class TwainSessionWPF : TwainSessionBase + public class TwainSessionWPF : TwainSession { /// /// Initializes a new instance of the class. diff --git a/NTwain/TwainSessionWinform.cs b/NTwain/TwainSessionWinform.cs index aa0388f..415c555 100644 --- a/NTwain/TwainSessionWinform.cs +++ b/NTwain/TwainSessionWinform.cs @@ -11,7 +11,7 @@ namespace NTwain /// A customized TWAIN session for use in winform environment. /// Use this by adding this as an via . /// - public class TwainSessionWinform : TwainSessionBase, IMessageFilter + public class TwainSessionWinform : TwainSession, IMessageFilter { /// /// Initializes a new instance of the class. diff --git a/Tests/Tester.WPF/MainWindow.xaml.cs b/Tests/Tester.WPF/MainWindow.xaml.cs index 9a040ab..a01eed1 100644 --- a/Tests/Tester.WPF/MainWindow.xaml.cs +++ b/Tests/Tester.WPF/MainWindow.xaml.cs @@ -19,6 +19,7 @@ using System.Runtime.InteropServices; using CommonWin32; using System.Threading; using ModernWPF.Controls; +using System.Reflection; namespace Tester.WPF { @@ -27,7 +28,7 @@ namespace Tester.WPF /// public partial class MainWindow : Window { - TwainSessionOld twain; + TwainSessionWPF twain; public MainWindow() { InitializeComponent(); @@ -48,19 +49,13 @@ namespace Tester.WPF base.OnSourceInitialized(e); var hwnd = new WindowInteropHelper(this).Handle; - HwndSource.FromHwnd(hwnd).AddHook(WndProc); - } - - IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) - { - var res = twain.PreFilterMessage(hwnd, msg, wParam, lParam, ref handled); - return res; + HwndSource.FromHwnd(hwnd).AddHook(twain.PreFilterMessage); } private void SetupTwain() { - TWIdentity appId = TWIdentity.Create(DataGroups.Image, new Version(1, 0), "My Company", "Test Family", "Tester", null); - twain = new TwainSessionOld(appId); + TWIdentity appId = TWIdentity.CreateFromAssembly(DataGroups.Image, Assembly.GetEntryAssembly()); + twain = new TwainSessionWPF(appId); twain.DataTransferred += (s, e) => { if (e.Data != IntPtr.Zero) diff --git a/Tests/Tester.Winform/TestForm.cs b/Tests/Tester.Winform/TestForm.cs index d0d9cb1..3db4420 100644 --- a/Tests/Tester.Winform/TestForm.cs +++ b/Tests/Tester.Winform/TestForm.cs @@ -20,7 +20,7 @@ namespace Tester.Winform sealed partial class TestForm : Form { ImageCodecInfo _tiffCodecInfo; - TwainSessionOld _twain; + TwainSessionWinform _twain; bool _stopScan; bool _loadingCaps; @@ -60,11 +60,8 @@ namespace Tester.Winform private void SetupTwain() { - var appVer = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location); - - TWIdentity appId = TWIdentity.Create(DataGroups.Image, new Version(appVer.ProductMajorPart, appVer.ProductMinorPart), - "My Company", "Test Family", "Tester", "A TWAIN testing app."); - _twain = new TwainSessionOld(appId); + var appId = TWIdentity.CreateFromAssembly(DataGroups.Image, Assembly.GetEntryAssembly()); + _twain = new TwainSessionWinform(appId); _twain.DataTransferred += (s, e) => { if (pictureBox1.Image != null)