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;