mirror of
https://github.com/soukoku/ntwain.git
synced 2025-10-25 02:49:04 +08:00
Internal loop and readme update.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
using NTwain.Triplets;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Threading;
|
||||
@@ -18,11 +19,10 @@ namespace NTwain
|
||||
|
||||
Dispatcher _dispatcher;
|
||||
bool _started;
|
||||
HwndSource _dummyWindow;
|
||||
|
||||
WindowsHook _hook;
|
||||
private MessageLoop() { }
|
||||
|
||||
public void EnsureStarted()
|
||||
public void EnsureStarted(WindowsHook.WndProcHook hook)
|
||||
{
|
||||
if (!_started)
|
||||
{
|
||||
@@ -33,12 +33,9 @@ namespace NTwain
|
||||
{
|
||||
Debug.WriteLine("NTwain message loop started.");
|
||||
_dispatcher = Dispatcher.CurrentDispatcher;
|
||||
if (Dsm.IsWin)
|
||||
if (!Dsm.IsOnMono)
|
||||
{
|
||||
// start a windows msg loop for old twain to post msgs
|
||||
// the style values are purely guesses here with
|
||||
// CS_NOCLOSE, WS_DISABLED, and WS_EX_NOACTIVATE
|
||||
_dummyWindow = new HwndSource(0x0200, 0x8000000, 0x8000000, 0, 0, "NTWAIN_LOOPER", IntPtr.Zero);
|
||||
_hook = new WindowsHook(hook);
|
||||
}
|
||||
hack.Set();
|
||||
Dispatcher.Run();
|
||||
@@ -57,7 +54,7 @@ namespace NTwain
|
||||
{
|
||||
get
|
||||
{
|
||||
return _dummyWindow == null ? IntPtr.Zero : _dummyWindow.Handle;
|
||||
return _hook == null ? IntPtr.Zero : _hook.Handle;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +76,6 @@ namespace NTwain
|
||||
else
|
||||
{
|
||||
//_dispatcher.Invoke(DispatcherPriority.Normal, action);
|
||||
// why use this instead of the single line above? for possible future use in mono!
|
||||
var man = new ManualResetEvent(false);
|
||||
_dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
|
||||
{
|
||||
@@ -96,14 +92,67 @@ namespace NTwain
|
||||
man.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddHook(HwndSourceHook hook)
|
||||
/// <summary>
|
||||
/// Abstracts out wnd proc hook on Windows from MessageLoop class.
|
||||
/// This allows things to not depend on PresentationCore.dll at runtime on mono.
|
||||
/// Not that everything works yet in mono but it's something.
|
||||
/// </summary>
|
||||
class WindowsHook
|
||||
{
|
||||
public WindowsHook(WndProcHook hook)
|
||||
{
|
||||
if (_dummyWindow != null) { _dummyWindow.AddHook(hook); }
|
||||
// hook into windows msg loop for old twain to post msgs.
|
||||
// the style values are purely guesses here with
|
||||
// CS_NOCLOSE, WS_DISABLED, and WS_EX_NOACTIVATE
|
||||
var win = new HwndSource(0x0200, 0x8000000, 0x8000000, 0, 0, "NTWAIN_LOOPER", IntPtr.Zero);
|
||||
Handle = win.Handle;
|
||||
_hook = hook;
|
||||
win.AddHook(WndProc);
|
||||
}
|
||||
public void RemoveHook(HwndSourceHook hook)
|
||||
|
||||
public delegate void WndProcHook(ref MESSAGE winMsg, ref bool handled);
|
||||
|
||||
WndProcHook _hook;
|
||||
|
||||
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
|
||||
{
|
||||
if (_dummyWindow != null) { _dummyWindow.RemoveHook(hook); }
|
||||
if (_hook != null)
|
||||
{
|
||||
var winmsg = new MESSAGE(hwnd, msg, wParam, lParam);
|
||||
_hook(ref winmsg, ref handled);
|
||||
}
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
public IntPtr Handle { get; private set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The MSG structure in Windows for TWAIN use.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct MESSAGE
|
||||
{
|
||||
public MESSAGE(IntPtr hwnd, int message, IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
_hwnd = hwnd;
|
||||
_message = (uint)message;
|
||||
_wParam = wParam;
|
||||
_lParam = lParam;
|
||||
_time = 0;
|
||||
_x = 0;
|
||||
_y = 0;
|
||||
}
|
||||
|
||||
IntPtr _hwnd;
|
||||
uint _message;
|
||||
IntPtr _wParam;
|
||||
IntPtr _lParam;
|
||||
uint _time;
|
||||
int _x;
|
||||
int _y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ namespace NTwain.Triplets
|
||||
File.Exists(path);
|
||||
#endif
|
||||
}
|
||||
internal static readonly bool IsOnMono = Type.GetType("Mono.Runtime") != null;
|
||||
|
||||
internal static readonly bool IsWin = Environment.OSVersion.Platform == PlatformID.Win32NT;
|
||||
static readonly bool IsLinux = Environment.OSVersion.Platform == PlatformID.Unix;
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace NTwain
|
||||
((ITwainStateInternal)this).ChangeState(1, false);
|
||||
EnforceState = true;
|
||||
|
||||
MessageLoop.Instance.EnsureStarted();
|
||||
MessageLoop.Instance.EnsureStarted(HandleWndProcMessage);
|
||||
}
|
||||
|
||||
TWIdentity _appId;
|
||||
@@ -369,12 +369,6 @@ namespace NTwain
|
||||
}
|
||||
}
|
||||
|
||||
if (_callbackObj == null)
|
||||
{
|
||||
// must use msg loop if callback is not available
|
||||
MessageLoop.Instance.AddHook(HandleWndProcMessage);
|
||||
}
|
||||
|
||||
_twui = new TWUserInterface();
|
||||
_twui.ShowUI = mode == SourceEnableMode.ShowUI;
|
||||
_twui.ModalUI = modal;
|
||||
@@ -407,14 +401,7 @@ namespace NTwain
|
||||
rc = DGControl.UserInterface.DisableDS(_twui);
|
||||
if (rc == ReturnCode.Success)
|
||||
{
|
||||
if (_callbackObj == null)
|
||||
{
|
||||
MessageLoop.Instance.RemoveHook(HandleWndProcMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
_callbackObj = null;
|
||||
}
|
||||
_callbackObj = null;
|
||||
SafeAsyncSyncableRaiseOnEvent(OnSourceDisabled, SourceDisabled);
|
||||
}
|
||||
});
|
||||
@@ -616,19 +603,18 @@ namespace NTwain
|
||||
#region TWAIN logic during xfer work
|
||||
|
||||
//[EnvironmentPermissionAttribute(SecurityAction.LinkDemand)]
|
||||
IntPtr HandleWndProcMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
|
||||
void HandleWndProcMessage(ref NTwain.WindowsHook.MESSAGE winMsg, ref bool handled)
|
||||
{
|
||||
// this handles the message from a typical WndProc message loop and check if it's from the TWAIN source.
|
||||
if (State >= 5)
|
||||
{
|
||||
// transform it into a pointer for twain
|
||||
var winmsg = new MESSAGE(hwnd, msg, wParam, lParam);
|
||||
IntPtr msgPtr = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
// no need to do another lock call when using marshal alloc
|
||||
msgPtr = Marshal.AllocHGlobal(Marshal.SizeOf(winmsg));
|
||||
Marshal.StructureToPtr(winmsg, msgPtr, false);
|
||||
msgPtr = Marshal.AllocHGlobal(Marshal.SizeOf(winMsg));
|
||||
Marshal.StructureToPtr(winMsg, msgPtr, false);
|
||||
|
||||
var evt = new TWEvent();
|
||||
evt.pEvent = msgPtr;
|
||||
@@ -644,8 +630,6 @@ namespace NTwain
|
||||
if (msgPtr != IntPtr.Zero) { Marshal.FreeHGlobal(msgPtr); }
|
||||
}
|
||||
}
|
||||
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
ReturnCode HandleCallback(TWIdentity origin, TWIdentity destination, DataGroups dg, DataArgumentType dat, Message msg, IntPtr data)
|
||||
@@ -1223,31 +1207,5 @@ namespace NTwain
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The MSG structure in Windows for TWAIN use.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct MESSAGE
|
||||
{
|
||||
public MESSAGE(IntPtr hwnd, int message, IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
_hwnd = hwnd;
|
||||
_message = (uint)message;
|
||||
_wParam = wParam;
|
||||
_lParam = lParam;
|
||||
_time = 0;
|
||||
_x = 0;
|
||||
_y = 0;
|
||||
}
|
||||
|
||||
IntPtr _hwnd;
|
||||
uint _message;
|
||||
IntPtr _wParam;
|
||||
IntPtr _lParam;
|
||||
uint _time;
|
||||
int _x;
|
||||
int _y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,3 +32,15 @@ example for handling DIB image in native transfer using the CommonWin32 lib.
|
||||
Because it hosts its own message thread, the event callbacks will likely be from another thread.
|
||||
If you would like things marshalled to a "UI" thread then set the SynchronizationContext property
|
||||
to the one from the UI thread. This part is highly experimental.
|
||||
|
||||
64-bit OS
|
||||
--------------------------------------
|
||||
If the application process is running in 64-bit then you will need to make sure you have the
|
||||
newer data source manager (twaindsm.dll) installed.
|
||||
[DSM from TWAIN.org](http://sourceforge.net/projects/twain-dsm/files/TWAIN%20DSM%202%20Win/)
|
||||
|
||||
Otherwise just compile and run the app as x86 and it'll use the 32-bit version (twain_32.dll) that comes with Windows.
|
||||
|
||||
If you really want to test 64-bit drivers for whatever reason, you most likely will have to use
|
||||
the test one from TWAIN.org since there are no known 64-bit TWAIN DS drivers at the time of writing.
|
||||
[Sample DS from TWAIN.org](http://sourceforge.net/projects/twain-samples/files/TWAIN%202%20Sample%20Data%20Source/TWAIN%20DS%202.1.3/)
|
||||
@@ -38,47 +38,57 @@ namespace Tester
|
||||
|
||||
static void DoTwainWork()
|
||||
{
|
||||
Console.WriteLine("Getting ready to do twain stuff on thread {0}", Thread.CurrentThread.ManagedThreadId);
|
||||
Console.WriteLine("Getting ready to do twain stuff on thread {0}.", Thread.CurrentThread.ManagedThreadId);
|
||||
Thread.Sleep(1000);
|
||||
|
||||
var rc = twain.OpenManager();
|
||||
|
||||
if (rc == ReturnCode.Success)
|
||||
{
|
||||
rc = twain.OpenSource("TWAIN2 FreeImage Software Scanner");
|
||||
|
||||
if (rc == ReturnCode.Success)
|
||||
var hit = twain.GetSources().Where(s => string.Equals(s.ProductName, "TWAIN2 FreeImage Software Scanner")).FirstOrDefault();
|
||||
if (hit == null)
|
||||
{
|
||||
rc = twain.EnableSource(SourceEnableMode.NoUI, false, IntPtr.Zero);
|
||||
Console.WriteLine("The sample source \"TWAIN2 FreeImage Software Scanner\" is not installed.");
|
||||
twain.CloseManager();
|
||||
}
|
||||
else
|
||||
{
|
||||
twain.CloseManager();
|
||||
rc = twain.OpenSource(hit.ProductName);
|
||||
|
||||
if (rc == ReturnCode.Success)
|
||||
{
|
||||
Console.WriteLine("Start capture from the sample source.");
|
||||
rc = twain.EnableSource(SourceEnableMode.NoUI, false, IntPtr.Zero);
|
||||
}
|
||||
else
|
||||
{
|
||||
twain.CloseManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void twain_SourceDisabled(object sender, EventArgs e)
|
||||
{
|
||||
Console.WriteLine("Source disabled on thread {0}", Thread.CurrentThread.ManagedThreadId);
|
||||
Console.WriteLine("Source disabled on thread {0}.", Thread.CurrentThread.ManagedThreadId);
|
||||
var rc = twain.CloseSource();
|
||||
rc = twain.CloseManager();
|
||||
}
|
||||
|
||||
static void twain_TransferReady(object sender, TransferReadyEventArgs e)
|
||||
{
|
||||
Console.WriteLine("Got xfer ready on thread {0}", Thread.CurrentThread.ManagedThreadId);
|
||||
Console.WriteLine("Got xfer ready on thread {0}.", Thread.CurrentThread.ManagedThreadId);
|
||||
}
|
||||
|
||||
static void twain_DataTransferred(object sender, DataTransferredEventArgs e)
|
||||
{
|
||||
if (e.NativeData != IntPtr.Zero)
|
||||
{
|
||||
Console.WriteLine("Got twain data on thread {0}", Thread.CurrentThread.ManagedThreadId);
|
||||
Console.WriteLine("Got twain data on thread {0}.", Thread.CurrentThread.ManagedThreadId);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("No twain data on thread {0}", Thread.CurrentThread.ManagedThreadId);
|
||||
Console.WriteLine("No twain data on thread {0}.", Thread.CurrentThread.ManagedThreadId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user