Added source selection methods.

This commit is contained in:
Eugene Wang
2018-11-13 21:02:29 -05:00
parent 63526070f8
commit 485810d46f
11 changed files with 265 additions and 21 deletions

View File

@@ -15,6 +15,7 @@ namespace NetCoreConsole
.Build(); .Build();
Console.WriteLine($"App = {(config.Is64Bit ? "64bit" : "32bit")}"); Console.WriteLine($"App = {(config.Is64Bit ? "64bit" : "32bit")}");
Console.WriteLine($"Platform = {config.Platform}"); Console.WriteLine($"Platform = {config.Platform}");
Console.WriteLine();
using (var session = new TwainSession(config)) using (var session = new TwainSession(config))
{ {
@@ -23,18 +24,33 @@ namespace NetCoreConsole
var handle = IntPtr.Zero; var handle = IntPtr.Zero;
if (session.Open(ref handle) == NTwain.Data.ReturnCode.Success) if (session.Open(ref handle) == NTwain.Data.ReturnCode.Success)
{ {
Console.WriteLine("Available data sources:");
foreach (var src in session.GetSources())
{
Console.WriteLine($"\t{src}");
}
Console.WriteLine();
var defaultSrc = session.DefaultSource;
Console.WriteLine($"Default data source = {defaultSrc}");
Console.WriteLine();
var selectSrc = session.ShowSourceSelector();
Console.WriteLine($"Selected data source = {selectSrc}");
Console.WriteLine();
//session.DefaultSource = null;
} }
} }
Console.WriteLine("Test ended, press Enter to exit...");
Console.ReadLine();
} }
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine("ERROR: " + ex.ToString()); Console.WriteLine("ERROR: " + ex.ToString());
} }
Console.WriteLine("Test ended, press Enter to exit...");
Console.ReadLine();
} }
private static void Session_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) private static void Session_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)

View File

@@ -310,7 +310,7 @@ namespace NTwain.Data
partial class TW_IDENTITY partial class TW_IDENTITY
{ {
// TODO: id needs to be 64bit in 64bit? // TODO: id needs to be 64bit in 64bit?
TW_UINT32 _id; internal TW_UINT32 Id;
TW_VERSION _version; TW_VERSION _version;
TW_UINT16 _protocolMajor; TW_UINT16 _protocolMajor;
TW_UINT16 _protocolMinor; TW_UINT16 _protocolMinor;

View File

@@ -1584,7 +1584,8 @@ namespace NTwain.Data
/// </returns> /// </returns>
public override string ToString() public override string ToString()
{ {
return string.Format(CultureInfo.InvariantCulture, "{0}.{1} {2}", Major, Minor, Info); if (Info == null) return $"v{Major}.{Minor}";
return $"v{Major}.{Minor} ({Info})";
} }
#region equals #region equals

45
src/NTwain/DataSource.cs Normal file
View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NTwain.Data;
namespace NTwain
{
/// <summary>
/// A TWAIN data source.
/// </summary>
public class DataSource
{
internal readonly TwainSession Session;
internal TW_IDENTITY Identity { get; }
internal DataSource(TwainSession session, TW_IDENTITY src)
{
this.Session = session;
this.Identity = src;
}
/// <summary>
/// Gets the source name.
/// </summary>
public string Name => Identity.ProductName;
/// <summary>
/// Gets the source version info.
/// </summary>
public TW_VERSION Version => Identity.Version;
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString()
{
return $"{Name} {Version}";
}
}
}

View File

@@ -1,12 +1,25 @@
namespace NTwain.Triplets using System;
namespace NTwain.Triplets
{ {
/// <summary>
/// Base class for grouping triplet operations.
/// </summary>
public abstract class BaseTriplet public abstract class BaseTriplet
{ {
protected TwainSession session; /// <summary>
/// Gets the associated <see cref="TwainSession"/>.
/// </summary>
protected readonly TwainSession Session;
public BaseTriplet(TwainSession session) /// <summary>
/// Initializes a new instance of the <see cref="BaseTriplet" /> class.
/// </summary>
/// <param name="session">The session.</param>
/// <exception cref="System.ArgumentNullException"></exception>
protected BaseTriplet(TwainSession session)
{ {
this.session = session; this.Session = session ?? throw new ArgumentNullException(nameof(session));
} }
} }
} }

View File

@@ -13,7 +13,7 @@ namespace NTwain.Triplets
public ReturnCode Get(out TW_ENTRYPOINT entryPoint) public ReturnCode Get(out TW_ENTRYPOINT entryPoint)
{ {
entryPoint = new TW_ENTRYPOINT(); entryPoint = new TW_ENTRYPOINT();
return NativeMethods.DsmWin32(session.Config.AppWin32, null, return NativeMethods.DsmWin32(Session.Config.AppWin32, null,
DataGroups.Control, DataArgumentType.EntryPoint, Message.Get, entryPoint); DataGroups.Control, DataArgumentType.EntryPoint, Message.Get, entryPoint);
} }
} }

View File

@@ -0,0 +1,70 @@
using NTwain.Data;
using NTwain.Internals;
using System;
namespace NTwain.Triplets
{
sealed class Identity : BaseTriplet
{
internal Identity(TwainSession session) : base(session) { }
public ReturnCode CloseDS(TW_IDENTITY source)
{
var rc = NativeMethods.DsmWin32(Session.Config.AppWin32, IntPtr.Zero,
DataGroups.Control, DataArgumentType.Identity, Message.CloseDS, source);
if (rc == ReturnCode.Success)
{
Session.State = TwainState.S3;
Session.CurrentSource = null;
}
return rc;
}
public ReturnCode GetDefault(out TW_IDENTITY source)
{
source = new TW_IDENTITY();
return NativeMethods.DsmWin32(Session.Config.AppWin32, IntPtr.Zero,
DataGroups.Control, DataArgumentType.Identity, Message.GetDefault, source);
}
public ReturnCode GetFirst(out TW_IDENTITY source)
{
source = new TW_IDENTITY();
return NativeMethods.DsmWin32(Session.Config.AppWin32, IntPtr.Zero,
DataGroups.Control, DataArgumentType.Identity, Message.GetFirst, source);
}
public ReturnCode GetNext(out TW_IDENTITY source)
{
source = new TW_IDENTITY();
return NativeMethods.DsmWin32(Session.Config.AppWin32, IntPtr.Zero,
DataGroups.Control, DataArgumentType.Identity, Message.GetNext, source);
}
public ReturnCode OpenDS(TW_IDENTITY source)
{
var rc = NativeMethods.DsmWin32(Session.Config.AppWin32, IntPtr.Zero,
DataGroups.Control, DataArgumentType.Identity, Message.OpenDS, source);
if (rc == ReturnCode.Success)
{
Session.CurrentSource = Session.GetSourceSingleton(source);
Session.State = TwainState.S4;
}
return rc;
}
public ReturnCode Set(DataSource source)
{
return NativeMethods.DsmWin32(Session.Config.AppWin32, IntPtr.Zero,
DataGroups.Control, DataArgumentType.Identity, Message.Set, source?.Identity);
}
public ReturnCode UserSelect(out TW_IDENTITY source)
{
source = new TW_IDENTITY();
return NativeMethods.DsmWin32(Session.Config.AppWin32, IntPtr.Zero,
DataGroups.Control, DataArgumentType.Identity, Message.UserSelect, source);
}
}
}

View File

@@ -12,20 +12,20 @@ namespace NTwain.Triplets
public ReturnCode OpenDSM(ref IntPtr hWnd) public ReturnCode OpenDSM(ref IntPtr hWnd)
{ {
var rc = NativeMethods.DsmWin32(session.Config.AppWin32, null, var rc = NativeMethods.DsmWin32(Session.Config.AppWin32, null,
DataGroups.Control, DataArgumentType.Parent, Message.OpenDSM, ref hWnd); DataGroups.Control, DataArgumentType.Parent, Message.OpenDSM, ref hWnd);
if (rc == ReturnCode.Success) if (rc == ReturnCode.Success)
{ {
session.State = TwainState.DsmOpened; Session.State = TwainState.DsmOpened;
// if twain2 then get memory management functions // if twain2 then get memory management functions
if ((session.Config.AppWin32.DataFunctionalities & DataFunctionalities.Dsm2) == DataFunctionalities.Dsm2) if ((Session.Config.AppWin32.DataFunctionalities & DataFunctionalities.Dsm2) == DataFunctionalities.Dsm2)
{ {
TW_ENTRYPOINT entry; TW_ENTRYPOINT entry;
rc = session.DGControl.EntryPoint.Get(out entry); rc = Session.DGControl.EntryPoint.Get(out entry);
if (rc == ReturnCode.Success) if (rc == ReturnCode.Success)
{ {
session.Config.MemoryManager = entry; Session.Config.MemoryManager = entry;
} }
else else
{ {
@@ -38,9 +38,9 @@ namespace NTwain.Triplets
public ReturnCode CloseDSM(ref IntPtr hWnd) public ReturnCode CloseDSM(ref IntPtr hWnd)
{ {
var rc = NativeMethods.DsmWin32(session.Config.AppWin32, null, DataGroups.Control, var rc = NativeMethods.DsmWin32(Session.Config.AppWin32, null, DataGroups.Control,
DataArgumentType.Parent, Message.CloseDSM, ref hWnd); DataArgumentType.Parent, Message.CloseDSM, ref hWnd);
if (rc == ReturnCode.Success) session.State = TwainState.DsmLoaded; if (rc == ReturnCode.Success) Session.State = TwainState.DsmLoaded;
return rc; return rc;
} }
} }

View File

@@ -14,9 +14,12 @@ namespace NTwain.Triplets
internal DGControl(TwainSession session) : base(session) { } internal DGControl(TwainSession session) : base(session) { }
Parent _parent; Parent _parent;
internal Parent Parent => _parent ?? (_parent = new Parent(session)); internal Parent Parent => _parent ?? (_parent = new Parent(Session));
EntryPoint _entryPoint; EntryPoint _entryPoint;
internal EntryPoint EntryPoint => _entryPoint ?? (_entryPoint = new EntryPoint(session)); internal EntryPoint EntryPoint => _entryPoint ?? (_entryPoint = new EntryPoint(Session));
Identity _identity;
internal Identity Identity => _identity ?? (_identity = new Identity(Session));
} }
} }

View File

@@ -11,7 +11,7 @@ namespace NTwain
/// </summary> /// </summary>
public class TwainConfigBuilder public class TwainConfigBuilder
{ {
private bool _legacy; //private bool _legacy;
private string _appName; private string _appName;
private Version _version; private Version _version;
private string _companyName; private string _companyName;

View File

@@ -8,22 +8,41 @@ using System.Text;
namespace NTwain namespace NTwain
{ {
/// <summary>
/// Manages a TWAIN session.
/// </summary>
public partial class TwainSession public partial class TwainSession
{ {
internal TwainConfig Config; internal readonly TwainConfig Config;
private IntPtr _hWnd; private IntPtr _hWnd;
// cache generated twain sources so if you get same source from same session it'll return the same object
readonly Dictionary<string, DataSource> _ownedSources = new Dictionary<string, DataSource>();
/// <summary>
/// Constructs a new <see cref="TwainSession"/>.
/// </summary>
/// <param name="config"></param>
public TwainSession(TwainConfig config) public TwainSession(TwainConfig config)
{ {
Config = config; Config = config;
} }
/// <summary>
/// Opens the TWAIN session.
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
public ReturnCode Open(ref IntPtr hWnd) public ReturnCode Open(ref IntPtr hWnd)
{ {
_hWnd = hWnd; _hWnd = hWnd;
return DGControl.Parent.OpenDSM(ref hWnd); return DGControl.Parent.OpenDSM(ref hWnd);
} }
/// <summary>
/// Steps down to the target session state.
/// </summary>
/// <param name="targetState"></param>
/// <returns></returns>
public ReturnCode StepDown(TwainState targetState) public ReturnCode StepDown(TwainState targetState)
{ {
var rc = ReturnCode.Failure; var rc = ReturnCode.Failure;
@@ -39,5 +58,82 @@ namespace NTwain
} }
return rc; return rc;
} }
/// <summary>
/// Gets list of sources available on the machine.
/// </summary>
/// <returns></returns>
public IEnumerable<DataSource> GetSources()
{
TW_IDENTITY srcId;
var rc = DGControl.Identity.GetFirst(out srcId);
while (rc == ReturnCode.Success)
{
yield return GetSourceSingleton(srcId);
rc = DGControl.Identity.GetNext(out srcId);
}
}
/// <summary>
/// Gets/sets the default data source.
/// </summary>
public DataSource DefaultSource
{
get
{
TW_IDENTITY src;
if (DGControl.Identity.GetDefault(out src) == ReturnCode.Success)
{
return GetSourceSingleton(src);
}
return null;
}
set
{
//if (value != null && value.Session != this)
//{
// throw new InvalidOperationException("Source is not from this session.");
//}
DGControl.Identity.Set(value);
RaisePropertyChanged(nameof(DefaultSource));
}
}
/// <summary>
/// Tries to show the built-in source selector dialog and return the selected source.
/// </summary>
/// <returns></returns>
public DataSource ShowSourceSelector()
{
TW_IDENTITY id;
if (DGControl.Identity.UserSelect(out id) == ReturnCode.Success)
{
return GetSourceSingleton(id);
}
return null;
}
/// <summary>
/// Gets the currently open data source.
/// </summary>
/// <value>
/// The current source.
/// </value>
public DataSource CurrentSource { get; internal set; }
internal DataSource GetSourceSingleton(TW_IDENTITY sourceId)
{
DataSource source = null;
var key = $"{sourceId.Id}|{sourceId.Manufacturer}|{sourceId.ProductFamily}|{sourceId.ProductName}";
if (_ownedSources.ContainsKey(key))
{
source = _ownedSources[key];
}
else
{
_ownedSources[key] = source = new DataSource(this, sourceId);
}
return source;
}
} }
} }