c# – 使用TWAIN和BackgroundWorker进行TwainDotNet扫描
作者:互联网
有没有人尝试过TwainDotNet扫描来自.NET的TWAIN API调用?虽然它运行良好,但是当与使用MVVM的WPF应用程序一起使用时,我遇到了一些问题.基本上我是从服务调用Twain扫描功能,而Service又使用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事件处理程序.有什么建议来解决这个问题吗?
解决方法:
事实上,Twain对象在其对象构造函数中需要一个窗口句柄,这表明Twain对象内部的某些内容需要处理消息.开始时跨线程消息处理很棘手,但是当它在API内部发生时更是如此.
如果twain API创建一个窗口句柄(公开地,例如弹出窗口或对话框,或秘密地,例如进程间通信(IPC))作为您从后台线程调用的API函数的一部分,那个窗口handle将绑定到它创建的线程 – 后台线程.发送到该窗口句柄的所有消息将排队等待后台线程在消息循环中处理它们.您的后台线程中没有消息循环,因此窗口句柄将陷入困境.它不会响应窗口消息.发布的消息将无法回复. SendMessage()将死锁.
即使这不是一个窗口句柄/消息循环问题,很可能如果Twain API没有在考虑多线程的情况下显式和故意实现,那么在跨线程使用时会出现问题.您正在一个线程中创建twain对象,然后在另一个线程中使用它,因此这是一个跨线程的情况.如果您可以在后台线程中创建twain对象并且仅在该后台线程的上下文中使用twain对象,则这可能会解决twain API实现中的线程关联性问题.当涉及窗口句柄和消息时,将所有内容移动到后台线程可能会使事情变得更糟.
跨线程使用对象的能力不是免费的.如果twain API不是为跨线程使用而设计的,那么你几乎无法使它跨线程工作.最好的办法是将Twain对象保留在主UI线程中.
标签:c,net,backgroundworker,twain 来源: https://codeday.me/bug/20190527/1159513.html