Added source open/close methods and callback placeholder.

This commit is contained in:
Eugene Wang
2018-11-13 22:03:35 -05:00
parent c72f145703
commit deff4dbae5
12 changed files with 254 additions and 11 deletions

View File

@@ -5,6 +5,11 @@
<TargetFramework>netcoreapp2.1</TargetFramework> <TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<PlatformTarget>AnyCPU</PlatformTarget>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\NTwain\NTwain.csproj" /> <ProjectReference Include="..\..\src\NTwain\NTwain.csproj" />
</ItemGroup> </ItemGroup>

View File

@@ -22,12 +22,14 @@ namespace NetCoreConsole
{ {
session.PropertyChanged += Session_PropertyChanged; session.PropertyChanged += Session_PropertyChanged;
var handle = IntPtr.Zero; if (session.Open(IntPtr.Zero) == NTwain.Data.ReturnCode.Success)
if (session.Open(ref handle) == NTwain.Data.ReturnCode.Success)
{ {
Console.WriteLine("Available data sources:"); Console.WriteLine("Available data sources:");
DataSource firstSrc = null;
foreach (var src in session.GetSources()) foreach (var src in session.GetSources())
{ {
if (firstSrc == null) firstSrc = src;
Console.WriteLine($"\t{src}"); Console.WriteLine($"\t{src}");
} }
Console.WriteLine(); Console.WriteLine();
@@ -39,6 +41,18 @@ namespace NetCoreConsole
var selectSrc = session.ShowSourceSelector(); var selectSrc = session.ShowSourceSelector();
Console.WriteLine($"Selected data source = {selectSrc}"); Console.WriteLine($"Selected data source = {selectSrc}");
Console.WriteLine(); Console.WriteLine();
var targetSrc = selectSrc ?? defaultSrc ?? firstSrc;
if (targetSrc != null)
{
TestThisSource(targetSrc);
}
else
{
Console.WriteLine("No data source to test.");
Console.WriteLine();
}
} }
} }
@@ -52,6 +66,15 @@ namespace NetCoreConsole
Console.ReadLine(); Console.ReadLine();
} }
private static void TestThisSource(DataSource targetSrc)
{
Console.WriteLine($"Testing data source {targetSrc}");
Console.WriteLine();
targetSrc.Open();
targetSrc.Close();
}
private static void Session_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) private static void Session_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{ {
var session = (TwainSession)sender; var session = (TwainSession)sender;

View File

@@ -89,19 +89,19 @@ namespace NTwain.Data
[StructLayout(LayoutKind.Sequential, Pack = 2)] [StructLayout(LayoutKind.Sequential, Pack = 2)]
partial struct TW_CALLBACK partial class TW_CALLBACK
{ {
[MarshalAs(UnmanagedType.FunctionPtr)] [MarshalAs(UnmanagedType.FunctionPtr)]
public CallbackDelegate _callBackProc; CallbackDelegate _callBackProc;
TW_UINT32 _refCon; TW_UINT32 _refCon;
TW_INT16 _message; TW_INT16 _message;
} }
[StructLayout(LayoutKind.Sequential, Pack = 2)] [StructLayout(LayoutKind.Sequential, Pack = 2)]
partial struct TW_CALLBACK2 partial class TW_CALLBACK2
{ {
[MarshalAs(UnmanagedType.FunctionPtr)] [MarshalAs(UnmanagedType.FunctionPtr)]
public CallbackDelegate _callBackProc; CallbackDelegate _callBackProc;
TW_UINTPTR _refCon; TW_UINTPTR _refCon;
TW_INT16 _message; TW_INT16 _message;
} }

View File

@@ -571,6 +571,69 @@ namespace NTwain.Data
} }
/// <summary>
/// Used in Callback mechanism for sending messages from the Source to the Application.
/// Applications version 2.2 or higher must use <see cref="TW_CALLBACK2"/>.
/// </summary>
partial class TW_CALLBACK
{
/// <summary>
/// Initializes a new instance of the <see cref="TWCallback"/> class.
/// </summary>
/// <param name="callback">The callback functions entry point.</param>
public TW_CALLBACK(CallbackDelegate callback)
{
_callBackProc = callback;
}
///// <summary>
///// An application defined reference constant.
///// </summary>
///// <value>
///// The reference constant.
///// </value>
//public uint RefCon { get { return _refCon; } set { _refCon = value; } }
///// <summary>
///// Initialized to any valid DG_CONTROL / DAT_NULL message.
///// </summary>
///// <value>
///// The message.
///// </value>
//public short Message { get { return _message; } set { _message = value; } }
}
/// <summary>
/// Used in the Callback mechanism for sending messages from the Source to the Application.
/// </summary>
partial class TW_CALLBACK2
{
/// <summary>
/// Initializes a new instance of the <see cref="TW_CALLBACK2"/> class.
/// </summary>
/// <param name="callback">The callback functions entry point.</param>
public TW_CALLBACK2(CallbackDelegate callback)
{
_callBackProc = callback;
}
///// <summary>
///// An application defined reference constant. It has a different size on different
///// platforms.
///// </summary>
///// <value>
///// The reference constant.
///// </value>
//public UIntPtr RefCon { get { return _refCon; } set { _refCon = value; } }
///// <summary>
///// Initialized to any valid DG_CONTROL / DAT_NULL message.
///// </summary>
///// <value>
///// The message.
///// </value>
//public short Message { get { return _message; } set { _message = value; } }
}
// /// <summary> // /// <summary>
// /// Used by an application either to get information about, or control the setting of a capability. // /// Used by an application either to get information about, or control the setting of a capability.

View File

@@ -19,6 +19,7 @@ namespace NTwain
{ {
this.Session = session; this.Session = session;
this.Identity = src; this.Identity = src;
ProtocolVersion = new Version(src.ProtocolMajor, src.ProtocolMinor);
} }
/// <summary> /// <summary>
@@ -27,10 +28,51 @@ namespace NTwain
public string Name => Identity.ProductName; public string Name => Identity.ProductName;
/// <summary> /// <summary>
/// Gets the source version info. /// Gets the source's manufacturer name.
/// </summary>
public string Manufacturer => Identity.Manufacturer;
/// <summary>
/// Gets the source's product family.
/// </summary>
public string ProductFamily => Identity.ProductFamily;
/// <summary>
/// Gets the source's version info.
/// </summary> /// </summary>
public TW_VERSION Version => Identity.Version; public TW_VERSION Version => Identity.Version;
/// <summary>
/// Gets the supported data group.
/// </summary>
public DataGroups DataGroup => Identity.DataGroup;
/// <summary>
/// Gets the supported TWAIN protocol version.
/// </summary>
public Version ProtocolVersion { get; }
/// <summary>
/// Gets a value indicating whether this data source is open.
/// </summary>
public bool IsOpen => Session.State > TwainState.DsmOpened && Session.CurrentSource == this;
/// <summary>
/// Opens the source for capability negotiation.
/// </summary>
/// <returns></returns>
public ReturnCode Open() => Session.DGControl.Identity.OpenDS(Identity);
/// <summary>
/// Closes the source.
/// </summary>
/// <returns></returns>
public ReturnCode Close() => Session.DGControl.Identity.CloseDS(Identity);
/// <summary> /// <summary>
/// Returns a <see cref="System.String"/> that represents this instance. /// Returns a <see cref="System.String"/> that represents this instance.
/// </summary> /// </summary>

View File

@@ -15,7 +15,7 @@
<SignAssembly>true</SignAssembly> <SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>Sign.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>Sign.snk</AssemblyOriginatorKeyFile>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<AssemblyVersion>4.0.0.0</AssemblyVersion> <AssemblyVersion>4.0.0.0</AssemblyVersion>
<FileVersion>4.0.0.0</FileVersion> <FileVersion>4.0.0.0</FileVersion>
<Version>4.0.0</Version> <Version>4.0.0</Version>

View File

@@ -0,0 +1,16 @@
using NTwain.Data;
using NTwain.Internals;
namespace NTwain.Triplets
{
sealed class Callback : BaseTriplet
{
internal Callback(TwainSession session) : base(session) { }
public ReturnCode RegisterCallback(TW_CALLBACK callback)
{
return NativeMethods.DsmWin32(Session.Config.AppWin32, Session.CurrentSource.Identity,
DataGroups.Control, DataArgumentType.Callback2, Message.RegisterCallback, callback);
}
}
}

View File

@@ -0,0 +1,16 @@
using NTwain.Data;
using NTwain.Internals;
namespace NTwain.Triplets
{
sealed class Callback2 : BaseTriplet
{
internal Callback2(TwainSession session) : base(session) { }
public ReturnCode RegisterCallback(TW_CALLBACK2 callback)
{
return NativeMethods.DsmWin32(Session.Config.AppWin32, Session.CurrentSource.Identity,
DataGroups.Control, DataArgumentType.Callback2, Message.RegisterCallback, callback);
}
}
}

View File

@@ -16,6 +16,7 @@ namespace NTwain.Triplets
{ {
Session.State = TwainState.S3; Session.State = TwainState.S3;
Session.CurrentSource = null; Session.CurrentSource = null;
Session.UpdateCallback();
} }
return rc; return rc;
} }
@@ -50,6 +51,7 @@ namespace NTwain.Triplets
{ {
Session.CurrentSource = Session.GetSourceSingleton(source); Session.CurrentSource = Session.GetSourceSingleton(source);
Session.State = TwainState.S4; Session.State = TwainState.S4;
Session.UpdateCallback();
} }
return rc; return rc;
} }

View File

@@ -21,5 +21,11 @@ namespace NTwain.Triplets
Identity _identity; Identity _identity;
internal Identity Identity => _identity ?? (_identity = new Identity(Session)); internal Identity Identity => _identity ?? (_identity = new Identity(Session));
Callback _callback;
internal Callback Callback => _callback ?? (_callback = new Callback(Session));
Callback2 _callback2;
internal Callback2 Callback2 => _callback2 ?? (_callback2 = new Callback2(Session));
} }
} }

View File

@@ -70,7 +70,7 @@ namespace NTwain.Triplets
DataGroups dg, DataGroups dg,
DataArgumentType dat, DataArgumentType dat,
Message msg, Message msg,
ref TW_CALLBACK data); [In, Out]TW_CALLBACK data);
[DllImport(WinDsmDll, EntryPoint = EntryName)] [DllImport(WinDsmDll, EntryPoint = EntryName)]
public static extern ReturnCode DsmWin32( public static extern ReturnCode DsmWin32(
@@ -79,7 +79,7 @@ namespace NTwain.Triplets
DataGroups dg, DataGroups dg,
DataArgumentType dat, DataArgumentType dat,
Message msg, Message msg,
ref TW_CALLBACK2 data); [In, Out]TW_CALLBACK2 data);
[DllImport(WinDsmDll, EntryPoint = EntryName)] [DllImport(WinDsmDll, EntryPoint = EntryName)]
public static extern ReturnCode DsmWin32( public static extern ReturnCode DsmWin32(

View File

@@ -15,6 +15,7 @@ namespace NTwain
{ {
internal readonly TwainConfig Config; internal readonly TwainConfig Config;
private IntPtr _hWnd; private IntPtr _hWnd;
object _callbackObj; // kept around in this class so it doesn't get gc'ed
// cache generated twain sources so if you get same source from same session it'll return the same object // 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>(); readonly Dictionary<string, DataSource> _ownedSources = new Dictionary<string, DataSource>();
@@ -32,7 +33,7 @@ namespace NTwain
/// </summary> /// </summary>
/// <param name="hWnd"></param> /// <param name="hWnd"></param>
/// <returns></returns> /// <returns></returns>
public ReturnCode Open(ref IntPtr hWnd) public ReturnCode Open(IntPtr hWnd)
{ {
_hWnd = hWnd; _hWnd = hWnd;
return DGControl.Parent.OpenDSM(ref hWnd); return DGControl.Parent.OpenDSM(ref hWnd);
@@ -63,6 +64,44 @@ namespace NTwain
return rc; return rc;
} }
internal void UpdateCallback()
{
if (State < TwainState.S4)
{
_callbackObj = null;
}
else
{
var rc = ReturnCode.Failure;
// per the spec (8-10) apps for 2.2 or higher uses callback2 so try this first
if (Config.AppWin32.ProtocolMajor > 2 ||
(Config.AppWin32.ProtocolMajor >= 2 && Config.AppWin32.ProtocolMinor >= 2))
{
var cb = new TW_CALLBACK2(HandleCallback);
rc = DGControl.Callback2.RegisterCallback(cb);
if (rc == ReturnCode.Success)
{
_callbackObj = cb;
}
}
if (rc != ReturnCode.Success)
{
// always try old callback
var cb = new TW_CALLBACK(HandleCallback);
rc = DGControl.Callback.RegisterCallback(cb);
if (rc == ReturnCode.Success)
{
_callbackObj = cb;
}
}
}
}
/// <summary> /// <summary>
/// Gets list of sources available on the machine. /// Gets list of sources available on the machine.
/// </summary> /// </summary>
@@ -142,5 +181,36 @@ namespace NTwain
} }
return source; return source;
} }
ReturnCode HandleCallback(TW_IDENTITY origin, TW_IDENTITY destination,
DataGroups dg, DataArgumentType dat, Message msg, IntPtr data)
{
//if (origin != null && CurrentSource != null && origin.Id == CurrentSource.Identity.Id && State >= S5)
//{
// // spec says we must handle this on the thread that enabled the DS.
// // by using the internal dispatcher this will be the case.
// // In any event the trick to get this thing working is to return from the callback first
// // before trying to process the msg or there will be unpredictable errors.
// // changed to sync invoke instead of begininvoke for hp scanjet.
// if (origin.ProductName.IndexOf("scanjet", StringComparison.OrdinalIgnoreCase) > -1)
// {
// _msgLoopHook?.Invoke(() =>
// {
// HandleSourceMsg(msg);
// });
// }
// else
// {
// _msgLoopHook?.BeginInvoke(() =>
// {
// HandleSourceMsg(msg);
// });
// }
// return ReturnCode.Success;
//}
return ReturnCode.Failure;
}
} }
} }