From 320dfb2175ab86d4164bbfd20e97876191e7eac4 Mon Sep 17 00:00:00 2001 From: soukoku Date: Mon, 14 Apr 2014 19:04:48 -0400 Subject: [PATCH] Initial internal loop idea that compiles. --- NTwain/AsyncPump.cs | 50 ----- NTwain/NTwain.csproj | 5 +- NTwain/Properties/VersionInfo.cs | 2 +- NTwain/Triplets/Dsm.cs | 108 +++++----- NTwain/TwainSession.cs | 252 ++++++++++++------------ NTwain/TwainSessionOld.cs | 229 --------------------- NTwain/TwainSessionWPF.cs | 39 ---- NTwain/TwainSessionWinform.cs | 32 --- Tests/NTwain.Tests/TwainSessionTests.cs | 4 +- Tests/Tester.Console/Program.cs | 33 +--- Tests/Tester.WPF/MainWindow.xaml.cs | 7 +- Tests/Tester.WPF/TwainVM.cs | 23 ++- Tests/Tester.Winform/TestForm.cs | 58 +++--- 13 files changed, 231 insertions(+), 611 deletions(-) delete mode 100644 NTwain/AsyncPump.cs delete mode 100644 NTwain/TwainSessionOld.cs delete mode 100644 NTwain/TwainSessionWPF.cs delete mode 100644 NTwain/TwainSessionWinform.cs diff --git a/NTwain/AsyncPump.cs b/NTwain/AsyncPump.cs deleted file mode 100644 index 5800cc7..0000000 --- a/NTwain/AsyncPump.cs +++ /dev/null @@ -1,50 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using System.Text; -//using System.Threading; -//using System.Windows.Threading; - -//namespace NTwain -//{ -// // from http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx - -// /// -// /// Provides a pump that supports running asynchronous methods on the current thread. -// /// -// public static class AsyncPump -// { -// /// -// /// Runs the specified asynchronous function. -// /// -// /// The asynchronous function to execute. -// /// func -// /// No task provided. -// public static void Run(Func func) -// { -// if (func == null) throw new ArgumentNullException("func"); - -// var prevCtx = SynchronizationContext.Current; -// try -// { -// var syncCtx = new DispatcherSynchronizationContext(); -// SynchronizationContext.SetSynchronizationContext(syncCtx); - -// var t = func(); -// if (t == null) throw new InvalidOperationException(); - -// var frame = new DispatcherFrame(); -// t.ContinueWith(_ => { frame.Continue = false; }, -// TaskScheduler.Default); -// Dispatcher.PushFrame(frame); - -// t.GetAwaiter().GetResult(); -// } -// finally -// { -// SynchronizationContext.SetSynchronizationContext(prevCtx); -// } - -// } -// } -//} diff --git a/NTwain/NTwain.csproj b/NTwain/NTwain.csproj index 62826c4..51c3e09 100644 --- a/NTwain/NTwain.csproj +++ b/NTwain/NTwain.csproj @@ -53,7 +53,6 @@ - @@ -64,6 +63,7 @@ + True @@ -82,8 +82,6 @@ - - @@ -125,7 +123,6 @@ - diff --git a/NTwain/Properties/VersionInfo.cs b/NTwain/Properties/VersionInfo.cs index 91820f5..f7bc74d 100644 --- a/NTwain/Properties/VersionInfo.cs +++ b/NTwain/Properties/VersionInfo.cs @@ -14,6 +14,6 @@ namespace NTwain // keep this same in majors releases public const string Release = "0.10.0.0"; // change this for each nuget release - public const string Build = "0.10.1"; + public const string Build = "0.10.2"; } } \ No newline at end of file diff --git a/NTwain/Triplets/Dsm.cs b/NTwain/Triplets/Dsm.cs index dfc7358..9b089e5 100644 --- a/NTwain/Triplets/Dsm.cs +++ b/NTwain/Triplets/Dsm.cs @@ -21,7 +21,7 @@ namespace NTwain.Triplets // in essence it only exists in 64 bit systems and thus // the 2 sets of identical pinvokes for windows :( - public static readonly bool CanUseNewDSM = CheckIfCanUseNewDSM(); + internal static readonly bool UseNewDSM = CheckIfCanUseNewDSM(); private static bool CheckIfCanUseNewDSM() { @@ -35,7 +35,7 @@ namespace NTwain.Triplets #endif } - static readonly bool IsWin = Environment.OSVersion.Platform == PlatformID.Win32NT; + internal static readonly bool IsWin = Environment.OSVersion.Platform == PlatformID.Win32NT; static readonly bool IsLinux = Environment.OSVersion.Platform == PlatformID.Unix; // define sig for each different data type since "object" doesn't work @@ -52,7 +52,7 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, dg, dat, msg, ref data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, dg, dat, msg, ref data); } else { return NativeMethods.DsmWinOld(origin, destination, dg, dat, msg, ref data); } } else if (IsLinux) @@ -72,7 +72,7 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, dg, dat, msg, ref data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, dg, dat, msg, ref data); } else { return NativeMethods.DsmWinOld(origin, destination, dg, dat, msg, ref data); } } else if (IsLinux) @@ -90,7 +90,7 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Audio, DataArgumentType.AudioInfo, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Audio, DataArgumentType.AudioInfo, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Audio, DataArgumentType.AudioInfo, msg, data); } } else if (IsLinux) @@ -109,12 +109,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.Capability, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.Capability, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Control, DataArgumentType.Capability, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.Capability, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.Capability, msg, data); } throw new PlatformNotSupportedException(); } @@ -128,12 +128,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.CustomDSData, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.CustomDSData, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Control, DataArgumentType.CustomDSData, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.CustomDSData, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.CustomDSData, msg, data); } throw new PlatformNotSupportedException(); } @@ -147,12 +147,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.DeviceEvent, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.DeviceEvent, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Control, DataArgumentType.DeviceEvent, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.DeviceEvent, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.DeviceEvent, msg, data); } throw new PlatformNotSupportedException(); } @@ -166,12 +166,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.Callback, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.Callback, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Control, DataArgumentType.Callback, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.Callback, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.Callback, msg, data); } throw new PlatformNotSupportedException(); } @@ -185,12 +185,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.Callback, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.Callback, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Control, DataArgumentType.Callback, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.Callback, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.Callback, msg, data); } throw new PlatformNotSupportedException(); } @@ -204,12 +204,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.EntryPoint, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.EntryPoint, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Control, DataArgumentType.EntryPoint, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.EntryPoint, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.EntryPoint, msg, data); } throw new PlatformNotSupportedException(); } @@ -223,12 +223,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.Event, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.Event, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Control, DataArgumentType.Event, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.Event, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.Event, msg, data); } throw new PlatformNotSupportedException(); } @@ -242,12 +242,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.FileSystem, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.FileSystem, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Control, DataArgumentType.FileSystem, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.FileSystem, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.FileSystem, msg, data); } throw new PlatformNotSupportedException(); } @@ -259,7 +259,7 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, IntPtr.Zero, DataGroups.Control, DataArgumentType.Identity, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, IntPtr.Zero, DataGroups.Control, DataArgumentType.Identity, msg, data); } else { return NativeMethods.DsmWinOld(origin, IntPtr.Zero, DataGroups.Control, DataArgumentType.Identity, msg, data); } } else if (IsLinux) @@ -278,7 +278,7 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.PassThru, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.PassThru, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Control, DataArgumentType.PassThru, msg, data); } } else if (IsLinux) @@ -297,12 +297,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.PendingXfers, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.PendingXfers, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Control, DataArgumentType.PendingXfers, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.PendingXfers, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.PendingXfers, msg, data); } throw new PlatformNotSupportedException(); } @@ -316,12 +316,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.SetupFileXfer, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.SetupFileXfer, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Control, DataArgumentType.SetupFileXfer, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.SetupFileXfer, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.SetupFileXfer, msg, data); } throw new PlatformNotSupportedException(); } @@ -335,12 +335,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.SetupMemXfer, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.SetupMemXfer, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Control, DataArgumentType.SetupMemXfer, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.SetupMemXfer, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.SetupMemXfer, msg, data); } throw new PlatformNotSupportedException(); } @@ -354,12 +354,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.StatusUtf8, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.StatusUtf8, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Control, DataArgumentType.StatusUtf8, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.StatusUtf8, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.StatusUtf8, msg, data); } throw new PlatformNotSupportedException(); } @@ -373,12 +373,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.UserInterface, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.UserInterface, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Control, DataArgumentType.UserInterface, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.UserInterface, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.UserInterface, msg, data); } throw new PlatformNotSupportedException(); } @@ -392,12 +392,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.CieColor, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.CieColor, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Image, DataArgumentType.CieColor, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Image, DataArgumentType.CieColor, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Image, DataArgumentType.CieColor, msg, data); } throw new PlatformNotSupportedException(); } @@ -411,12 +411,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.ExtImageInfo, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.ExtImageInfo, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Image, DataArgumentType.ExtImageInfo, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Image, DataArgumentType.ExtImageInfo, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Image, DataArgumentType.ExtImageInfo, msg, data); } throw new PlatformNotSupportedException(); } @@ -429,12 +429,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.Filter, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.Filter, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Image, DataArgumentType.Filter, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Image, DataArgumentType.Filter, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Image, DataArgumentType.Filter, msg, data); } throw new PlatformNotSupportedException(); } @@ -447,12 +447,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.GrayResponse, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.GrayResponse, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Image, DataArgumentType.GrayResponse, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Image, DataArgumentType.GrayResponse, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Image, DataArgumentType.GrayResponse, msg, data); } throw new PlatformNotSupportedException(); } @@ -466,7 +466,7 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.ImageInfo, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.ImageInfo, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Image, DataArgumentType.ImageInfo, msg, data); } } else if (IsLinux) @@ -485,12 +485,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.ImageLayout, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.ImageLayout, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Image, DataArgumentType.ImageLayout, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Image, DataArgumentType.ImageLayout, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Image, DataArgumentType.ImageLayout, msg, data); } throw new PlatformNotSupportedException(); } @@ -504,7 +504,7 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.ImageMemXfer, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.ImageMemXfer, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Image, DataArgumentType.ImageMemXfer, msg, data); } } else if (IsLinux) @@ -523,12 +523,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.JpegCompression, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.JpegCompression, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Image, DataArgumentType.JpegCompression, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Image, DataArgumentType.JpegCompression, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Image, DataArgumentType.JpegCompression, msg, data); } throw new PlatformNotSupportedException(); } @@ -542,7 +542,7 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.Palette8, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.Palette8, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Image, DataArgumentType.Palette8, msg, data); } } else if (IsLinux) @@ -561,12 +561,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.RgbResponse, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Image, DataArgumentType.RgbResponse, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Image, DataArgumentType.RgbResponse, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Image, DataArgumentType.RgbResponse, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Image, DataArgumentType.RgbResponse, msg, data); } throw new PlatformNotSupportedException(); } @@ -580,12 +580,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.Status, msg, data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, DataArgumentType.Status, msg, data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Control, DataArgumentType.Status, msg, data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.Status, msg, data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, DataArgumentType.Status, msg, data); } throw new PlatformNotSupportedException(); } @@ -600,12 +600,12 @@ namespace NTwain.Triplets { if (IsWin) { - if (CanUseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, dat, msg, ref data); } + if (UseNewDSM) { return NativeMethods.DsmWinNew(origin, destination, DataGroups.Control, dat, msg, ref data); } else { return NativeMethods.DsmWinOld(origin, destination, DataGroups.Control, dat, msg, ref data); } } else if (IsLinux) { - return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, dat, msg, ref data); + return NativeMethods.DsmLinux(origin, destination, DataGroups.Control, dat, msg, ref data); } throw new PlatformNotSupportedException(); } diff --git a/NTwain/TwainSession.cs b/NTwain/TwainSession.cs index ca20e4f..4c72fe0 100644 --- a/NTwain/TwainSession.cs +++ b/NTwain/TwainSession.cs @@ -8,8 +8,10 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.InteropServices; +using System.Security.Permissions; using System.Text; using System.Threading; +using System.Windows.Threading; namespace NTwain { @@ -29,11 +31,13 @@ namespace NTwain _appId = appId; ((ITwainStateInternal)this).ChangeState(1, false); EnforceState = true; + + Debug.WriteLine("current thread id =" + Thread.CurrentThread.ManagedThreadId); + + MessageLoop.Instance.EnsureStarted(); } TWIdentity _appId; - IntPtr _appHandle; - SynchronizationContext _syncer; object _callbackObj; // kept around so it doesn't get gc'ed TWUserInterface _twui; @@ -205,17 +209,14 @@ namespace NTwain /// Opens the data source manager. This must be the first method used /// before using other TWAIN functions. Calls to this must be followed by when done with a TWAIN session. /// - /// On Windows = points to the window handle (hWnd) that will act as the Source’s - /// "parent". On Macintosh = should be a NULL value. /// - public ReturnCode OpenManager(IntPtr appHandle) + public ReturnCode OpenManager() { Debug.WriteLine(string.Format("Thread {0}: OpenManager.", Thread.CurrentThread.ManagedThreadId)); - var rc = DGControl.Parent.OpenDsm(appHandle); + var rc = DGControl.Parent.OpenDsm(MessageLoop.Instance.LoopHandle); if (rc == ReturnCode.Success) { - _appHandle = appHandle; // if twain2 then get memory management functions if ((_appId.DataFunctionalities & DataFunctionalities.Dsm2) == DataFunctionalities.Dsm2) { @@ -243,11 +244,7 @@ namespace NTwain { Debug.WriteLine(string.Format("Thread {0}: CloseManager.", Thread.CurrentThread.ManagedThreadId)); - var rc = DGControl.Parent.CloseDsm(_appHandle); - if (rc == ReturnCode.Success) - { - _appHandle = IntPtr.Zero; - } + var rc = DGControl.Parent.CloseDsm(MessageLoop.Instance.LoopHandle); return rc; } @@ -289,6 +286,7 @@ namespace NTwain var rc = DGControl.Identity.CloseDS(); if (rc == ReturnCode.Success) { + MessageLoop.Instance.RemoveHook(HandleWndProcMessage); _callbackObj = null; SupportedCaps = null; } @@ -301,62 +299,62 @@ namespace NTwain /// The mode. /// if set to true any driver UI will display as modal. /// The window handle if modal. - /// - /// The - /// is required if TWAIN is using callback mode - /// instead of the typical WndProc message loop. - /// It is recommended you call this method in an UI thread and pass in - /// - /// if you do not have a custom one setup. /// /// context - public ReturnCode EnableSource(SourceEnableMode mode, bool modal, IntPtr windowHandle, SynchronizationContext context) + public ReturnCode EnableSource(SourceEnableMode mode, bool modal, IntPtr windowHandle) { - if (context == null && _callbackObj != null) { throw new ArgumentNullException("SynchronizationContext is required when not using message loop.", "context"); } - Debug.WriteLine(string.Format("Thread {0}: EnableSource.", Thread.CurrentThread.ManagedThreadId)); - _syncer = context; + ReturnCode rc = ReturnCode.Success; - // app v2.2 or higher uses callback2 - if (_appId.ProtocolMajor >= 2 && _appId.ProtocolMinor >= 2) + MessageLoop.Instance.Invoke(() => { - var cb = new TWCallback2(HandleCallback); - var rc2 = DGControl.Callback2.RegisterCallback(cb); - - if (rc2 == ReturnCode.Success) + // app v2.2 or higher uses callback2 + if (_appId.ProtocolMajor >= 2 && _appId.ProtocolMinor >= 2) { - Debug.WriteLine("Registered callback2 OK."); - _callbackObj = cb; + var cb = new TWCallback2(HandleCallback); + var rc2 = DGControl.Callback2.RegisterCallback(cb); + + if (rc2 == ReturnCode.Success) + { + Debug.WriteLine("Registered callback2 OK."); + _callbackObj = cb; + } } - } - else - { - var cb = new TWCallback(HandleCallback); - - var rc2 = DGControl.Callback.RegisterCallback(cb); - - if (rc2 == ReturnCode.Success) + else { - Debug.WriteLine("Registered callback OK."); - _callbackObj = cb; + var cb = new TWCallback(HandleCallback); + + var rc2 = DGControl.Callback.RegisterCallback(cb); + + if (rc2 == ReturnCode.Success) + { + Debug.WriteLine("Registered callback OK."); + _callbackObj = cb; + } } - } - _twui = new TWUserInterface(); - _twui.ShowUI = mode == SourceEnableMode.ShowUI; - _twui.ModalUI = modal; - _twui.hParent = windowHandle; + if (_callbackObj == null) + { + // must use msg loop if callback is not available + MessageLoop.Instance.AddHook(HandleWndProcMessage); + } - if (mode == SourceEnableMode.ShowUIOnly) - { - return DGControl.UserInterface.EnableDSUIOnly(_twui); - } - else - { - return DGControl.UserInterface.EnableDS(_twui); - } + _twui = new TWUserInterface(); + _twui.ShowUI = mode == SourceEnableMode.ShowUI; + _twui.ModalUI = modal; + _twui.hParent = windowHandle; + if (mode == SourceEnableMode.ShowUIOnly) + { + rc = DGControl.UserInterface.EnableDSUIOnly(_twui); + } + else + { + rc = DGControl.UserInterface.EnableDS(_twui); + } + }); + return rc; } /// @@ -367,64 +365,69 @@ namespace NTwain { Debug.WriteLine(string.Format("Thread {0}: DisableSource.", Thread.CurrentThread.ManagedThreadId)); - var rc = DGControl.UserInterface.DisableDS(_twui); - if (rc == ReturnCode.Success) + ReturnCode rc = ReturnCode.Success; + + MessageLoop.Instance.Invoke(() => { - OnSourceDisabled(); - } + rc = DGControl.UserInterface.DisableDS(_twui); + if (rc == ReturnCode.Success) + { + OnSourceDisabled(); + } + }); return rc; } /// /// Forces the stepping down of an opened source when things gets out of control. /// Used when session state and source state become out of sync. - /// This should be called on the Thread that originally called the - /// method, if applicable. /// /// State of the target. public void ForceStepDown(int targetState) { Debug.WriteLine(string.Format("Thread {0}: ForceStepDown.", Thread.CurrentThread.ManagedThreadId)); + MessageLoop.Instance.Invoke(() => + { + bool origFlag = EnforceState; + EnforceState = false; - bool origFlag = EnforceState; - EnforceState = false; + // From the twain spec + // Stepping Back Down the States + // DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER → state 7 to 6 + // DG_CONTROL / DAT_PENDINGXFERS / MSG_RESET → state 6 to 5 + // DG_CONTROL / DAT_USERINTERFACE / MSG_DISABLEDS → state 5 to 4 + // DG_CONTROL / DAT_IDENTITY / MSG_CLOSEDS → state 4 to 3 + // Ignore the status returns from the calls prior to the one yielding the desired state. For instance, if a + // call during scanning returns TWCC_SEQERROR and the desire is to return to state 5, then use the + // following commands. + // DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER → state 7 to 6 + // DG_CONTROL / DAT_PENDINGXFERS / MSG_RESET → state 6 to 5 + // Being sure to confirm that DG_CONTROL / DAT_PENDINGXFERS / MSG_RESET returned + // success, the return status from DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER may + // be ignored. - // From the twain spec - // Stepping Back Down the States - // DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER → state 7 to 6 - // DG_CONTROL / DAT_PENDINGXFERS / MSG_RESET → state 6 to 5 - // DG_CONTROL / DAT_USERINTERFACE / MSG_DISABLEDS → state 5 to 4 - // DG_CONTROL / DAT_IDENTITY / MSG_CLOSEDS → state 4 to 3 - // Ignore the status returns from the calls prior to the one yielding the desired state. For instance, if a - // call during scanning returns TWCC_SEQERROR and the desire is to return to state 5, then use the - // following commands. - // DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER → state 7 to 6 - // DG_CONTROL / DAT_PENDINGXFERS / MSG_RESET → state 6 to 5 - // Being sure to confirm that DG_CONTROL / DAT_PENDINGXFERS / MSG_RESET returned - // success, the return status from DG_CONTROL / DAT_PENDINGXFERS / MSG_ENDXFER may - // be ignored. - - if (targetState < 7) - { - DGControl.PendingXfers.EndXfer(new TWPendingXfers()); - } - if (targetState < 6) - { - DGControl.PendingXfers.Reset(new TWPendingXfers()); - } - if (targetState < 5) - { - DisableSource(); - } - if (targetState < 4) - { - CloseSource(); - } - if (targetState < 3) - { - CloseManager(); - } - EnforceState = origFlag; + if (targetState < 7) + { + DGControl.PendingXfers.EndXfer(new TWPendingXfers()); + } + if (targetState < 6) + { + DGControl.PendingXfers.Reset(new TWPendingXfers()); + } + if (targetState < 5) + { + DisableSource(); + } + if (targetState < 4) + { + CloseSource(); + } + if (targetState < 3) + { + CloseManager(); + } + EnforceState = origFlag; + }); } #endregion @@ -583,14 +586,13 @@ namespace NTwain #region TWAIN logic during xfer work - /// - /// Handles the message from a typical WndProc message loop and check if it's from the TWAIN source. - /// - /// The message. - /// True if handled by TWAIN. - protected bool HandleWndProcMessage(ref MESSAGE message) + //[EnvironmentPermissionAttribute(SecurityAction.LinkDemand)] + IntPtr HandleWndProcMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { - var handled = false; + // this handles the message from a typical WndProc message loop and check if it's from the TWAIN source. + + var winmsg = new MESSAGE(hwnd, msg, wParam, lParam); + if (State >= 4) // technically we should only handle on state >= 5 but there might be missed msgs if we wait until state changes after enabling ds { // transform it into a pointer for twain @@ -598,15 +600,19 @@ namespace NTwain try { // no need to do another lock call when using marshal alloc - msgPtr = Marshal.AllocHGlobal(Marshal.SizeOf(message)); - Marshal.StructureToPtr(message, msgPtr, false); + msgPtr = Marshal.AllocHGlobal(Marshal.SizeOf(winmsg)); + Marshal.StructureToPtr(winmsg, msgPtr, false); TWEvent evt = new TWEvent(); evt.pEvent = msgPtr; - if (handled = DGControl.Event.ProcessEvent(evt) == ReturnCode.DSEvent) + 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); + + MessageLoop.Instance.BeginInvoke(() => + { + HandleSourceMsg(evt.TWMessage); + }); } } finally @@ -614,7 +620,8 @@ namespace NTwain if (msgPtr != IntPtr.Zero) { Marshal.FreeHGlobal(msgPtr); } } } - return handled; + + return IntPtr.Zero; } ReturnCode HandleCallback(TWIdentity origin, TWIdentity destination, DataGroups dg, DataArgumentType dat, Message msg, IntPtr data) @@ -622,28 +629,13 @@ namespace NTwain if (origin != null && SourceId != null && origin.Id == SourceId.Id) { 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 - // so this is an hack to make it happen. + // spec says we must handle this on the thread that enabled the DS. + // by using the internal dispatcher this will be the case. - // TODO: find a better method without needing a SynchronizationContext. - ThreadPool.QueueUserWorkItem(o => + MessageLoop.Instance.BeginInvoke(() => { - var ctx = o as SynchronizationContext; - if (ctx != null) - { - _syncer.Post(blah => - { - HandleSourceMsg(msg); - }, null); - } - else - { - // no context? better hope for the best! - HandleSourceMsg(msg); - } - }, _syncer); + HandleSourceMsg(msg); + }); return ReturnCode.Success; } return ReturnCode.Failure; diff --git a/NTwain/TwainSessionOld.cs b/NTwain/TwainSessionOld.cs deleted file mode 100644 index 294d5ce..0000000 --- a/NTwain/TwainSessionOld.cs +++ /dev/null @@ -1,229 +0,0 @@ -using System; -using NTwain.Triplets; -using NTwain.Data; -using NTwain.Values; -using System.Windows.Forms; -using System.Security.Permissions; - -namespace NTwain -{ - /// - /// Provides a session for working with TWAIN api in an application. - /// This is the old implementation for reference purposes only. - /// - [Obsolete("For reference purposes only.")] - public class TwainSessionOld : TwainSession, IMessageFilter - { - /// - /// Initializes a new instance of the class. - /// - /// The app id. - /// - public TwainSessionOld(TWIdentity appId) : base(appId) { } - - protected override void DoTransferRoutine() - { - 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); - var args = new TransferReadyEventArgs - { - PendingImageInfo = imgInfo, - PendingTransferCount = pending.Count, - EndOfJob = pending.EndOfJob == 0 - }; - args.CancelCurrent = skip; - - OnTransferReady(args); - - - if (!args.CancelAll && !args.CancelCurrent) - { - Values.XferMech mech = this.GetCurrentCap(CapabilityId.ICapXferMech).ConvertToEnum(); - - //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 - - 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 { NativeData = lockedPtr, FileDataPath = 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(); - - } - - #region messaging use - - /// - /// Message loop processor for winform. - /// Use this by adding the as an . - /// - /// The message to be dispatched. You cannot modify this message. - /// - /// true to filter the message and stop it from being dispatched; false to allow the message to continue to the next filter or control. - /// - //[EnvironmentPermissionAttribute(SecurityAction.LinkDemand)] - [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] - bool IMessageFilter.PreFilterMessage(ref System.Windows.Forms.Message m) - { - var winmsg = new MESSAGE(m.HWnd, m.Msg, m.WParam, m.LParam); - - return HandleWndProcMessage(ref winmsg); - } - - /// - /// Message loop processor for WPF. - /// - /// The window handle. - /// The message ID. - /// The message's wParam value. - /// The message's lParam value. - /// A value that indicates whether the message was handled. Set the value to true if the message was handled; otherwise, false. - /// - [EnvironmentPermissionAttribute(SecurityAction.LinkDemand)] - public IntPtr PreFilterMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) - { - var winmsg = new MESSAGE(hwnd, msg, wParam, lParam); - - handled = base.HandleWndProcMessage(ref winmsg); - - return IntPtr.Zero; - } - - #endregion - - } -} diff --git a/NTwain/TwainSessionWPF.cs b/NTwain/TwainSessionWPF.cs deleted file mode 100644 index 5a1fe13..0000000 --- a/NTwain/TwainSessionWPF.cs +++ /dev/null @@ -1,39 +0,0 @@ -using NTwain.Data; -using System; -using System.Security.Permissions; - -namespace NTwain -{ - /// - /// A customized TWAIN session for use in WPF environment. - /// Use this by using method as the target of delegate. - /// - public class TwainSessionWPF : TwainSession - { - /// - /// Initializes a new instance of the class. - /// - /// The app id. - /// - public TwainSessionWPF(TWIdentity appId) : base(appId) { } - - /// - /// Message loop processor for WPF. - /// - /// The window handle. - /// The message ID. - /// The message's wParam value. - /// The message's lParam value. - /// A value that indicates whether the message was handled. Set the value to true if the message was handled; otherwise, false. - /// - [EnvironmentPermissionAttribute(SecurityAction.LinkDemand)] - public IntPtr PreFilterMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) - { - var winmsg = new MESSAGE(hwnd, msg, wParam, lParam); - - handled = base.HandleWndProcMessage(ref winmsg); - - return IntPtr.Zero; - } - } -} diff --git a/NTwain/TwainSessionWinform.cs b/NTwain/TwainSessionWinform.cs deleted file mode 100644 index de28237..0000000 --- a/NTwain/TwainSessionWinform.cs +++ /dev/null @@ -1,32 +0,0 @@ -using NTwain.Data; -using System.Security.Permissions; -using System.Windows.Forms; - -namespace NTwain -{ - /// - /// A customized TWAIN session for use in winform environment. - /// Use this by adding this as an via . - /// - public class TwainSessionWinform : TwainSession, IMessageFilter - { - /// - /// Initializes a new instance of the class. - /// - /// The app id. - /// - public TwainSessionWinform(TWIdentity appId) : base(appId) { } - - #region IMessageFilter Members - - [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] - public bool PreFilterMessage(ref Message m) - { - var winmsg = new MESSAGE(m.HWnd, m.Msg, m.WParam, m.LParam); - - return HandleWndProcMessage(ref winmsg); - } - - #endregion - } -} diff --git a/Tests/NTwain.Tests/TwainSessionTests.cs b/Tests/NTwain.Tests/TwainSessionTests.cs index f335acd..896148a 100644 --- a/Tests/NTwain.Tests/TwainSessionTests.cs +++ b/Tests/NTwain.Tests/TwainSessionTests.cs @@ -12,7 +12,7 @@ namespace NTwain.Tests [ExpectedException(typeof(TwainStateException), "State check failed to throw.")] public void VerifyState_Throws_When_State_Is_Enforced() { - ITwainStateInternal session = new TwainSessionOld(TWIdentity.Create(DataGroups.Image, new Version(1, 0), "test", "test", "test", "test")); + ITwainStateInternal session = new TwainSession(TWIdentity.Create(DataGroups.Image, new Version(1, 0), "test", "test", "test", "test")); session.EnforceState = true; session.ChangeState(4, false); @@ -22,7 +22,7 @@ namespace NTwain.Tests [TestMethod] public void VerifyState_No_Throws_When_State_Is_Not_Enforced() { - ITwainStateInternal session = new TwainSessionOld(TWIdentity.Create(DataGroups.Image, new Version(1, 0), "test", "test", "test", "test")); + ITwainStateInternal session = new TwainSession(TWIdentity.Create(DataGroups.Image, new Version(1, 0), "test", "test", "test", "test")); session.EnforceState = false; session.ChangeState(4, false); diff --git a/Tests/Tester.Console/Program.cs b/Tests/Tester.Console/Program.cs index 0ed4cb6..3b38844 100644 --- a/Tests/Tester.Console/Program.cs +++ b/Tests/Tester.Console/Program.cs @@ -17,14 +17,9 @@ namespace Tester { static void Main(string[] args) { - // just an amusing example to do twain in console without UI, but may not work in real life - - Console.WriteLine("Running Main on thread {0}", Thread.CurrentThread.ManagedThreadId); - new Thread(new ParameterizedThreadStart(DoTwainWork)).Start(Dispatcher.CurrentDispatcher); - - // basically just needs a msg loop to act as the UI thread - Dispatcher.Run(); - Console.WriteLine("Test completed."); + // just an amusing example to do twain in console without UI + DoTwainWork(); + Console.WriteLine("Test completed, press Enter to exit."); Console.ReadLine(); } @@ -41,19 +36,12 @@ namespace Tester } - static void DoTwainWork(object obj) + static void DoTwainWork() { Console.WriteLine("Getting ready to do twain stuff on thread {0}", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(1000); - var mySyncer = SynchronizationContext.Current; - - if (mySyncer == null) - { - mySyncer = new DispatcherSynchronizationContext(obj as Dispatcher); - } - - var rc = twain.OpenManager(IntPtr.Zero); + var rc = twain.OpenManager(); if (rc == ReturnCode.Success) { @@ -61,20 +49,13 @@ namespace Tester if (rc == ReturnCode.Success) { - // enablesource must be on the thread the sync context works on - mySyncer.Post(blah => - { - rc = twain.EnableSource(SourceEnableMode.NoUI, false, IntPtr.Zero, blah as SynchronizationContext); - }, mySyncer); - return; + rc = twain.EnableSource(SourceEnableMode.NoUI, false, IntPtr.Zero); } else { twain.CloseManager(); } } - - Dispatcher.ExitAllFrames(); } static void twain_SourceDisabled(object sender, EventArgs e) @@ -82,8 +63,6 @@ namespace Tester Console.WriteLine("Source disabled on thread {0}", Thread.CurrentThread.ManagedThreadId); var rc = twain.CloseSource(); rc = twain.CloseManager(); - - Dispatcher.ExitAllFrames(); } static void twain_TransferReady(object sender, TransferReadyEventArgs e) diff --git a/Tests/Tester.WPF/MainWindow.xaml.cs b/Tests/Tester.WPF/MainWindow.xaml.cs index d607aa2..be1d30f 100644 --- a/Tests/Tester.WPF/MainWindow.xaml.cs +++ b/Tests/Tester.WPF/MainWindow.xaml.cs @@ -68,12 +68,7 @@ namespace Tester.WPF { base.OnSourceInitialized(e); - var hwnd = new WindowInteropHelper(this).Handle; - - // this line is unnecessary if using twain 2 dsm but doesn't hurt to use it - HwndSource.FromHwnd(hwnd).AddHook(_twainVM.PreFilterMessage); - - var rc = _twainVM.OpenManager(hwnd); + var rc = _twainVM.OpenManager(); if (rc == ReturnCode.Success) { SrcList.ItemsSource = _twainVM.GetSources().Select(s => new DSVM { DS = s }); diff --git a/Tests/Tester.WPF/TwainVM.cs b/Tests/Tester.WPF/TwainVM.cs index 409e44e..d1c05cd 100644 --- a/Tests/Tester.WPF/TwainVM.cs +++ b/Tests/Tester.WPF/TwainVM.cs @@ -17,7 +17,7 @@ namespace Tester.WPF /// /// Wraps the twain session as a view model for databinding. /// - class TwainVM : TwainSessionWPF + class TwainVM : TwainSession { public TwainVM() : base(TWIdentity.CreateFromAssembly(DataGroups.Image | DataGroups.Audio, Assembly.GetEntryAssembly())) @@ -87,15 +87,18 @@ namespace Tester.WPF protected override void OnDataTransferred(DataTransferredEventArgs e) { - if (e.NativeData != IntPtr.Zero) + App.Current.Dispatcher.Invoke(new Action(() => { - Image = e.NativeData.GetWPFBitmap(); - } - else if (!string.IsNullOrEmpty(e.FileDataPath)) - { - var img = new BitmapImage(new Uri(e.FileDataPath)); - Image = img; - } + if (e.NativeData != IntPtr.Zero) + { + Image = e.NativeData.GetWPFBitmap(); + } + else if (!string.IsNullOrEmpty(e.FileDataPath)) + { + var img = new BitmapImage(new Uri(e.FileDataPath)); + Image = img; + } + })); base.OnDataTransferred(e); } @@ -113,7 +116,7 @@ namespace Tester.WPF this.CapSetImageXferMech(XferMech.File); } - var rc = EnableSource(SourceEnableMode.NoUI, false, hwnd, SynchronizationContext.Current); + var rc = EnableSource(SourceEnableMode.NoUI, false, hwnd); } } } diff --git a/Tests/Tester.Winform/TestForm.cs b/Tests/Tester.Winform/TestForm.cs index 7f425b2..9252774 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; - TwainSessionWinform _twain; + TwainSession _twain; bool _stopScan; bool _loadingCaps; @@ -61,44 +61,48 @@ namespace Tester.Winform private void SetupTwain() { var appId = TWIdentity.CreateFromAssembly(DataGroups.Image, Assembly.GetEntryAssembly()); - _twain = new TwainSessionWinform(appId); + _twain = new TwainSession(appId); _twain.DataTransferred += (s, e) => { - if (pictureBox1.Image != null) + this.Invoke(new Action(() => { - pictureBox1.Image.Dispose(); - pictureBox1.Image = null; - } - if (e.NativeData != IntPtr.Zero) - { - //_ptrTest = e.Data; - var img = e.NativeData.GetDrawingBitmap(); - if (img != null) + if (pictureBox1.Image != null) + { + pictureBox1.Image.Dispose(); + pictureBox1.Image = null; + } + if (e.NativeData != IntPtr.Zero) + { + //_ptrTest = e.Data; + var img = e.NativeData.GetDrawingBitmap(); + if (img != null) + pictureBox1.Image = img; + } + else if (!string.IsNullOrEmpty(e.FileDataPath)) + { + var img = new Bitmap(e.FileDataPath); pictureBox1.Image = img; - } - else if (!string.IsNullOrEmpty(e.FileDataPath)) - { - var img = new Bitmap(e.FileDataPath); - pictureBox1.Image = img; - } + } + })); }; _twain.SourceDisabled += (s, e) => { - btnStopScan.Enabled = false; - btnStartCapture.Enabled = true; - panelOptions.Enabled = true; - LoadSourceCaps(); + this.Invoke(new Action(() => + { + btnStopScan.Enabled = false; + btnStartCapture.Enabled = true; + panelOptions.Enabled = true; + LoadSourceCaps(); + })); }; _twain.TransferReady += (s, e) => { e.CancelAll = _stopScan; }; - Application.AddMessageFilter(_twain); } private void CleanupTwain() { - Application.RemoveMessageFilter(_twain); if (_twain.State == 4) { _twain.CloseSource(); @@ -164,7 +168,7 @@ namespace Tester.Winform if (_twain.SupportedCaps.Contains(CapabilityId.CapUIControllable)) { // hide scanner ui if possible - if (_twain.EnableSource(SourceEnableMode.NoUI, false, this.Handle, SynchronizationContext.Current) == ReturnCode.Success) + if (_twain.EnableSource(SourceEnableMode.NoUI, false, this.Handle) == ReturnCode.Success) { btnStopScan.Enabled = true; btnStartCapture.Enabled = false; @@ -173,7 +177,7 @@ namespace Tester.Winform } else { - if (_twain.EnableSource(SourceEnableMode.ShowUI, true, this.Handle, SynchronizationContext.Current) == ReturnCode.Success) + if (_twain.EnableSource(SourceEnableMode.ShowUI, true, this.Handle) == ReturnCode.Success) { btnStopScan.Enabled = true; btnStartCapture.Enabled = false; @@ -229,7 +233,7 @@ namespace Tester.Winform { if (_twain.State < 3) { - _twain.OpenManager(this.Handle); + _twain.OpenManager(); } if (_twain.State >= 3) @@ -356,7 +360,7 @@ namespace Tester.Winform private void btnAllSettings_Click(object sender, EventArgs e) { - _twain.EnableSource(SourceEnableMode.ShowUIOnly, true, this.Handle, SynchronizationContext.Current); + _twain.EnableSource(SourceEnableMode.ShowUIOnly, true, this.Handle); } #endregion