mirror of
https://github.com/soukoku/ntwain.git
synced 2025-07-17 16:22:54 +08:00
Added most hooks except xfer logic and winform/wpf versions.
This commit is contained in:
parent
94f2720de4
commit
0064db2c2d
@ -27,11 +27,4 @@ namespace NTwain
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
DGImage DGImage { get; }
|
DGImage DGImage { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Internal interface for operations use.
|
|
||||||
/// </summary>
|
|
||||||
interface ITwainOperationInternal : ITwainOperation
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,8 @@
|
|||||||
<Compile Include="Triplets\PInvokes.64bit.cs" />
|
<Compile Include="Triplets\PInvokes.64bit.cs" />
|
||||||
<Compile Include="TwainSessionExtensions.cs" />
|
<Compile Include="TwainSessionExtensions.cs" />
|
||||||
<Compile Include="TwainSessionBase.cs" />
|
<Compile Include="TwainSessionBase.cs" />
|
||||||
|
<Compile Include="TwainSessionWPF.cs" />
|
||||||
|
<Compile Include="TwainSessionWinform.cs" />
|
||||||
<Compile Include="TwainStateException.cs" />
|
<Compile Include="TwainStateException.cs" />
|
||||||
<Compile Include="Data\Types.cs" />
|
<Compile Include="Data\Types.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
@ -715,14 +715,16 @@ namespace NTwain
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// no need to lock for marshal alloc
|
// no need to lock for marshal alloc
|
||||||
msgPtr = MemoryManager.Instance.Allocate((uint)Marshal.SizeOf(winmsg));
|
//msgPtr = MemoryManager.Instance.Allocate((uint)Marshal.SizeOf(winmsg));
|
||||||
|
msgPtr = Marshal.AllocHGlobal(Marshal.SizeOf(winmsg));
|
||||||
Marshal.StructureToPtr(winmsg, msgPtr, false);
|
Marshal.StructureToPtr(winmsg, msgPtr, false);
|
||||||
return HandleLoopMsgEvent(ref msgPtr);
|
return HandleLoopMsgEvent(ref msgPtr);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (msgPtr != IntPtr.Zero)
|
if (msgPtr != IntPtr.Zero)
|
||||||
MemoryManager.Instance.Free(msgPtr);
|
Marshal.FreeHGlobal(msgPtr);
|
||||||
|
//MemoryManager.Instance.Free(msgPtr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -754,14 +756,16 @@ namespace NTwain
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// no need to lock for marshal alloc
|
// no need to lock for marshal alloc
|
||||||
msgPtr = MemoryManager.Instance.Allocate((uint)Marshal.SizeOf(winmsg));
|
//msgPtr = MemoryManager.Instance.Allocate((uint)Marshal.SizeOf(winmsg));
|
||||||
|
msgPtr = Marshal.AllocHGlobal(Marshal.SizeOf(winmsg));
|
||||||
Marshal.StructureToPtr(winmsg, msgPtr, false);
|
Marshal.StructureToPtr(winmsg, msgPtr, false);
|
||||||
handled = HandleLoopMsgEvent(ref msgPtr);
|
handled = HandleLoopMsgEvent(ref msgPtr);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (msgPtr != IntPtr.Zero)
|
if (msgPtr != IntPtr.Zero)
|
||||||
MemoryManager.Instance.Free(msgPtr);
|
Marshal.FreeHGlobal(msgPtr);
|
||||||
|
//MemoryManager.Instance.Free(msgPtr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return IntPtr.Zero;
|
return IntPtr.Zero;
|
||||||
|
@ -9,13 +9,14 @@ using System.Linq;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Windows.Interop;
|
||||||
|
|
||||||
namespace NTwain
|
namespace NTwain
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base working class for interfacing with TWAIN.
|
/// Base class for interfacing with TWAIN.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TwainSessionBase : ITwainStateInternal, ITwainOperationInternal
|
public class TwainSessionBase : ITwainStateInternal, ITwainOperation
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="TwainSession" /> class.
|
/// Initializes a new instance of the <see cref="TwainSession" /> class.
|
||||||
@ -276,7 +277,7 @@ namespace NTwain
|
|||||||
// app v2.2 or higher uses callback2
|
// app v2.2 or higher uses callback2
|
||||||
if (_appId.ProtocolMajor >= 2 && _appId.ProtocolMinor >= 2)
|
if (_appId.ProtocolMajor >= 2 && _appId.ProtocolMinor >= 2)
|
||||||
{
|
{
|
||||||
var cb = new TWCallback2(CallbackHandler);
|
var cb = new TWCallback2(HandleCallback);
|
||||||
var rc2 = DGControl.Callback2.RegisterCallback(cb);
|
var rc2 = DGControl.Callback2.RegisterCallback(cb);
|
||||||
|
|
||||||
if (rc2 == ReturnCode.Success)
|
if (rc2 == ReturnCode.Success)
|
||||||
@ -287,7 +288,7 @@ namespace NTwain
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var cb = new TWCallback(CallbackHandler);
|
var cb = new TWCallback(HandleCallback);
|
||||||
|
|
||||||
var rc2 = DGControl.Callback.RegisterCallback(cb);
|
var rc2 = DGControl.Callback.RegisterCallback(cb);
|
||||||
|
|
||||||
@ -384,36 +385,143 @@ namespace NTwain
|
|||||||
|
|
||||||
#region custom events and overridables
|
#region custom events and overridables
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when <see cref="State"/> has changed.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler StateChanged;
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when <see cref="SourceId"/> has changed.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler SourceChanged;
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when source has been disabled (back to state 4).
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler SourceDisabled;
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when the source has generated an event.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<DeviceEventArgs> DeviceEvent;
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when a data transfer is ready.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<TransferReadyEventArgs> TransferReady;
|
||||||
|
/// <summary>
|
||||||
|
/// Occurs when data has been transferred.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<DataTransferredEventArgs> DataTransferred;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when <see cref="State"/> changed.
|
/// Called when <see cref="State"/> changed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnStateChanged() { }
|
protected virtual void OnStateChanged()
|
||||||
|
{
|
||||||
|
var hand = StateChanged;
|
||||||
|
if (hand != null)
|
||||||
|
{
|
||||||
|
hand(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when <see cref="SourceId"/> changed.
|
/// Called when <see cref="SourceId"/> changed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnSourceIdChanged() { }
|
protected virtual void OnSourceChanged()
|
||||||
|
{
|
||||||
|
var hand = SourceChanged;
|
||||||
|
if (hand != null)
|
||||||
|
{
|
||||||
|
hand(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when source has been disabled (back to state 4).
|
/// Called when source has been disabled (back to state 4).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnSourceDisabled() { }
|
protected virtual void OnSourceDisabled()
|
||||||
|
{
|
||||||
|
var hand = SourceDisabled;
|
||||||
|
if (hand != null)
|
||||||
|
{
|
||||||
|
hand(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raises the <see cref="E:DeviceEvent" /> event.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e">The <see cref="DeviceEventArgs"/> instance containing the event data.</param>
|
||||||
|
protected virtual void OnDeviceEvent(DeviceEventArgs e)
|
||||||
|
{
|
||||||
|
var hand = DeviceEvent;
|
||||||
|
if (hand != null)
|
||||||
|
{
|
||||||
|
hand(this, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raises the <see cref="E:TransferReady" /> event.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e">The <see cref="TransferReadyEventArgs"/> instance containing the event data.</param>
|
||||||
|
protected virtual void OnTransferReady(TransferReadyEventArgs e)
|
||||||
|
{
|
||||||
|
var hand = TransferReady;
|
||||||
|
if (hand != null)
|
||||||
|
{
|
||||||
|
hand(this, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raises the <see cref="E:DataTransferred" /> event.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e">The <see cref="DataTransferredEventArgs"/> instance containing the event data.</param>
|
||||||
|
protected virtual void OnDataTransferred(DataTransferredEventArgs e)
|
||||||
|
{
|
||||||
|
var hand = DataTransferred;
|
||||||
|
if (hand != null)
|
||||||
|
{
|
||||||
|
hand(this, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region real TWAIN logic during xfer
|
#region real TWAIN logic during xfer
|
||||||
|
|
||||||
void HandleSourceMsg(TWIdentity origin, TWIdentity destination, DataGroups dg, DataArgumentType dat, Message msg, IntPtr data)
|
/// <summary>
|
||||||
|
/// Handles the message from a typical WndProc message loop and check if it's from the TWAIN source.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message.</param>
|
||||||
|
/// <returns>True if handled by TWAIN.</returns>
|
||||||
|
protected bool HandleWndProcMessage(ref MSG message)
|
||||||
{
|
{
|
||||||
if (msg != Message.Null)
|
if (State >= 4) // technically we should only handle on state >= 5 but there might be missed msgs if we wait until state changes after enabling ds
|
||||||
{
|
{
|
||||||
Debug.WriteLine(string.Format("Thread {0}: HandleSourceMsg at state {1} with DG={2} DAT={3} MSG={4}.", Thread.CurrentThread.ManagedThreadId, State, dg, dat, msg));
|
// transform it into a pointer for twain
|
||||||
|
IntPtr msgPtr = IntPtr.Zero;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// no need to do another lock call when using marshal alloc
|
||||||
|
msgPtr = Marshal.AllocHGlobal(Marshal.SizeOf(message));
|
||||||
|
Marshal.StructureToPtr(message, msgPtr, false);
|
||||||
|
|
||||||
|
TWEvent evt = new TWEvent();
|
||||||
|
evt.pEvent = msgPtr;
|
||||||
|
var rc = DGControl.Event.ProcessEvent(evt);
|
||||||
|
// TODO: not sure what to DAT to pass
|
||||||
|
HandleSourceMsg(null, null, DataGroups.Control, DataArgumentType.Null, evt.TWMessage, IntPtr.Zero);
|
||||||
|
return rc == ReturnCode.DSEvent;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (msgPtr != IntPtr.Zero) { Marshal.FreeHGlobal(msgPtr); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode CallbackHandler(TWIdentity origin, TWIdentity destination, DataGroups dg, DataArgumentType dat, Message msg, IntPtr data)
|
ReturnCode HandleCallback(TWIdentity origin, TWIdentity destination, DataGroups dg, DataArgumentType dat, Message msg, IntPtr data)
|
||||||
{
|
{
|
||||||
if (origin != null && SourceId != null && origin.Id == SourceId.Id)
|
if (origin != null && SourceId != null && origin.Id == SourceId.Id)
|
||||||
{
|
{
|
||||||
@ -444,6 +552,16 @@ namespace NTwain
|
|||||||
return ReturnCode.Failure;
|
return ReturnCode.Failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// final method that handles stuff from the source, whether it's from wndproc or callbacks
|
||||||
|
void HandleSourceMsg(TWIdentity origin, TWIdentity destination, DataGroups dg, DataArgumentType dat, Message msg, IntPtr data)
|
||||||
|
{
|
||||||
|
if (msg != Message.Null)
|
||||||
|
{
|
||||||
|
Debug.WriteLine(string.Format("Thread {0}: HandleSourceMsg at state {1} with DG={2} DAT={3} MSG={4}.", Thread.CurrentThread.ManagedThreadId, State, dg, dat, msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
48
NTwain/TwainSessionWPF.cs
Normal file
48
NTwain/TwainSessionWPF.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
using NTwain.Data;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Permissions;
|
||||||
|
using System.Text;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.Windows.Interop;
|
||||||
|
|
||||||
|
namespace NTwain
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A customized TWAIN session for use in WPF environment.
|
||||||
|
/// Use this by using <see cref="PreFilterMessage"/> method as the target of <see cref="HwndSource.AddHook"/> delegate.
|
||||||
|
/// </summary>
|
||||||
|
public class TwainSessionWPF : TwainSessionBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="TwainSessionWPF" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="appId">The app id.</param>
|
||||||
|
/// <exception cref="System.ArgumentNullException"></exception>
|
||||||
|
public TwainSessionWPF(TWIdentity appId) : base(appId) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Message loop processor for WPF.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hwnd">The window handle.</param>
|
||||||
|
/// <param name="msg">The message ID.</param>
|
||||||
|
/// <param name="wParam">The message's wParam value.</param>
|
||||||
|
/// <param name="lParam">The message's lParam value.</param>
|
||||||
|
/// <param name="handled">A value that indicates whether the message was handled. Set the value to true if the message was handled; otherwise, false.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[EnvironmentPermissionAttribute(SecurityAction.LinkDemand)]
|
||||||
|
public IntPtr PreFilterMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
|
||||||
|
{
|
||||||
|
MSG winmsg = default(MSG);
|
||||||
|
winmsg.hwnd = hwnd;
|
||||||
|
winmsg.lParam = lParam;
|
||||||
|
winmsg.message = msg;
|
||||||
|
winmsg.wParam = wParam;
|
||||||
|
|
||||||
|
handled = base.HandleWndProcMessage(ref winmsg);
|
||||||
|
|
||||||
|
return IntPtr.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
NTwain/TwainSessionWinform.cs
Normal file
39
NTwain/TwainSessionWinform.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
using NTwain.Data;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.Windows.Interop;
|
||||||
|
|
||||||
|
namespace NTwain
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A customized TWAIN session for use in winform environment.
|
||||||
|
/// Use this by adding this as an <see cref="IMessageFilter "/> via <see cref="Application.AddMessageFilter"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class TwainSessionWinform : TwainSessionBase, IMessageFilter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="TwainSessionWinform" /> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="appId">The app id.</param>
|
||||||
|
/// <exception cref="System.ArgumentNullException"></exception>
|
||||||
|
public TwainSessionWinform(TWIdentity appId) : base(appId) { }
|
||||||
|
|
||||||
|
#region IMessageFilter Members
|
||||||
|
|
||||||
|
bool IMessageFilter.PreFilterMessage(ref Message m)
|
||||||
|
{
|
||||||
|
MSG winmsg = default(MSG);
|
||||||
|
winmsg.hwnd = m.HWnd;
|
||||||
|
winmsg.lParam = m.LParam;
|
||||||
|
winmsg.message = m.Msg;
|
||||||
|
winmsg.wParam = m.WParam;
|
||||||
|
|
||||||
|
return HandleWndProcMessage(ref winmsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user