Можно ли отфильтровать сообщение из окна в другом потоке? - PullRequest
3 голосов
/ 22 марта 2012

Я пишу приложение, которое использует 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, поэтому любая информация о том, как я могу решить эту проблему или о причинах этой проблемы, будет полезной.

1 Ответ

2 голосов
/ 22 марта 2012

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

Чтобы создать поток, запускающий цикл сообщений, используйте 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();

Я должен указать, что наличие более одного потока пользовательского интерфейса может вызвать некоторые странные проблемы, поэтому обычно это не рекомендуется.Однако, как я уже сказал, у вас может не быть выбора.Кроме того, вся деятельность, происходящая в этих двух потоках пользовательского интерфейса, должна быть полностью отдельной.Вы не должны пытаться получить доступ к элементам управления пользовательского интерфейса, работающим в основном потоке пользовательского интерфейса, из этого вторичного потока пользовательского интерфейса.Есть все виды непредсказуемых и захватывающих проблем, которые возникнут.Если вам нужно принудительно выполнить действие в одном потоке, используйте Invoke или BeginInvoke, чтобы упорядочить выполнение делегата.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...