Can I filter a message from a window on a different thread?

I am writing an application that uses TwainDotNet for scanning.

Everything works fine, but the scan renders the user interface unusable. So I decided to scan on a different thread, but I never had a successful scan. Therefore, I decided to take a closer look at the implementation:

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)));

      

And the method that does the filtering:

protected IntPtr FilterMessage(IntPtr hwnd, int msg, IntPtr wParam, 
    IntPtr lParam, ref bool handled)
{

      

Usually this method filters the message log, but if I scan another stream, I don't get it.

Scanning part of my code:

    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();

      

I don't know anything about the Win32 message architecture, so any input on how I might solve this problem or the cause of this problem would be helpful.

+3


source to share


1 answer


The code you have will not work correctly because you are creating a form in a flow with no message outline. If this library really needs a form or post outline and it hangs in the UI, and besides the fact that it has design issues, this could be one of the very rare scenarios where you might want a second thread to do a message loop.

To create a thread that starts a message loop, use Application.Run

. Your modified code might look like this.



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();

      

I must point out that having more than one UI thread can cause some strange problems, so this is generally not recommended. However, as I said, you may not have a choice. In addition, all activities occurring on these two UI threads are completely separate. You should not try to access the UI controls running on your main UI thread from this secondary UI thread. There are all kinds of unpredictable and spectacular problems that will happen. If you need to force an action on a single thread, use Invoke

or BeginInvoke

to marshal the delegate's execution.

+2


source







All Articles