diff --git a/samples/NetCoreConsole/Program.cs b/samples/NetCoreConsole/Program.cs
index b9d27f1..e25973c 100644
--- a/samples/NetCoreConsole/Program.cs
+++ b/samples/NetCoreConsole/Program.cs
@@ -15,6 +15,7 @@ namespace NetCoreConsole
.Build();
Console.WriteLine($"App = {(config.Is64Bit ? "64bit" : "32bit")}");
Console.WriteLine($"Platform = {config.Platform}");
+ Console.WriteLine();
using (var session = new TwainSession(config))
{
@@ -23,18 +24,33 @@ namespace NetCoreConsole
var handle = IntPtr.Zero;
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)
{
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)
diff --git a/src/NTwain/Data/TwainTypes.cs b/src/NTwain/Data/TwainTypes.cs
index c58de00..165b51e 100644
--- a/src/NTwain/Data/TwainTypes.cs
+++ b/src/NTwain/Data/TwainTypes.cs
@@ -310,7 +310,7 @@ namespace NTwain.Data
partial class TW_IDENTITY
{
// TODO: id needs to be 64bit in 64bit?
- TW_UINT32 _id;
+ internal TW_UINT32 Id;
TW_VERSION _version;
TW_UINT16 _protocolMajor;
TW_UINT16 _protocolMinor;
diff --git a/src/NTwain/Data/TwainTypesExtended.cs b/src/NTwain/Data/TwainTypesExtended.cs
index b9617e7..ea13cf3 100644
--- a/src/NTwain/Data/TwainTypesExtended.cs
+++ b/src/NTwain/Data/TwainTypesExtended.cs
@@ -1584,7 +1584,8 @@ namespace NTwain.Data
///
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
diff --git a/src/NTwain/DataSource.cs b/src/NTwain/DataSource.cs
new file mode 100644
index 0000000..4f749b6
--- /dev/null
+++ b/src/NTwain/DataSource.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NTwain.Data;
+
+namespace NTwain
+{
+ ///
+ /// A TWAIN data source.
+ ///
+ 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;
+ }
+
+ ///
+ /// Gets the source name.
+ ///
+ public string Name => Identity.ProductName;
+
+ ///
+ /// Gets the source version info.
+ ///
+ public TW_VERSION Version => Identity.Version;
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ ///
+ /// A that represents this instance.
+ ///
+ public override string ToString()
+ {
+ return $"{Name} {Version}";
+ }
+ }
+}
diff --git a/src/NTwain/Triplets/BaseTriplet.cs b/src/NTwain/Triplets/BaseTriplet.cs
index 063502a..10275de 100644
--- a/src/NTwain/Triplets/BaseTriplet.cs
+++ b/src/NTwain/Triplets/BaseTriplet.cs
@@ -1,12 +1,25 @@
-namespace NTwain.Triplets
+using System;
+
+namespace NTwain.Triplets
{
+ ///
+ /// Base class for grouping triplet operations.
+ ///
public abstract class BaseTriplet
{
- protected TwainSession session;
+ ///
+ /// Gets the associated .
+ ///
+ protected readonly TwainSession Session;
- public BaseTriplet(TwainSession session)
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The session.
+ ///
+ protected BaseTriplet(TwainSession session)
{
- this.session = session;
+ this.Session = session ?? throw new ArgumentNullException(nameof(session));
}
}
}
\ No newline at end of file
diff --git a/src/NTwain/Triplets/DGControl.EntryPoint.cs b/src/NTwain/Triplets/DGControl.EntryPoint.cs
index ca60712..3ad28f0 100644
--- a/src/NTwain/Triplets/DGControl.EntryPoint.cs
+++ b/src/NTwain/Triplets/DGControl.EntryPoint.cs
@@ -13,7 +13,7 @@ namespace NTwain.Triplets
public ReturnCode Get(out TW_ENTRYPOINT 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);
}
}
diff --git a/src/NTwain/Triplets/DGControl.Identity.cs b/src/NTwain/Triplets/DGControl.Identity.cs
new file mode 100644
index 0000000..7f71049
--- /dev/null
+++ b/src/NTwain/Triplets/DGControl.Identity.cs
@@ -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);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NTwain/Triplets/DGControl.Parent.cs b/src/NTwain/Triplets/DGControl.Parent.cs
index db7948d..324b300 100644
--- a/src/NTwain/Triplets/DGControl.Parent.cs
+++ b/src/NTwain/Triplets/DGControl.Parent.cs
@@ -12,20 +12,20 @@ namespace NTwain.Triplets
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);
if (rc == ReturnCode.Success)
{
- session.State = TwainState.DsmOpened;
+ Session.State = TwainState.DsmOpened;
// 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;
- rc = session.DGControl.EntryPoint.Get(out entry);
+ rc = Session.DGControl.EntryPoint.Get(out entry);
if (rc == ReturnCode.Success)
{
- session.Config.MemoryManager = entry;
+ Session.Config.MemoryManager = entry;
}
else
{
@@ -38,9 +38,9 @@ namespace NTwain.Triplets
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);
- if (rc == ReturnCode.Success) session.State = TwainState.DsmLoaded;
+ if (rc == ReturnCode.Success) Session.State = TwainState.DsmLoaded;
return rc;
}
}
diff --git a/src/NTwain/Triplets/DGControl.cs b/src/NTwain/Triplets/DGControl.cs
index a2b2217..a07d157 100644
--- a/src/NTwain/Triplets/DGControl.cs
+++ b/src/NTwain/Triplets/DGControl.cs
@@ -14,9 +14,12 @@ namespace NTwain.Triplets
internal DGControl(TwainSession session) : base(session) { }
Parent _parent;
- internal Parent Parent => _parent ?? (_parent = new Parent(session));
+ internal Parent Parent => _parent ?? (_parent = new Parent(Session));
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));
}
}
diff --git a/src/NTwain/TwainConfigBuilder.cs b/src/NTwain/TwainConfigBuilder.cs
index f65cbfc..b34955e 100644
--- a/src/NTwain/TwainConfigBuilder.cs
+++ b/src/NTwain/TwainConfigBuilder.cs
@@ -11,7 +11,7 @@ namespace NTwain
///
public class TwainConfigBuilder
{
- private bool _legacy;
+ //private bool _legacy;
private string _appName;
private Version _version;
private string _companyName;
diff --git a/src/NTwain/TwainSession.cs b/src/NTwain/TwainSession.cs
index 4bed415..1318ddc 100644
--- a/src/NTwain/TwainSession.cs
+++ b/src/NTwain/TwainSession.cs
@@ -8,22 +8,41 @@ using System.Text;
namespace NTwain
{
+ ///
+ /// Manages a TWAIN session.
+ ///
public partial class TwainSession
{
- internal TwainConfig Config;
+ internal readonly TwainConfig Config;
private IntPtr _hWnd;
+ // cache generated twain sources so if you get same source from same session it'll return the same object
+ readonly Dictionary _ownedSources = new Dictionary();
+ ///
+ /// Constructs a new .
+ ///
+ ///
public TwainSession(TwainConfig config)
{
Config = config;
}
+ ///
+ /// Opens the TWAIN session.
+ ///
+ ///
+ ///
public ReturnCode Open(ref IntPtr hWnd)
{
_hWnd = hWnd;
return DGControl.Parent.OpenDSM(ref hWnd);
}
+ ///
+ /// Steps down to the target session state.
+ ///
+ ///
+ ///
public ReturnCode StepDown(TwainState targetState)
{
var rc = ReturnCode.Failure;
@@ -39,5 +58,82 @@ namespace NTwain
}
return rc;
}
+
+ ///
+ /// Gets list of sources available on the machine.
+ ///
+ ///
+ public IEnumerable 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);
+ }
+ }
+
+ ///
+ /// Gets/sets the default data source.
+ ///
+ 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));
+ }
+ }
+
+ ///
+ /// Tries to show the built-in source selector dialog and return the selected source.
+ ///
+ ///
+ public DataSource ShowSourceSelector()
+ {
+ TW_IDENTITY id;
+ if (DGControl.Identity.UserSelect(out id) == ReturnCode.Success)
+ {
+ return GetSourceSingleton(id);
+ }
+ return null;
+ }
+
+ ///
+ /// Gets the currently open data source.
+ ///
+ ///
+ /// The current source.
+ ///
+ 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;
+ }
}
}