我正在尝试创建第二个消息循环以在 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/