diff --git a/NTwain/DataTransferredEventArgs.cs b/NTwain/DataTransferredEventArgs.cs index 95f17f4..a6c3724 100644 --- a/NTwain/DataTransferredEventArgs.cs +++ b/NTwain/DataTransferredEventArgs.cs @@ -35,7 +35,7 @@ namespace NTwain /// The memory data. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] - public byte[] MemData { get; internal set; } + public byte[] MemoryData { get; internal set; } /// /// Gets the final image information if applicable. diff --git a/NTwain/Internals/InternalMessageLoopHook.cs b/NTwain/Internals/InternalMessageLoopHook.cs index 28379c8..6b622b9 100644 --- a/NTwain/Internals/InternalMessageLoopHook.cs +++ b/NTwain/Internals/InternalMessageLoopHook.cs @@ -9,7 +9,7 @@ using System.Windows.Threading; namespace NTwain.Internals { - sealed class InternalMessageLoopHook : MessageLoopHook + sealed class InternalMessageLoopHook : MessageLoopHook { Dispatcher _dispatcher; WindowsHook _hook; @@ -55,14 +55,14 @@ namespace NTwain.Internals } } - internal override void BeginInvoke(Action action) + public override void BeginInvoke(Action action) { if (_dispatcher == null) { throw new InvalidOperationException(Resources.MsgLoopUnavailble); } _dispatcher.BeginInvoke(DispatcherPriority.Normal, action); } - internal override void Invoke(Action action) + public override void Invoke(Action action) { if (_dispatcher == null) { throw new InvalidOperationException(Resources.MsgLoopUnavailble); } diff --git a/NTwain/Internals/MESSAGE.cs b/NTwain/Internals/MESSAGE.cs index 7a04c7c..1facde2 100644 --- a/NTwain/Internals/MESSAGE.cs +++ b/NTwain/Internals/MESSAGE.cs @@ -12,7 +12,7 @@ namespace NTwain.Internals /// The MSG structure in Windows for TWAIN use. /// [StructLayout(LayoutKind.Sequential)] - public struct MESSAGE + struct MESSAGE { public MESSAGE(IntPtr hwnd, int message, IntPtr wParam, IntPtr lParam) { diff --git a/NTwain/Internals/TransferLogic.cs b/NTwain/Internals/TransferLogic.cs index acff1bb..8ce7b62 100644 --- a/NTwain/Internals/TransferLogic.cs +++ b/NTwain/Internals/TransferLogic.cs @@ -118,9 +118,9 @@ namespace NTwain.Internals } while (rc == ReturnCode.Success && pending.Count != 0); - // some poorly written scanner drivers return failure on EndXfer so also check for pending count now + // some poorly written scanner drivers return failure on EndXfer so also check for pending count now. // this may break with other sources but we'll see - if (pending.Count == 0) + if (pending.Count == 0 && session.State > 5) { session.ChangeState(5, true); session.DisableSource(); @@ -441,7 +441,7 @@ namespace NTwain.Internals session.SafeSyncableRaiseEvent(new DataTransferredEventArgs { NativeData = dataPtr, - MemData = dataArray, + MemoryData = dataArray, FileDataPath = filePath, ImageInfo = imgInfo, //ExImageInfo = extInfo diff --git a/NTwain/MessageLoopHooks.cs b/NTwain/MessageLoopHooks.cs index 449942c..fd3fcd5 100644 --- a/NTwain/MessageLoopHooks.cs +++ b/NTwain/MessageLoopHooks.cs @@ -16,7 +16,11 @@ namespace NTwain internal abstract void Start(IWinMessageFilter filter); internal abstract void Stop(); - internal virtual void BeginInvoke(Action action) + /// + /// Asynchronously invokes the specified action on the message loop thread. + /// + /// The action. + public virtual void BeginInvoke(Action action) { if (SyncContext == null) { @@ -30,7 +34,12 @@ namespace NTwain }, null); } } - internal virtual void Invoke(Action action) + + /// + /// Synchronously invokes the specified action on the message loop thread. + /// + /// The action. + public virtual void Invoke(Action action) { if (SyncContext == null) { @@ -63,11 +72,11 @@ namespace NTwain /// /// Initializes a new instance of the class. /// - /// The handle to the app window. + /// The handle to the app window. /// A valid window handle is required. - public WindowsFormsMessageLoopHook(IntPtr hwnd) + public WindowsFormsMessageLoopHook(IntPtr windowHandle) { - if (hwnd == IntPtr.Zero) { throw new ArgumentException("A valid window handle is required."); } + if (windowHandle == IntPtr.Zero) { throw new ArgumentException("A valid window handle is required."); } if (!System.Windows.Forms.Application.MessageLoop) { @@ -78,7 +87,7 @@ namespace NTwain { ThrowInvalidOp(); } - Handle = hwnd; + Handle = windowHandle; SyncContext = sync; } internal override string InvalidMessage @@ -133,11 +142,11 @@ namespace NTwain /// /// Initializes a new instance of the class. /// - /// The handle to the app window. + /// The handle to the app window. /// A valid window handle is required. - public WpfMessageLoopHook(IntPtr hwnd) + public WpfMessageLoopHook(IntPtr windowHandle) { - if (hwnd == IntPtr.Zero) { throw new ArgumentException("A valid window handle is required."); } + if (windowHandle == IntPtr.Zero) { throw new ArgumentException("A valid window handle is required."); } if (System.Windows.Application.Current == null || !System.Windows.Application.Current.Dispatcher.CheckAccess()) @@ -149,7 +158,7 @@ namespace NTwain { ThrowInvalidOp(); } - Handle = hwnd; + Handle = windowHandle; SyncContext = sync; } internal override string InvalidMessage diff --git a/NTwain/Properties/VersionInfo.cs b/NTwain/Properties/VersionInfo.cs index 2f2ce7b..36dcc5a 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 = "2.0.0.0"; // change this for each nuget release - public const string Build = "2.0.3"; + public const string Build = "2.0.6"; } } \ No newline at end of file diff --git a/NTwain/Triplets/DGControl/DGControl.CapabilityCustom.cs b/NTwain/Triplets/DGControl/DGControl.CapabilityCustom.cs index 5f7d41c..1e5f2f4 100644 --- a/NTwain/Triplets/DGControl/DGControl.CapabilityCustom.cs +++ b/NTwain/Triplets/DGControl/DGControl.CapabilityCustom.cs @@ -16,6 +16,7 @@ namespace NTwain.Triplets /// The custom DAT_* value from manufacturer. /// The capability. /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "DAT")] public ReturnCode Get(ushort customDAT, TWCapability capability) { Session.VerifyState(4, 7, DataGroups.Control, (DataArgumentType)customDAT, Message.Get); @@ -28,6 +29,7 @@ namespace NTwain.Triplets /// The custom DAT_* value from manufacturer. /// The capability. /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "DAT")] public ReturnCode GetCurrent(ushort customDAT, TWCapability capability) { Session.VerifyState(4, 7, DataGroups.Control, (DataArgumentType)customDAT, Message.GetCurrent); @@ -40,6 +42,7 @@ namespace NTwain.Triplets /// The custom DAT_* value from manufacturer. /// The capability. /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "DAT")] public ReturnCode GetDefault(ushort customDAT, TWCapability capability) { Session.VerifyState(4, 7, DataGroups.Control, (DataArgumentType)customDAT, Message.GetDefault); @@ -53,6 +56,7 @@ namespace NTwain.Triplets /// The custom DAT_* value from manufacturer. /// The capability. /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "DAT")] public ReturnCode GetHelp(ushort customDAT, TWCapability capability) { Session.VerifyState(4, 4, DataGroups.Control, (DataArgumentType)customDAT, Message.GetHelp); @@ -66,6 +70,7 @@ namespace NTwain.Triplets /// The custom DAT_* value from manufacturer. /// The capability. /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "DAT")] public ReturnCode GetLabel(ushort customDAT, TWCapability capability) { Session.VerifyState(4, 4, DataGroups.Control, (DataArgumentType)customDAT, Message.GetLabel); @@ -79,6 +84,7 @@ namespace NTwain.Triplets /// The custom DAT_* value from manufacturer. /// The capability. /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "DAT")] public ReturnCode GetLabelEnum(ushort customDAT, TWCapability capability) { Session.VerifyState(4, 4, DataGroups.Control, (DataArgumentType)customDAT, Message.GetLabelEnum); @@ -91,6 +97,7 @@ namespace NTwain.Triplets /// The custom DAT_* value from manufacturer. /// The capability. /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "DAT")] public ReturnCode QuerySupport(ushort customDAT, TWCapability capability) { Session.VerifyState(4, 7, DataGroups.Control, (DataArgumentType)customDAT, Message.QuerySupport); @@ -104,6 +111,7 @@ namespace NTwain.Triplets /// The custom DAT_* value from manufacturer. /// The capability. /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "DAT")] public ReturnCode Reset(ushort customDAT, TWCapability capability) { Session.VerifyState(4, 4, DataGroups.Control, (DataArgumentType)customDAT, Message.Reset); @@ -117,6 +125,7 @@ namespace NTwain.Triplets /// The custom DAT_* value from manufacturer. /// The capability. /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "DAT")] public ReturnCode ResetAll(ushort customDAT, TWCapability capability) { Session.VerifyState(4, 4, DataGroups.Control, (DataArgumentType)customDAT, Message.ResetAll); @@ -133,6 +142,7 @@ namespace NTwain.Triplets /// The custom DAT_* value from manufacturer. /// The capability. /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "DAT")] public ReturnCode Set(ushort customDAT, TWCapability capability) { Session.VerifyState(4, 6, DataGroups.Control, (DataArgumentType)customDAT, Message.Set); @@ -148,6 +158,7 @@ namespace NTwain.Triplets /// The custom DAT_* value from manufacturer. /// The capability. /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "DAT")] public ReturnCode SetConstraint(ushort customDAT, TWCapability capability) { Session.VerifyState(4, 7, DataGroups.Control, (DataArgumentType)customDAT, Message.SetConstraint); diff --git a/NTwain/Triplets/DGControl/DGControl.SetupFileXfer.cs b/NTwain/Triplets/DGControl/DGControl.SetupFileXfer.cs index 296c21f..62dac5b 100644 --- a/NTwain/Triplets/DGControl/DGControl.SetupFileXfer.cs +++ b/NTwain/Triplets/DGControl/DGControl.SetupFileXfer.cs @@ -16,7 +16,7 @@ namespace NTwain.Triplets /// /// The setup file xfer. /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xfer"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#")] public ReturnCode Get(out TWSetupFileXfer setupFileXfer) { Session.VerifyState(4, 6, DataGroups.Control, DataArgumentType.SetupFileXfer, Message.Get); @@ -29,7 +29,7 @@ namespace NTwain.Triplets /// /// The setup file xfer. /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xfer"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#")] public ReturnCode GetDefault(out TWSetupFileXfer setupFileXfer) { Session.VerifyState(4, 6, DataGroups.Control, DataArgumentType.SetupFileXfer, Message.GetDefault); @@ -43,7 +43,7 @@ namespace NTwain.Triplets /// /// The setup file xfer. /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xfer"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#")] public ReturnCode Reset(out TWSetupFileXfer setupFileXfer) { Session.VerifyState(4, 4, DataGroups.Control, DataArgumentType.SetupFileXfer, Message.Reset); @@ -60,7 +60,8 @@ namespace NTwain.Triplets /// /// The setup file xfer. /// - public ReturnCode Set(TWSetupFileXfer setupFileXfer) + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xfer")] + public ReturnCode Set(TWSetupFileXfer setupFileXfer) { Session.VerifyState(4, 6, DataGroups.Control, DataArgumentType.SetupFileXfer, Message.Set); return Dsm.DsmEntry(Session.AppId, Session.CurrentSource.Identity, Message.Set, setupFileXfer); diff --git a/NTwain/Triplets/DGControl/DGControl.SetupMemXfer.cs b/NTwain/Triplets/DGControl/DGControl.SetupMemXfer.cs index 6c30f10..900d0a8 100644 --- a/NTwain/Triplets/DGControl/DGControl.SetupMemXfer.cs +++ b/NTwain/Triplets/DGControl/DGControl.SetupMemXfer.cs @@ -6,7 +6,7 @@ namespace NTwain.Triplets /// /// Represents . /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Mem")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xfer"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Mem")] public sealed class SetupMemXfer : OpBase { internal SetupMemXfer(ITwainSessionInternal session) : base(session) { } @@ -16,7 +16,7 @@ namespace NTwain.Triplets /// /// The setup mem xfer. /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Mem"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xfer"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#")] public ReturnCode Get(out TWSetupMemXfer setupMemXfer) { Session.VerifyState(4, 6, DataGroups.Control, DataArgumentType.SetupMemXfer, Message.Get); diff --git a/NTwain/Triplets/DGControl/DGControl.XferGroup.cs b/NTwain/Triplets/DGControl/DGControl.XferGroup.cs index 181298f..25209d8 100644 --- a/NTwain/Triplets/DGControl/DGControl.XferGroup.cs +++ b/NTwain/Triplets/DGControl/DGControl.XferGroup.cs @@ -6,7 +6,8 @@ namespace NTwain.Triplets /// /// Represents . /// - public sealed class XferGroup : OpBase + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xfer")] + public sealed class XferGroup : OpBase { internal XferGroup(ITwainSessionInternal session) : base(session) { } diff --git a/NTwain/Triplets/DGCustom.cs b/NTwain/Triplets/DGCustom.cs index 2aef0bd..1d5d320 100644 --- a/NTwain/Triplets/DGCustom.cs +++ b/NTwain/Triplets/DGCustom.cs @@ -28,6 +28,7 @@ namespace NTwain.Triplets /// The message. /// The data. /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "3#"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dat"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dsm")] public ReturnCode DsmEntry( DataGroups group, DataArgumentType dat, diff --git a/NTwain/Triplets/DGImage/DGImage.CieColor.cs b/NTwain/Triplets/DGImage/DGImage.CieColor.cs index 5b173cf..cdd687b 100644 --- a/NTwain/Triplets/DGImage/DGImage.CieColor.cs +++ b/NTwain/Triplets/DGImage/DGImage.CieColor.cs @@ -6,7 +6,8 @@ namespace NTwain.Triplets /// /// Represents . /// - public sealed class CieColor : OpBase + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Cie")] + public sealed class CieColor : OpBase { internal CieColor(ITwainSessionInternal session) : base(session) { } @@ -16,7 +17,7 @@ namespace NTwain.Triplets /// /// Color data. /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "cie"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#")] public ReturnCode Get(out TWCieColor cieColor) { Session.VerifyState(4, 6, DataGroups.Image, DataArgumentType.CieColor, Message.Get); diff --git a/NTwain/Triplets/DGImage/DGImage.IccProfile.cs b/NTwain/Triplets/DGImage/DGImage.IccProfile.cs index 78e9250..87249a8 100644 --- a/NTwain/Triplets/DGImage/DGImage.IccProfile.cs +++ b/NTwain/Triplets/DGImage/DGImage.IccProfile.cs @@ -6,7 +6,8 @@ namespace NTwain.Triplets /// /// Represents . /// - public sealed class IccProfile : OpBase + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Icc")] + public sealed class IccProfile : OpBase { internal IccProfile(ITwainSessionInternal session) : base(session) { } diff --git a/NTwain/Triplets/DGImage/DGImage.RgbResponse.cs b/NTwain/Triplets/DGImage/DGImage.RgbResponse.cs index 62abc97..8a7b8fb 100644 --- a/NTwain/Triplets/DGImage/DGImage.RgbResponse.cs +++ b/NTwain/Triplets/DGImage/DGImage.RgbResponse.cs @@ -6,7 +6,8 @@ namespace NTwain.Triplets /// /// Represents . /// - public sealed class RgbResponse : OpBase + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Rgb")] + public sealed class RgbResponse : OpBase { internal RgbResponse(ITwainSessionInternal session) : base(session) { } diff --git a/NTwain/Triplets/DGImage/DGImage.cs b/NTwain/Triplets/DGImage/DGImage.cs index 734fe37..339b834 100644 --- a/NTwain/Triplets/DGImage/DGImage.cs +++ b/NTwain/Triplets/DGImage/DGImage.cs @@ -19,6 +19,7 @@ namespace NTwain.Triplets /// /// Gets the operations defined for DAT_CIECOLOR. /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Cie")] public CieColor CieColor { get @@ -73,6 +74,7 @@ namespace NTwain.Triplets /// /// Gets the operations defined for DAT_ICCPROFILE. /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Icc")] public IccProfile IccProfile { get @@ -175,6 +177,7 @@ namespace NTwain.Triplets /// /// Gets the operations defined for DAT_RGBRESPONSE. /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Rgb")] public RgbResponse RgbResponse { get diff --git a/NTwain/TwainSession.cs b/NTwain/TwainSession.cs index a1c5a60..0571ed2 100644 --- a/NTwain/TwainSession.cs +++ b/NTwain/TwainSession.cs @@ -41,7 +41,10 @@ namespace NTwain _appId = appId; ((ITwainSessionInternal)this).ChangeState(1, false); +#if DEBUG + // defaults to false on release since it's only useful during dev EnforceState = true; +#endif } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] @@ -54,12 +57,18 @@ namespace NTwain internal static TwainSource GetSourceInstance(ITwainSessionInternal session, TWIdentity sourceId) { + TwainSource source = null; var key = string.Format(CultureInfo.InvariantCulture, "{0}|{1}|{2}", sourceId.Manufacturer, sourceId.ProductFamily, sourceId.ProductName); if (__ownedSources.ContainsKey(key)) { - return __ownedSources[key]; + source = __ownedSources[key]; + source.Session = session; } - return __ownedSources[key] = new TwainSource(session, sourceId); + else + { + __ownedSources[key] = source = new TwainSource(session, sourceId); + } + return source; } /// @@ -428,7 +437,7 @@ namespace NTwain _msgLoopHook.Invoke(() => { - Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: EnableSource.", Thread.CurrentThread.ManagedThreadId)); + Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: EnableSource with {1}.", Thread.CurrentThread.ManagedThreadId, mode)); // app v2.2 or higher uses callback2 if (_appId.ProtocolMajor >= 2 && _appId.ProtocolMinor >= 2) @@ -477,21 +486,32 @@ namespace NTwain return rc; } + bool _disabling; ReturnCode ITwainSessionInternal.DisableSource() { var rc = ReturnCode.Failure; - - _msgLoopHook.Invoke(() => + if (!_disabling) // temp hack as a workaround to this being called from multiple threads (xfer logic & closedsreq msg) { - Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: DisableSource.", Thread.CurrentThread.ManagedThreadId)); - - rc = ((ITwainSessionInternal)this).DGControl.UserInterface.DisableDS(_twui); - if (rc == ReturnCode.Success) + _disabling = true; + try { - _callbackObj = null; - SafeAsyncSyncableRaiseOnEvent(OnSourceDisabled, SourceDisabled); + _msgLoopHook.Invoke(() => + { + Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: DisableSource.", Thread.CurrentThread.ManagedThreadId)); + + rc = ((ITwainSessionInternal)this).DGControl.UserInterface.DisableDS(_twui); + if (rc == ReturnCode.Success) + { + _callbackObj = null; + SafeAsyncSyncableRaiseOnEvent(OnSourceDisabled, SourceDisabled); + } + }); } - }); + finally + { + _disabling = false; + } + } return rc; } @@ -524,15 +544,15 @@ namespace NTwain _msgLoopHook.Invoke(() => { - if (targetState < 7) + if (targetState < 7 && CurrentSource != null) { ((ITwainSessionInternal)this).DGControl.PendingXfers.EndXfer(new TWPendingXfers()); } - if (targetState < 6) + if (targetState < 6 && CurrentSource != null) { ((ITwainSessionInternal)this).DGControl.PendingXfers.Reset(new TWPendingXfers()); } - if (targetState < 5) + if (targetState < 5 && CurrentSource != null) { ((ITwainSessionInternal)this).DisableSource(); } @@ -782,6 +802,7 @@ namespace NTwain break; case Message.CloseDSReq: case Message.CloseDSOK: + Debug.WriteLine("Got msg " + msg); // even though it says closeDS it's really disable. // dsok is sent if source is enabled with uionly diff --git a/NTwain/TwainSource.Caps.cs b/NTwain/TwainSource.Caps.cs index 7b01ad1..3948aae 100644 --- a/NTwain/TwainSource.Caps.cs +++ b/NTwain/TwainSource.Caps.cs @@ -18,7 +18,7 @@ namespace NTwain QuerySupport retVal = QuerySupport.None; using (TWCapability cap = new TWCapability(capId)) { - var rc = _session.DGControl.Capability.QuerySupport(cap); + var rc = Session.DGControl.Capability.QuerySupport(cap); if (rc == ReturnCode.Success) { var read = CapabilityReader.ReadValue(cap); @@ -41,7 +41,7 @@ namespace NTwain { using (TWCapability cap = new TWCapability(capId)) { - var rc = _session.DGControl.Capability.GetCurrent(cap); + var rc = Session.DGControl.Capability.GetCurrent(cap); if (rc == ReturnCode.Success) { var read = CapabilityReader.ReadValue(cap); @@ -82,7 +82,7 @@ namespace NTwain var list = new List(); using (TWCapability cap = new TWCapability(capabilityId)) { - var rc = _session.DGControl.Capability.Get(cap); + var rc = Session.DGControl.Capability.Get(cap); if (rc == ReturnCode.Success) { cap.ReadMultiCapValues(list); @@ -126,7 +126,7 @@ namespace NTwain { using (TWCapability compressCap = new TWCapability(CapabilityId.ICapCompression, new TWOneValue { Item = (uint)compression, ItemType = ItemType.UInt16 })) { - return _session.DGControl.Capability.Set(compressCap); + return Session.DGControl.Capability.Set(compressCap); } } @@ -153,7 +153,7 @@ namespace NTwain { using (TWCapability formatCap = new TWCapability(CapabilityId.ICapImageFileFormat, new TWOneValue { Item = (uint)format, ItemType = ItemType.UInt16 })) { - return _session.DGControl.Capability.Set(formatCap); + return Session.DGControl.Capability.Set(formatCap); } } @@ -183,7 +183,7 @@ namespace NTwain one.ItemType = ItemType.UInt16; using (TWCapability dx = new TWCapability(CapabilityId.ICapPixelType, one)) { - return _session.DGControl.Capability.Set(dx); + return Session.DGControl.Capability.Set(dx); } } @@ -223,7 +223,7 @@ namespace NTwain one.ItemType = ItemType.UInt16; using (TWCapability dx = new TWCapability(CapabilityId.ICapXferMech, one)) { - return _session.DGControl.Capability.Set(dx); + return Session.DGControl.Capability.Set(dx); } } @@ -239,7 +239,7 @@ namespace NTwain one.ItemType = ItemType.UInt16; using (TWCapability dx = new TWCapability(CapabilityId.ACapXferMech, one)) { - return _session.DGControl.Capability.Set(dx); + return Session.DGControl.Capability.Set(dx); } } @@ -282,13 +282,13 @@ namespace NTwain using (TWCapability xres = new TWCapability(CapabilityId.ICapXResolution, one)) { - var rc = _session.DGControl.Capability.Set(xres); + var rc = Session.DGControl.Capability.Set(xres); if (rc == ReturnCode.Success) { one.Item = (uint)yDPI; using (TWCapability yres = new TWCapability(CapabilityId.ICapYResolution, one)) { - rc = _session.DGControl.Capability.Set(yres); + rc = Session.DGControl.Capability.Set(yres); } } return rc; @@ -322,7 +322,7 @@ namespace NTwain using (TWCapability xres = new TWCapability(CapabilityId.ICapSupportedSizes, one)) { - var rc = _session.DGControl.Capability.Set(xres); + var rc = Session.DGControl.Capability.Set(xres); return rc; } } @@ -351,7 +351,7 @@ namespace NTwain using (TWCapability dx = new TWCapability(CapabilityId.ICapAutomaticDeskew, en)) { - rc = _session.DGControl.Capability.Set(dx); + rc = Session.DGControl.Capability.Set(dx); } } else @@ -362,7 +362,7 @@ namespace NTwain using (TWCapability capValue = new TWCapability(CapabilityId.ICapAutomaticDeskew, one)) { - rc = _session.DGControl.Capability.Set(capValue); + rc = Session.DGControl.Capability.Set(capValue); } } } @@ -389,7 +389,7 @@ namespace NTwain using (TWCapability dx = new TWCapability(CapabilityId.ICapAutomaticRotate, en)) { - rc = _session.DGControl.Capability.Set(dx); + rc = Session.DGControl.Capability.Set(dx); } } else @@ -400,7 +400,7 @@ namespace NTwain using (TWCapability capValue = new TWCapability(CapabilityId.ICapAutomaticRotate, one)) { - rc = _session.DGControl.Capability.Set(capValue); + rc = Session.DGControl.Capability.Set(capValue); } } } @@ -428,11 +428,11 @@ namespace NTwain using (TWCapability dx = new TWCapability(CapabilityId.ICapUndefinedImageSize, en)) { - rc = _session.DGControl.Capability.Set(dx); + rc = Session.DGControl.Capability.Set(dx); } using (TWCapability dx = new TWCapability(CapabilityId.ICapAutomaticBorderDetection, en)) { - rc = _session.DGControl.Capability.Set(dx); + rc = Session.DGControl.Capability.Set(dx); } } else @@ -443,11 +443,11 @@ namespace NTwain using (TWCapability capValue = new TWCapability(CapabilityId.ICapUndefinedImageSize, one)) { - rc = _session.DGControl.Capability.Set(capValue); + rc = Session.DGControl.Capability.Set(capValue); } using (TWCapability capValue = new TWCapability(CapabilityId.ICapAutomaticBorderDetection, one)) { - rc = _session.DGControl.Capability.Set(capValue); + rc = Session.DGControl.Capability.Set(capValue); } } } @@ -471,7 +471,7 @@ namespace NTwain using (TWCapability dx = new TWCapability(CapabilityId.CapDuplexEnabled, en)) { - return _session.DGControl.Capability.Set(dx); + return Session.DGControl.Capability.Set(dx); } } else @@ -482,7 +482,7 @@ namespace NTwain using (TWCapability dx = new TWCapability(CapabilityId.CapDuplexEnabled, one)) { - return _session.DGControl.Capability.Set(dx); + return Session.DGControl.Capability.Set(dx); } } } @@ -512,7 +512,7 @@ namespace NTwain { using (TWCapability dx = new TWCapability(CapabilityId.CapFeederEnabled, en)) { - rc = _session.DGControl.Capability.Set(dx); + rc = Session.DGControl.Capability.Set(dx); } } @@ -522,14 +522,14 @@ namespace NTwain { using (TWCapability dx = new TWCapability(CapabilityId.CapAutoScan, en)) { - rc = _session.DGControl.Capability.Set(dx); + rc = Session.DGControl.Capability.Set(dx); } } else if (SupportedCaps.Contains(CapabilityId.CapAutoFeed)) { using (TWCapability dx = new TWCapability(CapabilityId.CapAutoFeed, en)) { - rc = _session.DGControl.Capability.Set(dx); + rc = Session.DGControl.Capability.Set(dx); } } } @@ -543,7 +543,7 @@ namespace NTwain { using (TWCapability enabled = new TWCapability(CapabilityId.CapFeederEnabled, one)) { - rc = _session.DGControl.Capability.Set(enabled); + rc = Session.DGControl.Capability.Set(enabled); } } // to really use feeder we must also set autofeed or autoscan, but only @@ -552,14 +552,14 @@ namespace NTwain { using (TWCapability autoScan = new TWCapability(CapabilityId.CapAutoScan, one)) { - rc = _session.DGControl.Capability.Set(autoScan); + rc = Session.DGControl.Capability.Set(autoScan); } } else if (SupportedCaps.Contains(CapabilityId.CapAutoFeed)) { using (TWCapability autoScan = new TWCapability(CapabilityId.CapAutoFeed, one)) { - rc = _session.DGControl.Capability.Set(autoScan); + rc = Session.DGControl.Capability.Set(autoScan); } } } diff --git a/NTwain/TwainSource.cs b/NTwain/TwainSource.cs index b9b2736..eb064f6 100644 --- a/NTwain/TwainSource.cs +++ b/NTwain/TwainSource.cs @@ -17,11 +17,11 @@ namespace NTwain /// public partial class TwainSource { - ITwainSessionInternal _session; + internal ITwainSessionInternal Session { get; set; } internal TwainSource(ITwainSessionInternal session, TWIdentity sourceId) { - _session = session; + Session = session; Identity = sourceId; } @@ -32,11 +32,11 @@ namespace NTwain public ReturnCode Open() { var rc = ReturnCode.Failure; - _session.MessageLoopHook.Invoke(() => + Session.MessageLoopHook.Invoke(() => { Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: OpenSource.", Thread.CurrentThread.ManagedThreadId)); - rc = _session.DGControl.Identity.OpenDS(this); + rc = Session.DGControl.Identity.OpenDS(this); }); return rc; } @@ -48,11 +48,11 @@ namespace NTwain public ReturnCode Close() { var rc = ReturnCode.Failure; - _session.MessageLoopHook.Invoke(() => + Session.MessageLoopHook.Invoke(() => { Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, "Thread {0}: CloseSource.", Thread.CurrentThread.ManagedThreadId)); - rc = _session.DGControl.Identity.CloseDS(); + rc = Session.DGControl.Identity.CloseDS(); if (rc == ReturnCode.Success) { SupportedCaps = null; @@ -71,7 +71,7 @@ namespace NTwain /// public ReturnCode StartTransfer(SourceEnableMode mode, bool modal, IntPtr windowHandle) { - return _session.EnableSource(mode, modal, windowHandle); + return Session.EnableSource(mode, modal, windowHandle); } /// @@ -81,7 +81,7 @@ namespace NTwain public TWStatus GetStatus() { TWStatus stat; - _session.DGControl.Status.GetSource(out stat); + Session.DGControl.Status.GetSource(out stat); return stat; } /// @@ -91,7 +91,7 @@ namespace NTwain public TWStatusUtf8 GetStatusUtf8() { TWStatusUtf8 stat; - _session.DGControl.StatusUtf8.GetSource(out stat); + Session.DGControl.StatusUtf8.GetSource(out stat); return stat; } @@ -170,7 +170,7 @@ namespace NTwain { get { - if (_supportedCaps == null && _session.State > 3) + if (_supportedCaps == null && Session.State > 3) { _supportedCaps = CapGetValues(CapabilityId.CapSupportedCaps).CastToEnum(false); } @@ -191,7 +191,7 @@ namespace NTwain { get { - return _session.DGControl; + return Session.DGControl; } } @@ -202,7 +202,7 @@ namespace NTwain { get { - return _session.DGImage; + return Session.DGImage; } } @@ -213,7 +213,7 @@ namespace NTwain { get { - return _session.DGCustom; + return Session.DGCustom; } } @@ -232,7 +232,7 @@ namespace NTwain ///// Name of the property. //protected void OnPropertyChanged(string propertyName) //{ - // var syncer = _session.SynchronizationContext; + // var syncer = Session.SynchronizationContext; // if (syncer == null) // { // try diff --git a/Tests/Tester.WPF/App.xaml b/Tests/Tester.WPF/App.xaml index d733b8c..9ea9427 100644 --- a/Tests/Tester.WPF/App.xaml +++ b/Tests/Tester.WPF/App.xaml @@ -1,7 +1,7 @@  + StartupUri="Dummy.xaml"> diff --git a/Tests/Tester.WPF/Dummy.xaml b/Tests/Tester.WPF/Dummy.xaml new file mode 100644 index 0000000..9304408 --- /dev/null +++ b/Tests/Tester.WPF/Dummy.xaml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/Tests/Tester.WPF/Dummy.xaml.cs b/Tests/Tester.WPF/Dummy.xaml.cs new file mode 100644 index 0000000..8c055a9 --- /dev/null +++ b/Tests/Tester.WPF/Dummy.xaml.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +namespace Tester.WPF +{ + /// + /// Interaction logic for Dummy.xaml + /// + public partial class Dummy : Window + { + public Dummy() + { + InitializeComponent(); + } + + private void Button_Click(object sender, RoutedEventArgs e) + { + new MainWindow().ShowDialog(); + } + } +} diff --git a/Tests/Tester.WPF/MainWindow.xaml.cs b/Tests/Tester.WPF/MainWindow.xaml.cs index 72a3198..c5b167b 100644 --- a/Tests/Tester.WPF/MainWindow.xaml.cs +++ b/Tests/Tester.WPF/MainWindow.xaml.cs @@ -4,6 +4,7 @@ using NTwain; using NTwain.Data; using System; using System.ComponentModel; +using System.Diagnostics; using System.Linq; using System.Windows; using System.Windows.Controls; @@ -51,13 +52,18 @@ namespace Tester.WPF }); } } - + protected override void OnClosing(CancelEventArgs e) + { + e.Cancel = _twainVM.State > 4; + base.OnClosing(e); + } protected override void OnClosed(EventArgs e) { if (_twainVM.State == 4) { _twainVM.CurrentSource.Close(); } + _twainVM.Close(); base.OnClosed(e); } @@ -68,6 +74,8 @@ namespace Tester.WPF // use this for internal msg loop //var rc = _twainVM.Open(); // use this to hook into current app loop + + var rc = _twainVM.Open(new WpfMessageLoopHook(new WindowInteropHelper(this).Handle)); if (rc == ReturnCode.Success) @@ -82,6 +90,15 @@ namespace Tester.WPF private void SrcList_SelectionChanged(object sender, SelectionChangedEventArgs e) { + + //var test = new NTwain.Internals.InternalMessageLoopHook(); + //test.StartTest(); + //test.BeginInvoke(() => + //{ + // Debug.WriteLine("doodle"); + // test.StopTest(); + //}); + if (_twainVM.State == 4) { _twainVM.CurrentSource.Close(); diff --git a/Tests/Tester.WPF/Tester.WPF.csproj b/Tests/Tester.WPF/Tester.WPF.csproj index b7b2cd3..54e4e0b 100644 --- a/Tests/Tester.WPF/Tester.WPF.csproj +++ b/Tests/Tester.WPF/Tester.WPF.csproj @@ -80,7 +80,14 @@ MSBuild:Compile Designer + + Dummy.xaml + + + Designer + MSBuild:Compile + MSBuild:Compile Designer diff --git a/Tests/Tester.WPF/ViewModels/TwainVM.cs b/Tests/Tester.WPF/ViewModels/TwainVM.cs index 8153351..51ece2a 100644 --- a/Tests/Tester.WPF/ViewModels/TwainVM.cs +++ b/Tests/Tester.WPF/ViewModels/TwainVM.cs @@ -3,6 +3,7 @@ using GalaSoft.MvvmLight.Messaging; using NTwain; using NTwain.Data; using System; +using System.IO; using System.Reflection; using System.Threading; using System.Windows.Media; @@ -76,12 +77,23 @@ namespace Tester.WPF var fileSetup = new TWSetupFileXfer { Format = wantFormat, - FileName = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.tif") + FileName = GetUniqueName(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test", ".tif") }; var rc = this.CurrentSource.DGControl.SetupFileXfer.Set(fileSetup); } } + private string GetUniqueName(string dir, string name, string ext) + { + var filePath = Path.Combine(dir, name + ext); + int next = 1; + while (File.Exists(filePath)) + { + filePath = Path.Combine(dir, string.Format("{0} ({1}){2}", name, next++, ext)); + } + return filePath; + } + protected override void OnDataTransferred(DataTransferredEventArgs e) { ImageSource img = null; diff --git a/Tests/Tester.Winform/TestForm.cs b/Tests/Tester.Winform/TestForm.cs index bebe5f1..dad7dbb 100644 --- a/Tests/Tester.Winform/TestForm.cs +++ b/Tests/Tester.Winform/TestForm.cs @@ -41,13 +41,16 @@ namespace Tester.Winform protected override void OnFormClosing(FormClosingEventArgs e) { - if (e.CloseReason == CloseReason.UserClosing && _twain.State > 4) + if (_twain != null) { - e.Cancel = true; - } - else - { - CleanupTwain(); + if (e.CloseReason == CloseReason.UserClosing && _twain.State > 4) + { + e.Cancel = true; + } + else + { + CleanupTwain(); + } } base.OnFormClosing(e); } @@ -105,22 +108,19 @@ namespace Tester.Winform private void CleanupTwain() { - if (_twain != null) + if (_twain.State == 4) { - if (_twain.State == 4) - { - _twain.CurrentSource.Close(); - } - if (_twain.State == 3) - { - _twain.Close(); - } + _twain.CurrentSource.Close(); + } + if (_twain.State == 3) + { + _twain.Close(); + } - if (_twain.State > 2) - { - // normal close down didn't work, do hard kill - _twain.ForceStepDown(2); - } + if (_twain.State > 2) + { + // normal close down didn't work, do hard kill + _twain.ForceStepDown(2); } } @@ -245,7 +245,7 @@ namespace Tester.Winform // use this for internal msg loop _twain.Open(); // use this to hook into current app loop - //_twain.Open(new WinformMessageLoopHook(this.Handle)); + //_twain.Open(new WindowsFormsMessageLoopHook(this.Handle)); } if (_twain.State >= 3)