Изменение потока сообщений в окне - PullRequest
9 голосов
/ 03 декабря 2010

Недавно я попытался поместить цикл сообщений окна в его собственный поток, и я удивился, почему он никогда не получал никаких сообщений, но я узнал, что Windows отправляет сообщения в поток, создавший окно. Как создать окно в одном потоке и заставить другой поток получать сообщения этого окна? Я видел функцию PostThreadMessage, но я полагаю, что она также требует, чтобы поток, создавший окно, прослушивал сообщения, что я и стараюсь избегать, так что эта функция - не то, что мне нужно.

Кажется, это был бы обычный вопрос, и я потратил немало времени, чтобы найти ответ, но не могу его найти.

Ответы [ 5 ]

11 голосов
/ 03 декабря 2010

Как создать окно в одном нить и вызвать другую нить получать сообщения этого окна?

Простой ответ ... нет. Создайте окно в потоке, в котором вы хотите обрабатывать его сообщения. Если это невозможно, вам нужно переосмыслить свой подход.

7 голосов
/ 03 декабря 2010

Насос сообщений Windows - это просто цикл while, который отбирает сообщения из очереди, используя PeekMessage(), и вызывает функцию Windows WndProc.Это немного больше, чем это, но это базовая операция.

Таким образом, любой поток, в котором запускается цикл while, является единственным потоком, в который могут «запускать» ваши окна. Вот каккаждое приложение Windows, которое я когда-либо видел, построено.

Однако в прошлом я думал, что, приложив немало усилий, должно быть возможно создать приложение Windows с окнами в нескольких потоках.У меня нет никакого кода, чтобы показать вам, потому что прошло много времени с тех пор, как я думал об этом, но я рассмотрел два подхода:

  1. Сохранить один поток сообщений в главном потоке,Но измените код обработчика сообщений так, чтобы в while он отправлял сообщения рабочим потокам, используя QueueUserAPC на основе потока, в котором запущен конкретный HWND. Для этого потребовалась бы карта поиска, которая может быть вычислительно дорогой.

  2. Создать новый поток сообщений в рабочем потоке.Вам придется написать весь код while, но это достаточно просто, и Классическая книга Петцольда предоставит вам все необходимые инструменты для этого.

Обратите внимание, что этот подход не имеет смысла с архитектурной точки зрения для любого приложения, о котором я могу думать.Вам просто не нужны окна для запуска в нескольких потоках, если вы разумно создаете свое приложение.Обработка окон происходит в одном потоке, операции происходят в другом (или многих).Тем не менее, у меня есть интересная область исследований, и именно это привело меня на этот путь.Короче говоря, я практически уверен, что вам не нужно делать это и не следует этого делать, но, возможно, именно так вы и сделаете.

5 голосов
/ 03 декабря 2010

Это невозможно. Каждое окно принадлежит потоку, который его создал, и это право собственности не может быть передано.

Дело не в том, чтобы пересылать сообщение в другую ветку. Каждый поток имеет свою очередь сообщений. Когда вы отправляете или публикуете сообщение в окне, ОС проверяет, какому потоку принадлежит это окно, и направляет сообщение в очередь сообщений этого потока. Потоки не могут читать ни одну очередь сообщений, кроме своей собственной, поэтому поток не может обрабатывать сообщения окон другого потока.

Вы можете пересылать сообщения в другой поток, как в первой идее в ответе Джона , но в качестве обработчика сообщений общего назначения это станет более сложным, чем стоит. Многие сообщения предназначены для изменения состояния окна, но вы не можете изменить состояние, кроме как из собственного потока окна. Некоторые сообщения отправляются с целью получения значимого возвращаемого значения, но вы не можете знать, что возвращать, пока сообщение не будет обработано, поэтому вам придется заблокировать, ожидая, пока рабочий поток обработает сообщение.

Вы бы лучше идентифицировали небольшой набор сообщений, которые действительно могут быть выгружены в рабочий поток, и обрабатывали их специально. Как только вы это сделаете, у вас не будет окна, сообщения которого обрабатываются в другом потоке; у вас просто будет обычный рабочий поток, и он будет намного менее запутанным.

Если имеются сообщения , отправляемые в ваше окно, которые требуют много времени для обработки, но отправителю либо не нужно знать результат, либо вы знаете результат, прежде чем закончите обработку, тогда вы можете дать ранний ответ , позвонив по номеру ReplyMessage. Это позволяет отправляющему потоку продолжать работу, пока поток вашего окна выполняет дополнительную работу.

2 голосов
/ 03 декабря 2010

Вы можете увидеть, работает ли AttachThreadInput - он позволяет обрабатывать сообщения из других потоков.

Это на самом деле не так часто встречается в вопросе, потому что вы почти всегда обрабатываете окна'сообщение в теме, где оно было создано.Смотрите ответ Гоза;Я согласен.

Обратите внимание, что вы ничего не получите от размещения обработки сообщений в другом потоке.Не разбивайте задачи графического интерфейса на несколько потоков, разбивайте задачи обработки / фоновые задачи на потоки.

0 голосов
/ 26 апреля 2013

см. Это:

MSDN: http://msdn.microsoft.com/en-us/library/ms644946(v=vs.85).aspx

Поток, в который отправляется сообщение, должен был создать очередь сообщений, иначе вызов PostThreadMessage не удается. Используйте следующий метод для решения этой ситуации.

1.Создать объект события, затем создать поток.

2.Используйте функцию WaitForSingleObject, чтобы дождаться, когда событие будет установлено в сигнальное состояние, перед вызовом PostThreadMessage.

3.В цепочке, в которую будет отправлено сообщение, вызовите PeekMessage, как показано здесь, чтобы заставить систему создать очередь сообщений.

PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE)

4.Установите событие, чтобы указать, что поток готов к приему опубликованных сообщений.

...