Fixed creating/opening/closing twainsession multiple times in an app not working.

This commit is contained in:
soukoku
2014-08-14 07:34:55 -04:00
parent a8891efe3b
commit f073bc6b65
13 changed files with 147 additions and 53 deletions

View File

@@ -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); }

View File

@@ -16,7 +16,11 @@ namespace NTwain
internal abstract void Start(IWinMessageFilter filter);
internal abstract void Stop();
internal virtual void BeginInvoke(Action action)
/// <summary>
/// Asynchronously invokes the specified action on the message loop thread.
/// </summary>
/// <param name="action">The action.</param>
public virtual void BeginInvoke(Action action)
{
if (SyncContext == null)
{
@@ -30,7 +34,12 @@ namespace NTwain
}, null);
}
}
internal virtual void Invoke(Action action)
/// <summary>
/// Synchronously invokes the specified action on the message loop thread.
/// </summary>
/// <param name="action">The action.</param>
public virtual void Invoke(Action action)
{
if (SyncContext == null)
{

View File

@@ -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.4";
public const string Build = "2.0.5";
}
}

View File

@@ -54,12 +54,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;
}
/// <summary>

View File

@@ -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<object>();
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);
}
}
}

View File

@@ -17,11 +17,11 @@ namespace NTwain
/// </summary>
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
/// <returns></returns>
public ReturnCode StartTransfer(SourceEnableMode mode, bool modal, IntPtr windowHandle)
{
return _session.EnableSource(mode, modal, windowHandle);
return Session.EnableSource(mode, modal, windowHandle);
}
/// <summary>
@@ -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;
}
/// <summary>
@@ -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<CapabilityId>(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
///// <param name="propertyName">Name of the property.</param>
//protected void OnPropertyChanged(string propertyName)
//{
// var syncer = _session.SynchronizationContext;
// var syncer = Session.SynchronizationContext;
// if (syncer == null)
// {
// try

View File

@@ -1,7 +1,7 @@
<Application x:Class="Tester.WPF.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
StartupUri="Dummy.xaml">
<Application.Resources>
<ResourceDictionary>
<!-- Dummy Style, anything you won't use goes -->

View File

@@ -0,0 +1,12 @@
<Window x:Class="Tester.WPF.Dummy"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Dummy" Height="300" Width="300">
<Grid>
<StackPanel VerticalAlignment="Center">
<Button Content="Open scan window" Click="Button_Click" Margin="4 0"></Button>
<TextBlock Text="This is to test opening/closing multiple twain sessions in an app" Margin="8"
TextWrapping="Wrap"></TextBlock>
</StackPanel>
</Grid>
</Window>

View File

@@ -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
{
/// <summary>
/// Interaction logic for Dummy.xaml
/// </summary>
public partial class Dummy : Window
{
public Dummy()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
new MainWindow().ShowDialog();
}
}
}

View File

@@ -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();

View File

@@ -80,7 +80,14 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Dummy.xaml.cs">
<DependentUpon>Dummy.xaml</DependentUpon>
</Compile>
<Compile Include="ViewModels\TwainVM.cs" />
<Page Include="Dummy.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>

View File

@@ -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;

View File

@@ -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)