Fixed stuck in Invoke.

This commit is contained in:
soukoku
2014-04-14 19:30:25 -04:00
parent 320dfb2175
commit d8512f7706
3 changed files with 200 additions and 84 deletions

98
NTwain/MessageLoop.cs Normal file
View File

@@ -0,0 +1,98 @@
using NTwain.Triplets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Interop;
using System.Windows.Threading;
namespace NTwain
{
/// <summary>
/// Provides a message loop for old TWAIN to post or new TWAIN to synchronize callbacks.
/// </summary>
class MessageLoop
{
// mostly wraps around a dispatcher?
static MessageLoop _instance = new MessageLoop();
public static MessageLoop Instance { get { return _instance; } }
Dispatcher _dispatcher;
bool _started;
HwndSource _dummyWindow;
private MessageLoop() { }
public void EnsureStarted()
{
if (!_started)
{
var loopThread = new Thread(new ThreadStart(() =>
{
_dispatcher = Dispatcher.CurrentDispatcher;
if (Dsm.IsWin)
{
// 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);
}
Dispatcher.Run();
}));
loopThread.IsBackground = true;
loopThread.SetApartmentState(ApartmentState.STA);
loopThread.Start();
_started = true;
}
}
public IntPtr LoopHandle
{
get
{
return _dummyWindow == null ? IntPtr.Zero : _dummyWindow.Handle;
}
}
public void BeginInvoke(Action action)
{
if (_dispatcher != null)
{
_dispatcher.BeginInvoke(DispatcherPriority.Normal, action);
}
}
public void Invoke(Action action)
{
if (_dispatcher != null)
{
if (_dispatcher.CheckAccess())
{
action();
}
else
{
//_dispatcher.Invoke(DispatcherPriority.Normal, action);
var man = new ManualResetEvent(false);
_dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
action();
man.Set();
}));
man.WaitOne();
man.Close();
}
}
}
public void AddHook(HwndSourceHook hook)
{
if (_dummyWindow != null) { _dummyWindow.AddHook(hook); }
}
public void RemoveHook(HwndSourceHook hook)
{
if (_dummyWindow != null) { _dummyWindow.RemoveHook(hook); }
}
}
}

View File

@@ -211,10 +211,13 @@ namespace NTwain
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public ReturnCode OpenManager() public ReturnCode OpenManager()
{
ReturnCode rc = ReturnCode.Success;
MessageLoop.Instance.Invoke(() =>
{ {
Debug.WriteLine(string.Format("Thread {0}: OpenManager.", Thread.CurrentThread.ManagedThreadId)); Debug.WriteLine(string.Format("Thread {0}: OpenManager.", Thread.CurrentThread.ManagedThreadId));
var rc = DGControl.Parent.OpenDsm(MessageLoop.Instance.LoopHandle); rc = DGControl.Parent.OpenDsm(MessageLoop.Instance.LoopHandle);
if (rc == ReturnCode.Success) if (rc == ReturnCode.Success)
{ {
// if twain2 then get memory management functions // if twain2 then get memory management functions
@@ -233,6 +236,7 @@ namespace NTwain
} }
} }
} }
});
return rc; return rc;
} }
@@ -241,10 +245,14 @@ namespace NTwain
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public ReturnCode CloseManager() public ReturnCode CloseManager()
{
ReturnCode rc = ReturnCode.Success;
MessageLoop.Instance.Invoke(() =>
{ {
Debug.WriteLine(string.Format("Thread {0}: CloseManager.", Thread.CurrentThread.ManagedThreadId)); Debug.WriteLine(string.Format("Thread {0}: CloseManager.", Thread.CurrentThread.ManagedThreadId));
var rc = DGControl.Parent.CloseDsm(MessageLoop.Instance.LoopHandle); rc = DGControl.Parent.CloseDsm(MessageLoop.Instance.LoopHandle);
});
return rc; return rc;
} }
@@ -260,15 +268,16 @@ namespace NTwain
{ {
if (string.IsNullOrEmpty(sourceProductName)) { throw new ArgumentException("Source name is required.", "sourceProductName"); } if (string.IsNullOrEmpty(sourceProductName)) { throw new ArgumentException("Source name is required.", "sourceProductName"); }
ReturnCode rc = ReturnCode.Success;
MessageLoop.Instance.Invoke(() =>
{
Debug.WriteLine(string.Format("Thread {0}: OpenSource.", Thread.CurrentThread.ManagedThreadId)); Debug.WriteLine(string.Format("Thread {0}: OpenSource.", Thread.CurrentThread.ManagedThreadId));
var source = new TWIdentity(); var source = new TWIdentity();
source.ProductName = sourceProductName; source.ProductName = sourceProductName;
var rc = DGControl.Identity.OpenDS(source); rc = DGControl.Identity.OpenDS(source);
if (rc == ReturnCode.Success) });
{
}
return rc; return rc;
} }
@@ -280,16 +289,20 @@ namespace NTwain
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public ReturnCode CloseSource() public ReturnCode CloseSource()
{
ReturnCode rc = ReturnCode.Success;
MessageLoop.Instance.Invoke(() =>
{ {
Debug.WriteLine(string.Format("Thread {0}: CloseSource.", Thread.CurrentThread.ManagedThreadId)); Debug.WriteLine(string.Format("Thread {0}: CloseSource.", Thread.CurrentThread.ManagedThreadId));
var rc = DGControl.Identity.CloseDS(); rc = DGControl.Identity.CloseDS();
if (rc == ReturnCode.Success) if (rc == ReturnCode.Success)
{ {
MessageLoop.Instance.RemoveHook(HandleWndProcMessage); MessageLoop.Instance.RemoveHook(HandleWndProcMessage);
_callbackObj = null; _callbackObj = null;
SupportedCaps = null; SupportedCaps = null;
} }
});
return rc; return rc;
} }
@@ -303,12 +316,12 @@ namespace NTwain
/// <exception cref="ArgumentNullException">context</exception> /// <exception cref="ArgumentNullException">context</exception>
public ReturnCode EnableSource(SourceEnableMode mode, bool modal, IntPtr windowHandle) public ReturnCode EnableSource(SourceEnableMode mode, bool modal, IntPtr windowHandle)
{ {
Debug.WriteLine(string.Format("Thread {0}: EnableSource.", Thread.CurrentThread.ManagedThreadId));
ReturnCode rc = ReturnCode.Success; ReturnCode rc = ReturnCode.Success;
MessageLoop.Instance.Invoke(() => MessageLoop.Instance.Invoke(() =>
{ {
Debug.WriteLine(string.Format("Thread {0}: EnableSource.", Thread.CurrentThread.ManagedThreadId));
// 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)
{ {
@@ -363,12 +376,12 @@ namespace NTwain
/// <returns></returns> /// <returns></returns>
protected ReturnCode DisableSource() protected ReturnCode DisableSource()
{ {
Debug.WriteLine(string.Format("Thread {0}: DisableSource.", Thread.CurrentThread.ManagedThreadId));
ReturnCode rc = ReturnCode.Success; ReturnCode rc = ReturnCode.Success;
MessageLoop.Instance.Invoke(() => MessageLoop.Instance.Invoke(() =>
{ {
Debug.WriteLine(string.Format("Thread {0}: DisableSource.", Thread.CurrentThread.ManagedThreadId));
rc = DGControl.UserInterface.DisableDS(_twui); rc = DGControl.UserInterface.DisableDS(_twui);
if (rc == ReturnCode.Success) if (rc == ReturnCode.Success)
{ {
@@ -386,8 +399,7 @@ namespace NTwain
public void ForceStepDown(int targetState) public void ForceStepDown(int targetState)
{ {
Debug.WriteLine(string.Format("Thread {0}: ForceStepDown.", Thread.CurrentThread.ManagedThreadId)); Debug.WriteLine(string.Format("Thread {0}: ForceStepDown.", Thread.CurrentThread.ManagedThreadId));
MessageLoop.Instance.Invoke(() =>
{
bool origFlag = EnforceState; bool origFlag = EnforceState;
EnforceState = false; EnforceState = false;
@@ -427,7 +439,6 @@ namespace NTwain
CloseManager(); CloseManager();
} }
EnforceState = origFlag; EnforceState = origFlag;
});
} }
#endregion #endregion
@@ -609,10 +620,7 @@ namespace NTwain
{ {
Debug.WriteLine(string.Format("Thread {0}: HandleWndProcMessage at state {1} with MSG={2}.", Thread.CurrentThread.ManagedThreadId, State, evt.TWMessage)); Debug.WriteLine(string.Format("Thread {0}: HandleWndProcMessage at state {1} with MSG={2}.", Thread.CurrentThread.ManagedThreadId, State, evt.TWMessage));
MessageLoop.Instance.BeginInvoke(() =>
{
HandleSourceMsg(evt.TWMessage); HandleSourceMsg(evt.TWMessage);
});
} }
} }
finally finally

View File

@@ -49,8 +49,18 @@ namespace Tester.WPF
if (!DesignerProperties.GetIsInDesignMode(this)) if (!DesignerProperties.GetIsInDesignMode(this))
{ {
Messenger.Default.Register<DialogMessage>(this, msg => Messenger.Default.Register<DialogMessage>(this, msg =>
{
if (Dispatcher.CheckAccess())
{ {
ModernMessageBox.Show(this, msg.Content, msg.Caption, msg.Button, msg.Icon, msg.DefaultResult); ModernMessageBox.Show(this, msg.Content, msg.Caption, msg.Button, msg.Icon, msg.DefaultResult);
}
else
{
Dispatcher.BeginInvoke(new Action(() =>
{
ModernMessageBox.Show(this, msg.Content, msg.Caption, msg.Button, msg.Icon, msg.DefaultResult);
}));
}
}); });
} }
} }