mirror of
https://github.com/soukoku/ntwain.git
synced 2026-02-25 13:04:07 +08:00
Made callback a struct.
This commit is contained in:
@@ -89,21 +89,19 @@ namespace NTwain.Data
|
|||||||
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
||||||
partial class TW_CALLBACK
|
partial struct TW_CALLBACK
|
||||||
{
|
{
|
||||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
public TW_MEMREF 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 class TW_CALLBACK2
|
partial struct TW_CALLBACK2
|
||||||
{
|
{
|
||||||
[MarshalAs(UnmanagedType.FunctionPtr)]
|
public TW_MEMREF CallBackProc;
|
||||||
CallbackDelegate _callBackProc;
|
TW_UINTPTR RefCon;
|
||||||
TW_UINTPTR _refCon;
|
TW_INT16 Message;
|
||||||
TW_INT16 _message;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
||||||
@@ -542,6 +540,7 @@ namespace NTwain.Data
|
|||||||
TW_HANDLE _hParent;
|
TW_HANDLE _hParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
delegate ReturnCode CallbackDelegate(TW_IDENTITY origin, TW_IDENTITY destination,
|
delegate ReturnCode CallbackDelegate(TW_IDENTITY origin, TW_IDENTITY destination,
|
||||||
DataGroups dg, DataArgumentType dat, Message msg, TW_MEMREF data);
|
DataGroups dg, DataArgumentType dat, Message msg, TW_MEMREF data);
|
||||||
|
|
||||||
|
|||||||
@@ -570,71 +570,6 @@ namespace NTwain.Data
|
|||||||
public string Name { get { return _name; } }
|
public string Name { get { return _name; } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <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.
|
||||||
// /// </summary>
|
// /// </summary>
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ namespace NTwain.Triplets
|
|||||||
{
|
{
|
||||||
internal Callback(TwainSession session) : base(session) { }
|
internal Callback(TwainSession session) : base(session) { }
|
||||||
|
|
||||||
public ReturnCode RegisterCallback(TW_CALLBACK callback)
|
public ReturnCode RegisterCallback(ref TW_CALLBACK callback)
|
||||||
{
|
{
|
||||||
return NativeMethods.DsmWin32(Session.Config.AppWin32, Session.CurrentSource.Identity,
|
return NativeMethods.DsmWin32(Session.Config.AppWin32, Session.CurrentSource.Identity,
|
||||||
DataGroups.Control, DataArgumentType.Callback2, Message.RegisterCallback, callback);
|
DataGroups.Control, DataArgumentType.Callback, Message.RegisterCallback, ref callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,10 +7,10 @@ namespace NTwain.Triplets
|
|||||||
{
|
{
|
||||||
internal Callback2(TwainSession session) : base(session) { }
|
internal Callback2(TwainSession session) : base(session) { }
|
||||||
|
|
||||||
public ReturnCode RegisterCallback(TW_CALLBACK2 callback)
|
public ReturnCode RegisterCallback(ref TW_CALLBACK2 callback)
|
||||||
{
|
{
|
||||||
return NativeMethods.DsmWin32(Session.Config.AppWin32, Session.CurrentSource.Identity,
|
return NativeMethods.DsmWin32(Session.Config.AppWin32, Session.CurrentSource.Identity,
|
||||||
DataGroups.Control, DataArgumentType.Callback2, Message.RegisterCallback, callback);
|
DataGroups.Control, DataArgumentType.Callback2, Message.RegisterCallback, ref callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,6 @@ namespace NTwain.Triplets
|
|||||||
{
|
{
|
||||||
Session.State = TwainState.S3;
|
Session.State = TwainState.S3;
|
||||||
Session.CurrentSource = null;
|
Session.CurrentSource = null;
|
||||||
Session.UpdateCallback();
|
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -51,7 +50,7 @@ namespace NTwain.Triplets
|
|||||||
{
|
{
|
||||||
Session.CurrentSource = Session.GetSourceSingleton(source);
|
Session.CurrentSource = Session.GetSourceSingleton(source);
|
||||||
Session.State = TwainState.S4;
|
Session.State = TwainState.S4;
|
||||||
Session.UpdateCallback();
|
Session.RegisterCallback();
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace NTwain.Triplets
|
|||||||
{
|
{
|
||||||
internal Parent(TwainSession session) : base(session) { }
|
internal Parent(TwainSession session) : base(session) { }
|
||||||
|
|
||||||
public ReturnCode OpenDSM(ref IntPtr hWnd)
|
public ReturnCode OpenDSM(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);
|
||||||
@@ -29,14 +29,14 @@ namespace NTwain.Triplets
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rc = CloseDSM(ref hWnd);
|
rc = CloseDSM(hWnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReturnCode CloseDSM(ref IntPtr hWnd)
|
public ReturnCode CloseDSM(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);
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ namespace NTwain.Triplets
|
|||||||
DataGroups dg,
|
DataGroups dg,
|
||||||
DataArgumentType dat,
|
DataArgumentType dat,
|
||||||
Message msg,
|
Message msg,
|
||||||
[In, Out]TW_CALLBACK data);
|
ref 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,
|
||||||
[In, Out]TW_CALLBACK2 data);
|
ref TW_CALLBACK2 data);
|
||||||
|
|
||||||
[DllImport(WinDsmDll, EntryPoint = EntryName)]
|
[DllImport(WinDsmDll, EntryPoint = EntryName)]
|
||||||
public static extern ReturnCode DsmWin32(
|
public static extern ReturnCode DsmWin32(
|
||||||
|
|||||||
21
src/NTwain/TwainSession.MsgHandling.cs
Normal file
21
src/NTwain/TwainSession.MsgHandling.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using NTwain.Data;
|
||||||
|
using NTwain.Triplets;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace NTwain
|
||||||
|
{
|
||||||
|
partial class TwainSession
|
||||||
|
{
|
||||||
|
private void HandleSourceMsg(Message msg)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,8 +3,11 @@ using NTwain.Triplets;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace NTwain
|
namespace NTwain
|
||||||
{
|
{
|
||||||
@@ -14,10 +17,12 @@ namespace NTwain
|
|||||||
public partial class TwainSession
|
public partial class TwainSession
|
||||||
{
|
{
|
||||||
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>();
|
||||||
|
// need to keep delegate around to prevent GC?
|
||||||
|
readonly CallbackDelegate _callbackDelegate;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a new <see cref="TwainSession"/>.
|
/// Constructs a new <see cref="TwainSession"/>.
|
||||||
@@ -26,6 +31,14 @@ namespace NTwain
|
|||||||
public TwainSession(TwainConfig config)
|
public TwainSession(TwainConfig config)
|
||||||
{
|
{
|
||||||
Config = config;
|
Config = config;
|
||||||
|
switch (config.Platform)
|
||||||
|
{
|
||||||
|
case PlatformID.MacOSX:
|
||||||
|
case PlatformID.Unix:
|
||||||
|
default:
|
||||||
|
_callbackDelegate = new CallbackDelegate(HandleWin32Callback);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -36,7 +49,7 @@ namespace NTwain
|
|||||||
public ReturnCode Open(IntPtr hWnd)
|
public ReturnCode Open(IntPtr hWnd)
|
||||||
{
|
{
|
||||||
_hWnd = hWnd;
|
_hWnd = hWnd;
|
||||||
return DGControl.Parent.OpenDSM(ref hWnd);
|
return DGControl.Parent.OpenDSM(hWnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -52,7 +65,7 @@ namespace NTwain
|
|||||||
switch (State)
|
switch (State)
|
||||||
{
|
{
|
||||||
case TwainState.DsmOpened:
|
case TwainState.DsmOpened:
|
||||||
rc = DGControl.Parent.CloseDSM(ref _hWnd);
|
rc = DGControl.Parent.CloseDSM(_hWnd);
|
||||||
if (rc != ReturnCode.Success) return rc;
|
if (rc != ReturnCode.Success) return rc;
|
||||||
break;
|
break;
|
||||||
case TwainState.SourceOpened:
|
case TwainState.SourceOpened:
|
||||||
@@ -64,38 +77,37 @@ namespace NTwain
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void UpdateCallback()
|
internal void RegisterCallback()
|
||||||
{
|
{
|
||||||
if (State < TwainState.S4)
|
if (State == TwainState.S4)
|
||||||
{
|
|
||||||
_callbackObj = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
var callbackPtr = Marshal.GetFunctionPointerForDelegate(_callbackDelegate);
|
||||||
|
|
||||||
var rc = ReturnCode.Failure;
|
var rc = ReturnCode.Failure;
|
||||||
// per the spec (8-10) apps for 2.2 or higher uses callback2 so try this first
|
// per the spec (8-10) apps for 2.2 or higher uses callback2 so try this first
|
||||||
if (Config.AppWin32.ProtocolMajor > 2 ||
|
if (Config.AppWin32.ProtocolMajor > 2 ||
|
||||||
(Config.AppWin32.ProtocolMajor >= 2 && Config.AppWin32.ProtocolMinor >= 2))
|
(Config.AppWin32.ProtocolMajor >= 2 && Config.AppWin32.ProtocolMinor >= 2))
|
||||||
{
|
{
|
||||||
var cb = new TW_CALLBACK2(HandleCallback);
|
var cb = new TW_CALLBACK2 { CallBackProc = callbackPtr };
|
||||||
rc = DGControl.Callback2.RegisterCallback(cb);
|
rc = DGControl.Callback2.RegisterCallback(ref cb);
|
||||||
|
if (rc == ReturnCode.Success) Debug.WriteLine("Registed Callback2 success.");
|
||||||
if (rc == ReturnCode.Success)
|
else
|
||||||
{
|
{
|
||||||
_callbackObj = cb;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc != ReturnCode.Success)
|
if (rc != ReturnCode.Success)
|
||||||
{
|
{
|
||||||
// always try old callback
|
// always try old callback
|
||||||
var cb = new TW_CALLBACK(HandleCallback);
|
var cb = new TW_CALLBACK { CallBackProc = callbackPtr };
|
||||||
|
|
||||||
rc = DGControl.Callback.RegisterCallback(cb);
|
rc = DGControl.Callback.RegisterCallback(ref cb);
|
||||||
|
|
||||||
if (rc == ReturnCode.Success)
|
if (rc == ReturnCode.Success) Debug.WriteLine("Registed Callback success.");
|
||||||
|
else
|
||||||
{
|
{
|
||||||
_callbackObj = cb;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,8 +120,7 @@ namespace NTwain
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public IEnumerable<DataSource> GetSources()
|
public IEnumerable<DataSource> GetSources()
|
||||||
{
|
{
|
||||||
TW_IDENTITY srcId;
|
var rc = DGControl.Identity.GetFirst(out TW_IDENTITY srcId);
|
||||||
var rc = DGControl.Identity.GetFirst(out srcId);
|
|
||||||
while (rc == ReturnCode.Success)
|
while (rc == ReturnCode.Success)
|
||||||
{
|
{
|
||||||
yield return GetSourceSingleton(srcId);
|
yield return GetSourceSingleton(srcId);
|
||||||
@@ -124,8 +135,7 @@ namespace NTwain
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
TW_IDENTITY src;
|
if (DGControl.Identity.GetDefault(out TW_IDENTITY src) == ReturnCode.Success)
|
||||||
if (DGControl.Identity.GetDefault(out src) == ReturnCode.Success)
|
|
||||||
{
|
{
|
||||||
return GetSourceSingleton(src);
|
return GetSourceSingleton(src);
|
||||||
}
|
}
|
||||||
@@ -151,8 +161,7 @@ namespace NTwain
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public DataSource ShowSourceSelector()
|
public DataSource ShowSourceSelector()
|
||||||
{
|
{
|
||||||
TW_IDENTITY id;
|
if (DGControl.Identity.UserSelect(out TW_IDENTITY id) == ReturnCode.Success)
|
||||||
if (DGControl.Identity.UserSelect(out id) == ReturnCode.Success)
|
|
||||||
{
|
{
|
||||||
return GetSourceSingleton(id);
|
return GetSourceSingleton(id);
|
||||||
}
|
}
|
||||||
@@ -182,35 +191,12 @@ namespace NTwain
|
|||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode HandleCallback(TW_IDENTITY origin, TW_IDENTITY destination,
|
ReturnCode HandleWin32Callback(TW_IDENTITY origin, TW_IDENTITY destination,
|
||||||
DataGroups dg, DataArgumentType dat, Message msg, IntPtr data)
|
DataGroups dg, DataArgumentType dat, Message msg, IntPtr data)
|
||||||
{
|
{
|
||||||
//if (origin != null && CurrentSource != null && origin.Id == CurrentSource.Identity.Id && State >= S5)
|
Debug.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: {nameof(HandleWin32Callback)}({dg}, {dat}, {msg}, {data})");
|
||||||
//{
|
HandleSourceMsg(msg);
|
||||||
// // spec says we must handle this on the thread that enabled the DS.
|
return ReturnCode.Success;
|
||||||
// // 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