Made callback a struct.

This commit is contained in:
Eugene Wang
2018-11-14 18:52:14 -05:00
parent 593dd6e675
commit 56bfc37c89
9 changed files with 77 additions and 137 deletions

View File

@@ -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);

View File

@@ -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 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.
// /// </summary> // /// </summary>

View File

@@ -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);
} }
} }
} }

View File

@@ -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);
} }
} }
} }

View File

@@ -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;
} }

View File

@@ -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);

View File

@@ -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(

View 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)
{
}
}
}

View File

@@ -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;
} }
} }
} }