mirror of
https://github.com/soukoku/ntwain.git
synced 2025-07-16 17:45:29 +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>
|
||||
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="TwainSessionExtensions.cs" />
|
||||
<Compile Include="TwainSessionBase.cs" />
|
||||
<Compile Include="TwainSessionWPF.cs" />
|
||||
<Compile Include="TwainSessionWinform.cs" />
|
||||
<Compile Include="TwainStateException.cs" />
|
||||
<Compile Include="Data\Types.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
|
@ -715,14 +715,16 @@ namespace NTwain
|
||||
try
|
||||
{
|
||||
// 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);
|
||||
return HandleLoopMsgEvent(ref msgPtr);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (msgPtr != IntPtr.Zero)
|
||||
MemoryManager.Instance.Free(msgPtr);
|
||||
Marshal.FreeHGlobal(msgPtr);
|
||||
//MemoryManager.Instance.Free(msgPtr);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -754,14 +756,16 @@ namespace NTwain
|
||||
try
|
||||
{
|
||||
// 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);
|
||||
handled = HandleLoopMsgEvent(ref msgPtr);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (msgPtr != IntPtr.Zero)
|
||||
MemoryManager.Instance.Free(msgPtr);
|
||||
Marshal.FreeHGlobal(msgPtr);
|
||||
//MemoryManager.Instance.Free(msgPtr);
|
||||
}
|
||||
}
|
||||
return IntPtr.Zero;
|
||||
|
@ -9,13 +9,14 @@ using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows.Interop;
|
||||
|
||||
namespace NTwain
|
||||
{
|
||||
/// <summary>
|
||||
/// Base working class for interfacing with TWAIN.
|
||||
/// Base class for interfacing with TWAIN.
|
||||
/// </summary>
|
||||
public class TwainSessionBase : ITwainStateInternal, ITwainOperationInternal
|
||||
public class TwainSessionBase : ITwainStateInternal, ITwainOperation
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TwainSession" /> class.
|
||||
@ -276,7 +277,7 @@ namespace NTwain
|
||||
// app v2.2 or higher uses callback2
|
||||
if (_appId.ProtocolMajor >= 2 && _appId.ProtocolMinor >= 2)
|
||||
{
|
||||
var cb = new TWCallback2(CallbackHandler);
|
||||
var cb = new TWCallback2(HandleCallback);
|
||||
var rc2 = DGControl.Callback2.RegisterCallback(cb);
|
||||
|
||||
if (rc2 == ReturnCode.Success)
|
||||
@ -287,7 +288,7 @@ namespace NTwain
|
||||
}
|
||||
else
|
||||
{
|
||||
var cb = new TWCallback(CallbackHandler);
|
||||
var cb = new TWCallback(HandleCallback);
|
||||
|
||||
var rc2 = DGControl.Callback.RegisterCallback(cb);
|
||||
|
||||
@ -384,36 +385,143 @@ namespace NTwain
|
||||
|
||||
#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>
|
||||
/// Called when <see cref="State"/> changed.
|
||||
/// </summary>
|
||||
protected virtual void OnStateChanged() { }
|
||||
protected virtual void OnStateChanged()
|
||||
{
|
||||
var hand = StateChanged;
|
||||
if (hand != null)
|
||||
{
|
||||
hand(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when <see cref="SourceId"/> changed.
|
||||
/// </summary>
|
||||
protected virtual void OnSourceIdChanged() { }
|
||||
protected virtual void OnSourceChanged()
|
||||
{
|
||||
var hand = SourceChanged;
|
||||
if (hand != null)
|
||||
{
|
||||
hand(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when source has been disabled (back to state 4).
|
||||
/// </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
|
||||
|
||||
#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)
|
||||
{
|
||||
@ -444,6 +552,16 @@ namespace NTwain
|
||||
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
|
||||
}
|
||||
|
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