From 3fc0b9709614170066b1bc63c5fd2047c8bacb32 Mon Sep 17 00:00:00 2001
From: Eugene Wang <8755753+soukoku@users.noreply.github.com>
Date: Sun, 2 Apr 2023 07:43:10 -0400
Subject: [PATCH] Add callback reg after opening source.
---
src/NTwain/DSM/OSXLegacyDSM.cs | 21 +++++++
src/NTwain/DSM/OSXNewDSM.cs | 21 +++++++
src/NTwain/DSM/WinLegacyDSM.cs | 21 +++++++
src/NTwain/DSM/WinNewDSM.cs | 21 +++++++
src/NTwain/Triplets/DATCallback.cs | 57 +++++++++++++++++
src/NTwain/Triplets/DATCallback2.cs | 57 +++++++++++++++++
src/NTwain/Triplets/DATIdentity.cs | 12 +---
src/NTwain/Triplets/DATParent.cs | 7 ++-
src/NTwain/Triplets/DGControl.cs | 6 ++
src/NTwain/TwainSession.Callbacks.cs | 91 +++++++++++++++++++++++++++
src/NTwain/TwainSession.PropEvents.cs | 2 +-
src/NTwain/TwainSession.cs | 3 +
12 files changed, 305 insertions(+), 14 deletions(-)
create mode 100644 src/NTwain/Triplets/DATCallback.cs
create mode 100644 src/NTwain/Triplets/DATCallback2.cs
create mode 100644 src/NTwain/TwainSession.Callbacks.cs
diff --git a/src/NTwain/DSM/OSXLegacyDSM.cs b/src/NTwain/DSM/OSXLegacyDSM.cs
index 06dc69f..de65b24 100644
--- a/src/NTwain/DSM/OSXLegacyDSM.cs
+++ b/src/NTwain/DSM/OSXLegacyDSM.cs
@@ -93,5 +93,26 @@ namespace NTwain.DSM
MSG msg,
ref TW_CUSTOMDSDATA twcustomedsdata
);
+
+ [DllImport(DsmName, CharSet = CharSet.Ansi)]
+ internal static extern UInt16 DSM_Entry
+ (
+ ref TW_IDENTITY_MACOSX origin,
+ ref TW_IDENTITY_MACOSX dest,
+ DG dg,
+ DAT dat,
+ MSG msg,
+ ref TW_CALLBACK twcallback
+ );
+ [DllImport(DsmName, CharSet = CharSet.Ansi)]
+ internal static extern UInt16 DSM_Entry
+ (
+ ref TW_IDENTITY_MACOSX origin,
+ ref TW_IDENTITY_MACOSX dest,
+ DG dg,
+ DAT dat,
+ MSG msg,
+ ref TW_CALLBACK2 twcallback
+ );
}
}
diff --git a/src/NTwain/DSM/OSXNewDSM.cs b/src/NTwain/DSM/OSXNewDSM.cs
index 9ef0f42..05b159c 100644
--- a/src/NTwain/DSM/OSXNewDSM.cs
+++ b/src/NTwain/DSM/OSXNewDSM.cs
@@ -93,5 +93,26 @@ namespace NTwain.DSM
MSG msg,
ref TW_CUSTOMDSDATA twcustomedsdata
);
+
+ [DllImport(DsmName, CharSet = CharSet.Ansi)]
+ internal static extern UInt16 DSM_Entry
+ (
+ ref TW_IDENTITY_MACOSX origin,
+ ref TW_IDENTITY_MACOSX dest,
+ DG dg,
+ DAT dat,
+ MSG msg,
+ ref TW_CALLBACK twcallback
+ );
+ [DllImport(DsmName, CharSet = CharSet.Ansi)]
+ internal static extern UInt16 DSM_Entry
+ (
+ ref TW_IDENTITY_MACOSX origin,
+ ref TW_IDENTITY_MACOSX dest,
+ DG dg,
+ DAT dat,
+ MSG msg,
+ ref TW_CALLBACK2 twcallback
+ );
}
}
diff --git a/src/NTwain/DSM/WinLegacyDSM.cs b/src/NTwain/DSM/WinLegacyDSM.cs
index d4d76d3..6b19c09 100644
--- a/src/NTwain/DSM/WinLegacyDSM.cs
+++ b/src/NTwain/DSM/WinLegacyDSM.cs
@@ -93,5 +93,26 @@ namespace NTwain.DSM
MSG msg,
ref TW_CUSTOMDSDATA twcustomedsdata
);
+
+ [DllImport(DsmName, CharSet = CharSet.Ansi)]
+ internal static extern UInt16 DSM_Entry
+ (
+ ref TW_IDENTITY_LEGACY origin,
+ ref TW_IDENTITY_LEGACY dest,
+ DG dg,
+ DAT dat,
+ MSG msg,
+ ref TW_CALLBACK twcallback
+ );
+ [DllImport(DsmName, CharSet = CharSet.Ansi)]
+ internal static extern UInt16 DSM_Entry
+ (
+ ref TW_IDENTITY_LEGACY origin,
+ ref TW_IDENTITY_LEGACY dest,
+ DG dg,
+ DAT dat,
+ MSG msg,
+ ref TW_CALLBACK2 twcallback
+ );
}
}
diff --git a/src/NTwain/DSM/WinNewDSM.cs b/src/NTwain/DSM/WinNewDSM.cs
index c2d693c..4eb42b5 100644
--- a/src/NTwain/DSM/WinNewDSM.cs
+++ b/src/NTwain/DSM/WinNewDSM.cs
@@ -93,5 +93,26 @@ namespace NTwain.DSM
MSG msg,
ref TW_CUSTOMDSDATA twcustomedsdata
);
+
+ [DllImport(DsmName, CharSet = CharSet.Ansi)]
+ internal static extern UInt16 DSM_Entry
+ (
+ ref TW_IDENTITY_LEGACY origin,
+ ref TW_IDENTITY_LEGACY dest,
+ DG dg,
+ DAT dat,
+ MSG msg,
+ ref TW_CALLBACK twcallback
+ );
+ [DllImport(DsmName, CharSet = CharSet.Ansi)]
+ internal static extern UInt16 DSM_Entry
+ (
+ ref TW_IDENTITY_LEGACY origin,
+ ref TW_IDENTITY_LEGACY dest,
+ DG dg,
+ DAT dat,
+ MSG msg,
+ ref TW_CALLBACK2 twcallback
+ );
}
}
diff --git a/src/NTwain/Triplets/DATCallback.cs b/src/NTwain/Triplets/DATCallback.cs
new file mode 100644
index 0000000..5f2d2aa
--- /dev/null
+++ b/src/NTwain/Triplets/DATCallback.cs
@@ -0,0 +1,57 @@
+using NTwain.DSM;
+using TWAINWorkingGroup;
+
+namespace NTwain.Triplets
+{
+ ///
+ /// Contains calls used with and .
+ ///
+ public class DATCallback : TripletBase
+ {
+ public DATCallback(TwainSession session) : base(session)
+ {
+ }
+
+ ///
+ /// Registers the callback function.
+ ///
+ ///
+ ///
+ public STS RegisterCallback(ref TW_CALLBACK data)
+ {
+ return DoIt(MSG.REGISTER_CALLBACK, ref data);
+ }
+
+ STS DoIt(MSG msg, ref TW_CALLBACK data)
+ {
+ var rc = STS.FAILURE;
+ if (TwainPlatform.IsWindows)
+ {
+ var app = Session.AppIdentity;
+ var ds = Session.CurrentSource;
+ if (TwainPlatform.Is32bit && TwainPlatform.PreferLegacyDSM)
+ {
+ rc = (STS)WinLegacyDSM.DSM_Entry(ref app, ref ds, DG.CONTROL, DAT.DEVICEEVENT, msg, ref data);
+ }
+ else
+ {
+ rc = (STS)WinNewDSM.DSM_Entry(ref app, ref ds, DG.CONTROL, DAT.DEVICEEVENT, msg, ref data);
+ }
+ }
+ else if (TwainPlatform.IsMacOSX)
+ {
+ TW_IDENTITY_MACOSX app = Session.AppIdentity;
+ TW_IDENTITY_MACOSX ds = Session.CurrentSource;
+ if (TwainPlatform.PreferLegacyDSM)
+ {
+ rc = (STS)OSXLegacyDSM.DSM_Entry(ref app, ref ds, DG.CONTROL, DAT.DEVICEEVENT, msg, ref data);
+ }
+ else
+ {
+ rc = (STS)OSXNewDSM.DSM_Entry(ref app, ref ds, DG.CONTROL, DAT.DEVICEEVENT, msg, ref data);
+ }
+ }
+ return rc;
+ }
+ }
+}
diff --git a/src/NTwain/Triplets/DATCallback2.cs b/src/NTwain/Triplets/DATCallback2.cs
new file mode 100644
index 0000000..130cf3f
--- /dev/null
+++ b/src/NTwain/Triplets/DATCallback2.cs
@@ -0,0 +1,57 @@
+using NTwain.DSM;
+using TWAINWorkingGroup;
+
+namespace NTwain.Triplets
+{
+ ///
+ /// Contains calls used with and .
+ ///
+ public class DATCallback2 : TripletBase
+ {
+ public DATCallback2(TwainSession session) : base(session)
+ {
+ }
+
+ ///
+ /// Registers the callback function.
+ ///
+ ///
+ ///
+ public STS RegisterCallback(ref TW_CALLBACK2 data)
+ {
+ return DoIt(MSG.REGISTER_CALLBACK, ref data);
+ }
+
+ STS DoIt(MSG msg, ref TW_CALLBACK2 data)
+ {
+ var rc = STS.FAILURE;
+ if (TwainPlatform.IsWindows)
+ {
+ var app = Session.AppIdentity;
+ var ds = Session.CurrentSource;
+ if (TwainPlatform.Is32bit && TwainPlatform.PreferLegacyDSM)
+ {
+ rc = (STS)WinLegacyDSM.DSM_Entry(ref app, ref ds, DG.CONTROL, DAT.DEVICEEVENT, msg, ref data);
+ }
+ else
+ {
+ rc = (STS)WinNewDSM.DSM_Entry(ref app, ref ds, DG.CONTROL, DAT.DEVICEEVENT, msg, ref data);
+ }
+ }
+ else if (TwainPlatform.IsMacOSX)
+ {
+ TW_IDENTITY_MACOSX app = Session.AppIdentity;
+ TW_IDENTITY_MACOSX ds = Session.CurrentSource;
+ if (TwainPlatform.PreferLegacyDSM)
+ {
+ rc = (STS)OSXLegacyDSM.DSM_Entry(ref app, ref ds, DG.CONTROL, DAT.DEVICEEVENT, msg, ref data);
+ }
+ else
+ {
+ rc = (STS)OSXNewDSM.DSM_Entry(ref app, ref ds, DG.CONTROL, DAT.DEVICEEVENT, msg, ref data);
+ }
+ }
+ return rc;
+ }
+ }
+}
diff --git a/src/NTwain/Triplets/DATIdentity.cs b/src/NTwain/Triplets/DATIdentity.cs
index 0f6057a..421fc7f 100644
--- a/src/NTwain/Triplets/DATIdentity.cs
+++ b/src/NTwain/Triplets/DATIdentity.cs
@@ -24,16 +24,8 @@ namespace NTwain.Triplets
if ((rc = DoIt(MSG.OPENDS, ref ds)) == STS.SUCCESS)
{
Session.CurrentSource = ds;
+ Session.RegisterCallback();
Session.State = STATE.S4;
- //// determine memory mgmt routines used
- //if ((((DG)Session._appIdentity.SupportedGroups) & DG.DSM2) == DG.DSM2)
- //{
- // TW_ENTRYPOINT_DELEGATES entry = default;
- // if (Session.DGControl.EntryPoint.Get(ref entry) == STS.SUCCESS)
- // {
- // Session._entryPoint = entry;
- // }
- //}
}
return rc;
}
@@ -48,8 +40,8 @@ namespace NTwain.Triplets
var ds = Session.CurrentSource;
if ((rc = DoIt(MSG.CLOSEDS, ref ds)) == STS.SUCCESS)
{
- Session.CurrentSource = default;
Session.State = STATE.S3;
+ Session.CurrentSource = default;
}
return rc;
}
diff --git a/src/NTwain/Triplets/DATParent.cs b/src/NTwain/Triplets/DATParent.cs
index 79ba354..ce810fa 100644
--- a/src/NTwain/Triplets/DATParent.cs
+++ b/src/NTwain/Triplets/DATParent.cs
@@ -24,7 +24,6 @@ namespace NTwain.Triplets
if ((rc = DoIt(MSG.OPENDSM, ref hwnd)) == STS.SUCCESS)
{
Session._hwnd = hwnd;
- Session.State = STATE.S3;
// get default source
if (Session.DGControl.Identity.GetDefault(out TW_IDENTITY_LEGACY ds) == STS.SUCCESS)
@@ -40,6 +39,7 @@ namespace NTwain.Triplets
Session._entryPoint = entry;
}
}
+ Session.State = STATE.S3;
}
return rc;
}
@@ -54,9 +54,10 @@ namespace NTwain.Triplets
STS rc;
if ((rc = DoIt(MSG.CLOSEDSM, ref hwnd)) == STS.SUCCESS)
{
- Session._hwnd = IntPtr.Zero;
- Session._entryPoint = default;
Session.State = STATE.S2;
+ Session._entryPoint = default;
+ Session.DefaultSource = default;
+ Session._hwnd = IntPtr.Zero;
}
return rc;
}
diff --git a/src/NTwain/Triplets/DGControl.cs b/src/NTwain/Triplets/DGControl.cs
index 4622ce1..18ec0bc 100644
--- a/src/NTwain/Triplets/DGControl.cs
+++ b/src/NTwain/Triplets/DGControl.cs
@@ -30,5 +30,11 @@
private DATDeviceEvent? _deviceEvent;
public DATDeviceEvent DeviceEvent => _deviceEvent ??= new DATDeviceEvent(Session);
+ private DATCallback? _callback;
+ public DATCallback Callback => _callback ??= new DATCallback(Session);
+
+ private DATCallback2? _callback2;
+ public DATCallback2 Callback2 => _callback2 ??= new DATCallback2(Session);
+
}
}
\ No newline at end of file
diff --git a/src/NTwain/TwainSession.Callbacks.cs b/src/NTwain/TwainSession.Callbacks.cs
new file mode 100644
index 0000000..e3c16ef
--- /dev/null
+++ b/src/NTwain/TwainSession.Callbacks.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Runtime.InteropServices;
+using TWAINWorkingGroup;
+
+namespace NTwain
+{
+ // this file contains callback methods
+
+ partial class TwainSession
+ {
+ // these are kept around while a callback ptr is registered so they
+ // don't get gc'd
+ readonly NativeMethods.WindowsDsmEntryCallbackDelegate _legacyCallbackDelegate;
+ readonly NativeMethods.MacosxDsmEntryCallbackDelegate _osxCallbackDelegate;
+
+ ///
+ /// Try to registers callbacks for after opening the source.
+ ///
+ internal void RegisterCallback()
+ {
+ IntPtr cbPtr = IntPtr.Zero;
+
+ if (TwainPlatform.IsMacOSX)
+ {
+ cbPtr = Marshal.GetFunctionPointerForDelegate(_osxCallbackDelegate);
+ }
+ else
+ {
+ cbPtr = Marshal.GetFunctionPointerForDelegate(_legacyCallbackDelegate);
+ }
+
+ var rc = STS.FAILURE;
+
+ // per the spec (pg 8-10), apps for 2.2 or higher uses callback2 so try this first
+ if (_appIdentity.ProtocolMajor > 2 || (_appIdentity.ProtocolMajor >= 2 && _appIdentity.ProtocolMinor >= 2))
+ {
+ var cb2 = new TW_CALLBACK2 { CallBackProc = cbPtr };
+ rc = DGControl.Callback2.RegisterCallback(ref cb2);
+ }
+ if (rc != STS.SUCCESS)
+ {
+ // always try old callback
+ var cb = new TW_CALLBACK { CallBackProc = cbPtr };
+ DGControl.Callback.RegisterCallback(ref cb);
+ }
+ }
+
+ private ushort LegacyCallbackHandler
+ (
+ ref TW_IDENTITY_LEGACY origin,
+ ref TW_IDENTITY_LEGACY dest,
+ DG dg,
+ DAT dat,
+ MSG msg,
+ IntPtr twnull
+ )
+ {
+ HandleSourceMsg(msg);
+ return (ushort)STS.SUCCESS;
+ }
+
+ private ushort OSXCallbackHandler
+ (
+ ref TW_IDENTITY_MACOSX origin,
+ ref TW_IDENTITY_MACOSX dest,
+ DG dg,
+ DAT dat,
+ MSG msg,
+ IntPtr twnull
+ )
+ {
+ HandleSourceMsg(msg);
+ return (ushort)STS.SUCCESS;
+ }
+
+ private void HandleSourceMsg(MSG msg)
+ {
+ switch (msg)
+ {
+ case MSG.XFERREADY:
+ break;
+ case MSG.DEVICEEVENT:
+ break;
+ case MSG.CLOSEDSOK:
+ break;
+ case MSG.CLOSEDSREQ:
+ break;
+ }
+ }
+ }
+}
diff --git a/src/NTwain/TwainSession.PropEvents.cs b/src/NTwain/TwainSession.PropEvents.cs
index c4bfe74..f83b3a9 100644
--- a/src/NTwain/TwainSession.PropEvents.cs
+++ b/src/NTwain/TwainSession.PropEvents.cs
@@ -2,6 +2,7 @@
using System;
using System.Runtime.InteropServices;
using TWAINWorkingGroup;
+using static System.Collections.Specialized.BitVector32;
namespace NTwain
{
@@ -151,6 +152,5 @@ namespace NTwain
/// Fires when changes.
///
public event Action? CurrentSourceChanged;
-
}
}
diff --git a/src/NTwain/TwainSession.cs b/src/NTwain/TwainSession.cs
index 04935a0..c2f37f2 100644
--- a/src/NTwain/TwainSession.cs
+++ b/src/NTwain/TwainSession.cs
@@ -81,6 +81,9 @@ namespace NTwain
DGControl = new DGControl(this);
DGImage = new DGImage(this);
DGAudio = new DGAudio(this);
+
+ _legacyCallbackDelegate = LegacyCallbackHandler;
+ _osxCallbackDelegate = OSXCallbackHandler;
}
internal IntPtr _hwnd;