我可以从不同线程中的窗口过滤消息吗?

时间:2012-03-21 20:31:11

标签: c# windows multithreading messages

我正在编写一个使用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 个答案:

答案 0 :(得分:2)

您拥有的代码将无法正常工作,因为您在没有消息循环的线程上创建表单。如果这个库确实需要一个表单或消息循环并且它挂起了UI,那么除了它有设计问题之外,这可能是非常罕见的情况之一,你可能想要考虑让第二个线程运行一个消息循环。 / p>

要创建运行消息循环的线程,请使用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();

我必须指出,拥有多个UI线程可能会导致一些奇怪的问题,因此通常不建议这样做。但是,就像我说的那样,你可能没有选择。此外,将这两个UI线程上发生的所有活动完全分开。您不应尝试从此辅助UI线程访问在主UI线程上运行的UI控件。会发生各种不可预测和引人注目的问题。如果您需要强制在一个线程上执行操作,请使用InvokeBeginInvoke来编组代理的执行。