diff --git a/src/NTwain/Data/TwainTypes.cs b/src/NTwain/Data/TwainTypes.cs
index 0db20d9..2651c2e 100644
--- a/src/NTwain/Data/TwainTypes.cs
+++ b/src/NTwain/Data/TwainTypes.cs
@@ -89,21 +89,19 @@ namespace NTwain.Data
[StructLayout(LayoutKind.Sequential, Pack = 2)]
- partial class TW_CALLBACK
+ partial struct TW_CALLBACK
{
- [MarshalAs(UnmanagedType.FunctionPtr)]
- CallbackDelegate _callBackProc;
- TW_UINT32 _refCon;
- TW_INT16 _message;
+ public TW_MEMREF CallBackProc;
+ TW_UINT32 RefCon;
+ TW_INT16 Message;
}
[StructLayout(LayoutKind.Sequential, Pack = 2)]
- partial class TW_CALLBACK2
+ partial struct TW_CALLBACK2
{
- [MarshalAs(UnmanagedType.FunctionPtr)]
- CallbackDelegate _callBackProc;
- TW_UINTPTR _refCon;
- TW_INT16 _message;
+ public TW_MEMREF CallBackProc;
+ TW_UINTPTR RefCon;
+ TW_INT16 Message;
}
[StructLayout(LayoutKind.Sequential, Pack = 2)]
@@ -542,6 +540,7 @@ namespace NTwain.Data
TW_HANDLE _hParent;
}
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate ReturnCode CallbackDelegate(TW_IDENTITY origin, TW_IDENTITY destination,
DataGroups dg, DataArgumentType dat, Message msg, TW_MEMREF data);
diff --git a/src/NTwain/Data/TwainTypesExtended.cs b/src/NTwain/Data/TwainTypesExtended.cs
index 9423c80..6221ad9 100644
--- a/src/NTwain/Data/TwainTypesExtended.cs
+++ b/src/NTwain/Data/TwainTypesExtended.cs
@@ -570,71 +570,6 @@ namespace NTwain.Data
public string Name { get { return _name; } }
}
-
- ///
- /// Used in Callback mechanism for sending messages from the Source to the Application.
- /// Applications version 2.2 or higher must use .
- ///
- partial class TW_CALLBACK
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The callback function’s entry point.
- public TW_CALLBACK(CallbackDelegate callback)
- {
- _callBackProc = callback;
- }
-
- /////
- ///// An application defined reference constant.
- /////
- /////
- ///// The reference constant.
- /////
- //public uint RefCon { get { return _refCon; } set { _refCon = value; } }
-
- /////
- ///// Initialized to any valid DG_CONTROL / DAT_NULL message.
- /////
- /////
- ///// The message.
- /////
- //public short Message { get { return _message; } set { _message = value; } }
- }
- ///
- /// Used in the Callback mechanism for sending messages from the Source to the Application.
- ///
- partial class TW_CALLBACK2
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The callback function’s entry point.
- public TW_CALLBACK2(CallbackDelegate callback)
- {
- _callBackProc = callback;
- }
-
- /////
- ///// An application defined reference constant. It has a different size on different
- ///// platforms.
- /////
- /////
- ///// The reference constant.
- /////
- //public UIntPtr RefCon { get { return _refCon; } set { _refCon = value; } }
-
- /////
- ///// Initialized to any valid DG_CONTROL / DAT_NULL message.
- /////
- /////
- ///// The message.
- /////
- //public short Message { get { return _message; } set { _message = value; } }
- }
-
-
// ///
// /// Used by an application either to get information about, or control the setting of a capability.
// ///
diff --git a/src/NTwain/Triplets/DGControl.Callback.cs b/src/NTwain/Triplets/DGControl.Callback.cs
index b823028..9cc7a53 100644
--- a/src/NTwain/Triplets/DGControl.Callback.cs
+++ b/src/NTwain/Triplets/DGControl.Callback.cs
@@ -7,10 +7,10 @@ namespace NTwain.Triplets
{
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,
- DataGroups.Control, DataArgumentType.Callback2, Message.RegisterCallback, callback);
+ DataGroups.Control, DataArgumentType.Callback, Message.RegisterCallback, ref callback);
}
}
}
\ No newline at end of file
diff --git a/src/NTwain/Triplets/DGControl.Callback2.cs b/src/NTwain/Triplets/DGControl.Callback2.cs
index 62c6a5c..3f3707e 100644
--- a/src/NTwain/Triplets/DGControl.Callback2.cs
+++ b/src/NTwain/Triplets/DGControl.Callback2.cs
@@ -7,10 +7,10 @@ namespace NTwain.Triplets
{
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,
- DataGroups.Control, DataArgumentType.Callback2, Message.RegisterCallback, callback);
+ DataGroups.Control, DataArgumentType.Callback2, Message.RegisterCallback, ref callback);
}
}
}
\ No newline at end of file
diff --git a/src/NTwain/Triplets/DGControl.Identity.cs b/src/NTwain/Triplets/DGControl.Identity.cs
index 35a3d09..958db81 100644
--- a/src/NTwain/Triplets/DGControl.Identity.cs
+++ b/src/NTwain/Triplets/DGControl.Identity.cs
@@ -16,7 +16,6 @@ namespace NTwain.Triplets
{
Session.State = TwainState.S3;
Session.CurrentSource = null;
- Session.UpdateCallback();
}
return rc;
}
@@ -51,7 +50,7 @@ namespace NTwain.Triplets
{
Session.CurrentSource = Session.GetSourceSingleton(source);
Session.State = TwainState.S4;
- Session.UpdateCallback();
+ Session.RegisterCallback();
}
return rc;
}
diff --git a/src/NTwain/Triplets/DGControl.Parent.cs b/src/NTwain/Triplets/DGControl.Parent.cs
index 324b300..5679af1 100644
--- a/src/NTwain/Triplets/DGControl.Parent.cs
+++ b/src/NTwain/Triplets/DGControl.Parent.cs
@@ -10,7 +10,7 @@ namespace NTwain.Triplets
{
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,
DataGroups.Control, DataArgumentType.Parent, Message.OpenDSM, ref hWnd);
@@ -29,14 +29,14 @@ namespace NTwain.Triplets
}
else
{
- rc = CloseDSM(ref hWnd);
+ rc = CloseDSM(hWnd);
}
}
}
return rc;
}
- public ReturnCode CloseDSM(ref IntPtr hWnd)
+ public ReturnCode CloseDSM(IntPtr hWnd)
{
var rc = NativeMethods.DsmWin32(Session.Config.AppWin32, null, DataGroups.Control,
DataArgumentType.Parent, Message.CloseDSM, ref hWnd);
diff --git a/src/NTwain/Triplets/NativeMethods.Win32.cs b/src/NTwain/Triplets/NativeMethods.Win32.cs
index 8f94cfc..0834d5b 100644
--- a/src/NTwain/Triplets/NativeMethods.Win32.cs
+++ b/src/NTwain/Triplets/NativeMethods.Win32.cs
@@ -70,7 +70,7 @@ namespace NTwain.Triplets
DataGroups dg,
DataArgumentType dat,
Message msg,
- [In, Out]TW_CALLBACK data);
+ ref TW_CALLBACK data);
[DllImport(WinDsmDll, EntryPoint = EntryName)]
public static extern ReturnCode DsmWin32(
@@ -79,7 +79,7 @@ namespace NTwain.Triplets
DataGroups dg,
DataArgumentType dat,
Message msg,
- [In, Out]TW_CALLBACK2 data);
+ ref TW_CALLBACK2 data);
[DllImport(WinDsmDll, EntryPoint = EntryName)]
public static extern ReturnCode DsmWin32(
diff --git a/src/NTwain/TwainSession.MsgHandling.cs b/src/NTwain/TwainSession.MsgHandling.cs
new file mode 100644
index 0000000..f5ed4f9
--- /dev/null
+++ b/src/NTwain/TwainSession.MsgHandling.cs
@@ -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)
+ {
+
+ }
+ }
+}
diff --git a/src/NTwain/TwainSession.cs b/src/NTwain/TwainSession.cs
index 56864bf..f4de1dd 100644
--- a/src/NTwain/TwainSession.cs
+++ b/src/NTwain/TwainSession.cs
@@ -3,8 +3,11 @@ 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
{
@@ -14,10 +17,12 @@ namespace NTwain
public partial class TwainSession
{
internal readonly TwainConfig Config;
+
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
readonly Dictionary _ownedSources = new Dictionary();
+ // need to keep delegate around to prevent GC?
+ readonly CallbackDelegate _callbackDelegate;
///
/// Constructs a new .
@@ -26,6 +31,14 @@ namespace NTwain
public TwainSession(TwainConfig config)
{
Config = config;
+ switch (config.Platform)
+ {
+ case PlatformID.MacOSX:
+ case PlatformID.Unix:
+ default:
+ _callbackDelegate = new CallbackDelegate(HandleWin32Callback);
+ break;
+ }
}
///
@@ -36,7 +49,7 @@ namespace NTwain
public ReturnCode Open(IntPtr hWnd)
{
_hWnd = hWnd;
- return DGControl.Parent.OpenDSM(ref hWnd);
+ return DGControl.Parent.OpenDSM(hWnd);
}
///
@@ -52,7 +65,7 @@ namespace NTwain
switch (State)
{
case TwainState.DsmOpened:
- rc = DGControl.Parent.CloseDSM(ref _hWnd);
+ rc = DGControl.Parent.CloseDSM(_hWnd);
if (rc != ReturnCode.Success) return rc;
break;
case TwainState.SourceOpened:
@@ -64,38 +77,37 @@ namespace NTwain
return rc;
}
- internal void UpdateCallback()
+ internal void RegisterCallback()
{
- if (State < TwainState.S4)
- {
- _callbackObj = null;
- }
- else
+ if (State == TwainState.S4)
{
+ var callbackPtr = Marshal.GetFunctionPointerForDelegate(_callbackDelegate);
+
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)
+ var cb = new TW_CALLBACK2 { CallBackProc = callbackPtr };
+ rc = DGControl.Callback2.RegisterCallback(ref cb);
+ if (rc == ReturnCode.Success) Debug.WriteLine("Registed Callback2 success.");
+ else
{
- _callbackObj = cb;
+
}
}
if (rc != ReturnCode.Success)
{
// 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
///
public IEnumerable GetSources()
{
- TW_IDENTITY srcId;
- var rc = DGControl.Identity.GetFirst(out srcId);
+ var rc = DGControl.Identity.GetFirst(out TW_IDENTITY srcId);
while (rc == ReturnCode.Success)
{
yield return GetSourceSingleton(srcId);
@@ -124,8 +135,7 @@ namespace NTwain
{
get
{
- TW_IDENTITY src;
- if (DGControl.Identity.GetDefault(out src) == ReturnCode.Success)
+ if (DGControl.Identity.GetDefault(out TW_IDENTITY src) == ReturnCode.Success)
{
return GetSourceSingleton(src);
}
@@ -151,8 +161,7 @@ namespace NTwain
///
public DataSource ShowSourceSelector()
{
- TW_IDENTITY id;
- if (DGControl.Identity.UserSelect(out id) == ReturnCode.Success)
+ if (DGControl.Identity.UserSelect(out TW_IDENTITY id) == ReturnCode.Success)
{
return GetSourceSingleton(id);
}
@@ -182,35 +191,12 @@ namespace NTwain
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)
{
- //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;
+ Debug.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: {nameof(HandleWin32Callback)}({dg}, {dat}, {msg}, {data})");
+ HandleSourceMsg(msg);
+ return ReturnCode.Success;
}
}
}