TwainDotNet Сканирование с использованием TWAIN с BackgroundWorker - PullRequest
4 голосов
/ 13 февраля 2010

Кто-нибудь пробовал TwainDotNet для сканирования с помощью вызовов TWAIN API из .NET? Хотя это работает хорошо, обычно у меня есть некоторые проблемы с ним при использовании вместе с приложением WPF, использующим MVVM. По сути, я вызываю функции сканирования Twain из службы, которая, в свою очередь, использует 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();
}

Обработчик события ScanningComplete никогда не запускается, когда мы работаем с BackgroundWorker. Любые предложения по решению этой проблемы?

Ответы [ 2 ]

6 голосов
/ 10 декабря 2011

Тот факт, что объект Twain требует дескриптор окна в своем конструкторе объектов, предполагает, что что-то внутри объекта Twain требует обработки сообщений. Обработка сообщений между потоками сложна для начала, но тем более, когда это происходит внутри API.

Если twain API создает дескриптор окна (открыто, например, всплывающее окно или диалоговое окно, или тайно, например, для межпроцессного взаимодействия (IPC)) как часть одной из функций API, вызываемых из фонового потока этот дескриптор окна будет связан с тем потоком, в котором он был создан - фоновым потоком. Все сообщения, отправленные этому дескриптору окна, будут стоять в очереди в ожидании фонового потока для их обработки в цикле сообщений. У вас нет цикла сообщений в фоновом потоке, поэтому дескриптор окна застрянет в подвешенном состоянии. Он не будет отвечать на сообщения окна. Отправленные сообщения останутся без ответа. SendMessage () заблокируется.

Даже если это не проблема дескриптора окна / цикла сообщений, весьма вероятно, что если API Twain не был явно и преднамеренно реализован с учетом многопоточности, у него будут проблемы при использовании в потоках. Вы создаете объект twain в одном потоке, а затем используете его в другом потоке, так что это ситуация с несколькими потоками. Если бы вы могли создать объект twain в фоновом потоке и использовать объект twain только в контексте этого фонового потока, это может обойти проблемы схождения потоков в реализации API twain. Когда используются дескрипторы окон и сообщения, перемещение всего в фоновый поток также может ухудшить ситуацию.

Возможность использовать объект между потоками не предоставляется бесплатно. Если twain API не был разработан для использования в потоках, вы мало что можете сделать, чтобы он работал в потоках. Лучше всего держать объект Twain в главном потоке пользовательского интерфейса.

1 голос
/ 13 февраля 2010

Вы пытались удалить LINQ'ness из кода и поместить его в отдельную функцию, чтобы на самом деле сначала проверить это, обратите внимание, что я завернул его в блок try/catch, чтобы увидеть, есть ли какая-либо ошибка, также обратите внимание что я создал простой класс WorkerArgs для передачи данных, поскольку это не код LINQ, было бы интересно посмотреть, какие есть результаты (если есть):

public class WorkerArgs{
   public List<BitMapSource> _bitmapSources;
   public Twain _twain;
   public ScanSettings _settings;
}
List<BitmapSource> bitmapSources = new List<BitmapSource>();
Twain twain = new Twain(new WpfWindowMessageHook(_window));
ScanSettings settings = new ScanSettings() { ShowTwainUI = false };
WorkerArgs wArgs = new WorkerArgs();
wArgs._bitmapSources = bitmapSources;
wArgs._twain = twain;
wArgs._settings = settings;
using (BackgroundWorker worker = new BackgroundWorker())
{
    worker.DoWork += new DoWorkEventHandler(worker_DoWork);
    worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    worker.RunWorkerAsync((WorkerArgs)wArgs);
}

void  worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
   try{
    image1.Source = (WorkerArgs(e.Argument))._bitmapSources[0];
   }catch(Exception up){
     throw up; // :P
   }
}

void  worker_DoWork(object sender, DoWorkEventArgs e)
{
   try{
     WorkerArgs thisArgs = (WorkerArgs)e.Argument as WorkerArgs;
     if (thisArgs != null){
        AutoResetEvent waitHandle = new AutoResetEvent(false);
        EventHandler scanCompleteHandler = (se, ev) => { waitHandle.Set(); };
        thisArgs._twain.ScanningComplete += scanCompleteHandler;
        thisArgs._twain.StartScanning(settings);
        waitHandle.WaitOne();

        if (thisArgs._twain.Images.Count &gt; 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());
                thisArgs._bitmapSources.Add(bitmapSource);
            }
        }
    }
   }catch(Exception up){
     throw up; // :P
   }
}

Я не мог не заметить, только после ввода кода я заметил это:

Twain twain = new Twain(new WpfWindowMessageHook(_window))

Вы выполняете перехват или что-то подобное в фоновом режиме - возможно, существует проблема перекрестного потока, следовательно, ScanningComplete не запускается? Просто мысль, можешь ли ты уточнить в любом случае?

...