mirror of
https://github.com/soukoku/ntwain.git
synced 2026-01-26 13:39:47 +08:00
Added source open/close methods and callback placeholder.
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 function’s 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 function’s 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.
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
16
src/NTwain/Triplets/DGControl.Callback.cs
Normal file
16
src/NTwain/Triplets/DGControl.Callback.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/NTwain/Triplets/DGControl.Callback2.cs
Normal file
16
src/NTwain/Triplets/DGControl.Callback2.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user