本文介绍了使用TWAIN和BackgroundWorker进行TwainDotNet扫描的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人尝试过 TwainDotNet 进行来自.NET的TWAIN API调用的扫描吗?尽管它通常运行良好,但在与使用MVVM的WPF应用程序一起使用时,我仍然遇到一些问题.基本上,我从服务调用Twain扫描功能,而服务又使用BackgroundWorker.

Has anyone tried TwainDotNet for scanning with TWAIN API calls from .NET? Though it works well usually I've some issues with it when used along with WPF application using MVVM. Basically I'm calling Twain scanning functions from a Service, which in turn uses a BackgroundWorker.

List<BitmapSource> bitmapSources = new List<BitmapSource>();
Twain twain = new Twain(new WpfWindowMessageHook(_window));
ScanSettings settings = new ScanSettings() { ShowTwainUI = false };
using (BackgroundWorker worker = new BackgroundWorker())
{
    worker.DoWork += (sndr, evnt) =>
    {
        AutoResetEvent waitHandle = new AutoResetEvent(false);
        EventHandler scanCompleteHandler = (se, ev) => { waitHandle.Set(); };
        twain.ScanningComplete += scanCompleteHandler;
        twain.StartScanning(settings);
        waitHandle.WaitOne();

        if (twain.Images.Count > 0)
        {
            foreach (var image in twain.Images)
            {
                BitmapSource bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(new Bitmap(image).GetHbitmap(),
                    IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
                bitmapSources.Add(bitmapSource);
            }
        }
    };
    worker.RunWorkerCompleted += (sndr, evnt) => { image1.Source = bitmapSources[0]; };
    worker.RunWorkerAsync();
}

在使用BackgroundWorker时,永远不会触发ScanningComplete事件处理程序.有解决此问题的建议吗?

ScanningComplete event handler is never fired when we are working with a BackgroundWorker. Any suggestions to resolve this issue?

推荐答案

Twain对象在其对象构造函数中需要窗口句柄这一事实表明,Twain对象内部的某些内容需要消息处理.跨线程消息处理从一开始就很棘手,但在API内发生时更是如此.

The fact that the Twain object requires a window handle in its object constructor suggests that something inside the Twain object requires message handling. Cross-thread message handling is tricky to begin with but even more so when it's happening inside an API.

如果twain API创建了一个窗口句柄(公开地,例如弹出窗口或对话框,或秘密地,例如用于进程间通信(IPC))作为您从后台线程调用的API函数之一的一部分,则该窗口句柄将绑定到在其上创建的线程-后台线程.发送到该窗口句柄的所有消息将排队,等待后台线程在消息循环中对其进行处理.您的后台线程中没有消息循环,因此窗口句柄将陷入困境.它不会响应窗口消息.发布的消息将无人应答. SendMessage()将死锁.

If the twain API creates a window handle (overtly, such as a popup window or dialog, or secretly, such as for interprocess communication (IPC)) as part of one of the API functions you're calling from the background thread, that window handle will be bound to the thread it was created on - the background thread. All messages sent to that window handle will queue up waiting for the background thread to process them in a message loop. You don't have a message loop in your background thread, so that window handle will get stuck in limbo. It won't respond to window messages. Posted messages will go unanswered. SendMessage() will deadlock.

即使这不是窗口句柄/消息循环问题,也很可能如果Twain API没有明确和故意实现多线程处理,则在跨线程使用时也会出现问题.您正在一个线程中创建twain对象,然后在另一个线程中使用它,所以这是跨线程的情况.如果您可以在后台线程中创建twain对象,并且仅在该后台线程的上下文中使用twain对象,则这可能可以解决twain API实现中的线程相似性问题.当涉及到窗口句柄和消息时,将所有内容移至后台线程很可能会使情况变得更糟.

Even if this is not a window handle / message loop problem, it is very likely that if the Twain API was not explicitly and deliberately implemented with multithreading in mind, it will have problems when used across threads. You are creating the twain object in one thread and then using it in another thread, so this is a cross-thread situation. If you could create the twain object in the background thread and only use the twain object in the context of that background thread, this might work around thread affinity issues in the twain API implementation. When window handles and messages are involved, moving everything to the background thread is just as likely to make things worse.

跨线程使用对象的能力并非免费提供.如果twain API不是为跨线程使用而设计的,那么您几乎无法做使其在跨线程中使用.最好的选择是将Twain对象保留在主UI线程中.

The ability to use an object across threads does not come for free. If the twain API was not designed for use across threads, there is little you can do to make it work across threads. Your best bet is to keep the Twain object in the main UI thread.

这篇关于使用TWAIN和BackgroundWorker进行TwainDotNet扫描的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-18 18:26