Я пытаюсь создать второй цикл сообщения для асинхронного обработки/фильтрации сообщений низкого уровня на C#. Он работает, создавая скрытую форму, выставляя свойство 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
}
Я использую его в основной форме конструктора следующим образом:
_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();
}
EDIT: Полное решение в моем ответе.
Нет, потому что это покажет вторую форму.Обратите внимание, что вторая форма просто поддельна и должна оставаться скрытой. Инициализация - это способ создания дескриптора окна, который будет получать сообщения. Меня не интересует итерация пользователя в этой форме. Как только основная форма закрыта, я ожидаю, что второй контекст приложения также будет закрыт. Может быть, цикл не уходит, потому что форма не закрыта ... Теперь я попробую. – ceztko
Хорошо, я понял, что то, что я делаю в HandleHelper, регистрирует «что-то» в цикле сообщений, поэтому попытка запуска приложения ApplicationContext.ExitThread неопределенно. Постарайтесь понять, может ли эта «сонять» быть незарегистрированной. – ceztko
Да, вам нужно будет проверить документы для этого класса «TwainSM», который вы используете. Если он реализует 'IDisposable', вы можете попытаться уничтожить его, как только процесс будет завершен (но это всего лишь идея). – Groo