c# - 如何以编程方式退出第二个消息循环?

标签 c# hidden window-handles message-pump message-loop

我正在尝试创建第二个消息循环以在 C# 中异步处理/过滤低级消息。它的工作原理是创建一个隐藏窗体,公开要 Hook 的 Handle 属性,并在单独的线程中运行第二个消息循环。目前我对结果很满意,但我无法正确退出第二个循环。唯一的解决方法是将 IsBackground 属性设置为 true,这样第二个线程将在主应用程序退出时简单地终止(不处理所有未决消息)。

问题是:如何正确退出该消息循环以便第二个 Application.Run() 返回?我尝试了不同的方法来创建单独的 ApplicationContext 并控制各种事件(Application.ApplicationExit、Application.ThreadExit、ApplicationContext.ThreadExit),但它们都因我无法调试的竞争条件而失败。

有什么提示吗?谢谢

这是代码:

public class MessagePump
{
    public delegate void HandleHelper(IntPtr handle);

    public MessagePump(HandleHelper handleHelper, Filter filter)
    {
        Thread thread = new Thread(delegate()
        {
            ApplicationContext applicationContext = new ApplicationContext();
            Form form = new Form();
            handleHelper(form.Handle);
            Application.AddMessageFilter(new MessageFilter(filter));
            Application.Run(applicationContext);
        });
        thread.SetApartmentState(ApartmentState.STA);
        thread.IsBackground = true; // <-- The workaround
        thread.Start();
    }
}

public delegate bool Filter(ref Message m);

internal class MessageFilter : IMessageFilter
{
    private Filter _Filter;

    public MessageFilter(Filter filter)
    {
        _Filter = filter;
    }

    #region IMessageFilter Members

    public bool PreFilterMessage(ref Message m)
    {
        return _Filter(ref m);
    }

    #endregion // IMessageFilter Members
}

我以这种方式在主 Form 构造函数中使用它:

_Completion = new ManualResetEvent(false);

MessagePump pump = new MessagePump(
delegate(IntPtr handle)
{
    // Sample code, I did this form twain drivers low level wrapping
    _Scanner = new TwainSM(handle);
    _Scanner.LoadDs("EPSON Perfection V30/V300");
},
delegate(ref Message m)
{
    // Asyncrhronous processing of the messages
    // When the correct message is found -->
    _Completion.Set();
}

编辑:我回答中的完整解决方案。

最佳答案

您应该将 Form 实例作为参数传递给 ApplicationContext 构造函数:

applicationContext = new ApplicationContext(form); 

现在,您基本上是在创建一个无上下文实例,它不关心您的表单是否被关闭。

此外,进行一些清理工作是一个很好的做法,例如在您不再需要过滤器时将其移除:

Form form = new Form();
ApplicationContext applicationContext = new ApplicationContext(form);
handleHelper(form.Handle);

MessageFilter filter = new MessageFilter(filter);
Application.AddMessageFilter(filter);
Application.Run(applicationContext);
Application.RemoveMessageFilter(filter);

[编辑]

如果您不想显示表单,那么您可以使用无参数构造器,但您必须通过调用 ApplicationContext.ExitThread 手动关闭上下文。方法。如果您在构造函数中传递表单,则当您的表单触发 FormClosed 事件时,实际上会调用此方法。

由于隐藏表单与上下文无关,所以你需要在某个时候将它们都退出。

关于c# - 如何以编程方式退出第二个消息循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4815699/

相关文章:

ios - 为什么我不能在 tableview、iOS、objective c 中的 didSelectRowAtIndexPath 中隐藏/显示标签

.net - 从 .NET 应用程序抓取和移动应用程序窗口?

java - 如何处理在新选项卡中自动打开的新窗口?

c# - 基本类型的默认值为 "value"

c# - 你如何使用出生日期计算 C# 中的年龄(考虑闰年)

windows - 使用批处理脚本查找和删除驱动器上每个文件夹中的 desktop.ini 文件

python - 如何在新选项卡中打开网站内的每个产品,以便通过 Python 使用 Selenium 进行抓取

c# - 从 C# 调用任何 Java 方法

c# - 在c#中执行SQL查询时出错,手动输入时没有错误