我正在编写一个使用TwainDotNet进行扫描的应用程序。
一切工作正常,但扫描使用户界面无法使用。 所以我决定扫描一个不同的线程,但我从来没有得到扫描成功的事件。 所以我决定仔细看看实施情况:
public DataSourceManager(Identity applicationId, IWindowsMessageHook messageHook) { // Make a copy of the identity in case it gets modified ApplicationId = applicationId.Clone(); ScanningComplete += delegate { }; TransferImage += delegate { }; _messageHook = messageHook; _messageHook.FilterMessageCallback = FilterMessage; IntPtr windowHandle = _messageHook.WindowHandle; _eventMessage.EventPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WindowsMessage)));
而过滤的方法是:
protected IntPtr FilterMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {
通常情况下,这个方法过滤消息的日志,但如果我在不同的线程扫描,我没有收到任何。
我的代码的扫描部分是:
var scanningThread = new Thread((ThreadStart) delegate { // Previously I got the main UI form here, but that didn't work either var form = new Form(); var messageHook = new WinFormsWindowMessageHook(form.Handle); var scanner = new TwainEngine(messageHook); scanner.TransferImage += TransferImage; scanner.ScanningComplete += ScanningComplete; scanner.StartScanning(twainSettings); }); scanningThread.Start();
我对Win32消息体系结构一无所知,所以关于如何解决这个问题的任何input或导致这个问题的原因都是有帮助的。
您拥有的代码将无法正常工作,因为您正在线程上创建一个没有消息循环的窗体。 如果这个库确实需要一个表单或消息循环,并且挂起了UI,那么除了它有设计问题之外,这可能是您可能想要考虑让第二个线程运行消息循环的非常罕见的场景之一。
要创建一个运行消息循环的线程,请使用Application.Run
。 您的修改后的代码可能如下所示。
var scanningThread = new Thread((ThreadStart) delegate { var form = new Form(); form.Load += (sender, args) => { var messageHook = new WinFormsWindowMessageHook(form.Handle); var scanner = new TwainEngine(messageHook); scanner.TransferImage += TransferImage; scanner.ScanningComplete += ScanningComplete; scanner.StartScanning(twainSettings); }; Application.Run(form); }); scanningThread.Start();
我必须指出,有多个UI线程可能会导致一些奇怪的问题,所以一般不建议。 但是,正如我所说,你可能没有选择。 此外,保持这两个UI线程上发生的所有活动完全分离。 您不应该尝试从这个辅助UI线程访问在主UI线程上运行的UI控件。 有各种不可预知的和壮观的问题将会发生。 如果您需要强制在一个线程上执行操作,请使用Invoke
或BeginInvoke
来编组委托的执行。