2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему
 
 Win32. DispatchMessage vs SendMessage
Сообщение08.10.2017, 15:19 
Заслуженный участник
Аватара пользователя


01/08/06
3133
Уфа
Стандартный цикл обработки сообщений в Win32 выглядит примерно так (точнее, тут не весь цикл, а его тело):
Используется синтаксис Delphi
if GetMessage(msg, NULL, 0, 0)
then begin
  if not PreprocessMessage(msg) // Специфический фильтр, например, IsDialogMessage() и т.п.
  then begin
    // Каноническая обработка сообщения в Win32
    TranslateMessage(msg);
    DispatchMessage(msg);
  end;
end;

Я не очень хорошо понимаю, что делает DispatchMessage. По документации, эта функция должна посылать сообщение нужному окну и возвращать результат обработки. Примерно то же самое делает SendMessage (я рассматриваю только случай, когда msg.hwnd не нулевой). Однако на практике (на примере сообщения WM_KEYDOWN) сталкиваюсь с ситуацией, когда SendMessage, посланный нужному окну, возвращает правильный результат (для WM_KEYDOWN это 0, если окно обработало сообщение и 1, если не обработало), а DispatchMessage всегда возвращает 0. Вероятно, эта функция, видя, что окно не обработало сообщение, передаёт его какому-то "обработчику по умолчанию", который его молча "съедает". Таким образом, после вызова DispatchMessage невозможно понять, обработалось ли сообщение.

Не может ли кто-нибудь просветить меня, почему так сложилось? Нет ли какого-либо способа узнать после DispatchMessage, обработалось ли сообщение в действительности, или же оно "съелось"?
Гугл мне не помог в этом вопросе. Видимо, как-то не так формулирую запрос.
Я обхожу эту проблему тем, что для конкретного сообщения WM_KEYDOWN вместо DispatchMessage вызываю SendMessage. Есть ли более стандартный или хотя бы более изящный способ её решить?

 Профиль  
                  
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение08.10.2017, 20:18 
Заслуженный участник


20/08/14
11805
Россия, Москва
У меня какое-то смутное ощущение, что SendMessage кладёт сообщение в очередь, а DispatchMessage вызывает реальную функцию обработки сообщения. Т.е. при вызове SendMessage сообщение упадёт в очередь (не обязательно нашу же), откуда изымется GetMessage и будет обработано DispatchMessage с вызовом соответствующего обработчика. Если это происходит в рамках одного потока то функциональность может быть и (почти) идентичной (особенно если в коде реализаций этих функций стоят проверки на совпадение хэндлов).
Соответственно DispatchMessage это внутренняя функция и использовать её не нужно, всю функциональность обеспечивают SendMessage или PostMessage, включая и проверку факта обработки.
Повторю, это скорее догадки и подтвердить их не могу.

 Профиль  
                  
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение08.10.2017, 21:51 
Заслуженный участник


02/08/11
7004
worm2, а вам зачем это нужно? DispatchMessage имеет в общем-то вполне конкретное назначение, и это назначение не предусматривает использование возвращаемого значения.

 Профиль  
                  
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение09.10.2017, 07:09 


27/08/14
207
worm2 в сообщении #1254070 писал(а):
Однако на практике (на примере сообщения WM_KEYDOWN) сталкиваюсь с ситуацией, когда SendMessage, посланный нужному окну, возвращает правильный результат (для WM_KEYDOWN это 0, если окно обработало сообщение и 1, если не обработало), а DispatchMessage всегда возвращает 0
Попробуйте проверить не изменяется ли LastError, вызвав GetLastError до DispatchMessage и после.

 Профиль  
                  
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение09.10.2017, 08:53 
Заслуженный участник
Аватара пользователя


01/08/06
3133
Уфа
warlock66613 в сообщении #1254125 писал(а):
worm2, а вам зачем это нужно? DispatchMessage имеет в общем-то вполне конкретное назначение, и это назначение не предусматривает использование возвращаемого значения.
У меня есть отдельно висящее окно, и мне нужно, чтобы оно закрылось по нажатию Esc. Даже если оно не держит фокус клавиатурного ввода. Но только в том случае, если нажатие Esc не обработало другое окно, этот фокус имеющее (или ещё кто-то другой). Т.е. если нажатие Esc никто другой не обработал, тогда только моё окно должно это "бесхозное" нажатие "подобрать" и обработать. Я не придумал ничего умнее, как зайти на самый нижний уровень, в цикл обработки сообщений. Наверное, есть какой-то правильный способ, но я его не нашёл. Хуки, например, вызываются до стандартной обработки, а мне вот понадобилось после. Хотя нет, меня бы устроило и "до". Только в этом "до" я должен сначала вызвать стандартную обработку, и если она "не шмогла", тогда я бы своё вставил.

-- Пн окт 09, 2017 11:04:54 --

Progger в сообщении #1254179 писал(а):
Попробуйте проверить не изменяется ли LastError, вызвав GetLastError до DispatchMessage и после.
Иногда изменяется, иногда нет. Зависимости от обработки/необработки сообщений не выявил.

 Профиль  
                  
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение09.10.2017, 09:58 


27/08/14
207
worm2 в сообщении #1254186 писал(а):
Иногда изменяется, иногда нет. Зависимости от обработки/необработки сообщений не выявил.
Интересно... А какие коды возвращаются в GetLastError? Ещё можно SetLastError(0) сделать перед вызовом DispatchMessage.

 Профиль  
                  
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение09.10.2017, 10:51 
Заслуженный участник
Аватара пользователя


01/08/06
3133
Уфа
Обычно GetLastError возвращает то же тестовое значение, которое я выставил в SetLastError перед вызовом DispatchMessage. Но несколько раз менялся на 0 и на 87 (ERROR_INVALID_PARAMETER). Вообще говоря, обработчики сообщений могут вызывать всякие функции WinAPI, которые могут менять LastError. Например, какой-то обработчик обратился к несуществующему файлу, и вот уже у меня там двойка (ERROR_FILE_NOT_FOUND). По-видимому, у DispatchMessage нет правила непременно выставлять LastError по результатам своей работы :-(

 Профиль  
                  
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение10.10.2017, 12:44 
Заслуженный участник
Аватара пользователя


01/08/06
3133
Уфа
Спасибо всем, кто откликнулся!
И тем, кто думал над моей проблемой, но ничего не смог придумать, тоже спасибо!
В принципе, теперь более или менее понятно стало, что происходит.
Дело в том, что необработанные сообщения полагается передавать в DefWindowProc. Даже если я вызываю SendMessage, такое тоже может случиться, так что DispatchMessage тут ни при чём. Функция DefWindowProc, как выяснилось, сама "съедает" сообщение, по крайней мере, в моей ситуации (нажатие Esc в Windows 7). Она виновата! Зачем она так делает, так и не понял. Проблему смог решить только оружием массового поражения, перехватив вызов DefWindowProc через таблицу импорта из user32.dll. Наверное, я в самой постановке задачи очень сильно неправ, но вот такого от меня хотели пользователи.

 Профиль  
                  
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение16.10.2017, 15:33 


04/10/17

153
Советую пролистать книгу Аблязова "Программирование на ассемблере на платформе х86-64".

 Профиль  
                  
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение16.10.2017, 15:46 
Заслуженный участник


02/08/11
7004
as73251, можете пояснить поподробнее, как эта книга связана с обсуждаемой задачей?

 Профиль  
                  
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение16.10.2017, 18:14 


04/10/17

153
warlock66613 в сообщении #1256069 писал(а):
as73251, можете пояснить поподробнее, как эта книга связана с обсуждаемой задачей?

В ней коротко, четко и ясно написано и о DispatchMessage, и о DefWindowProc. И еще много интересного и поучительного.

 Профиль  
                  
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение16.10.2017, 18:51 
Заслуженный участник
Аватара пользователя


01/08/06
3133
Уфа
Аблязов Р.З. в упомянутой книге 2011 года издания на стр. 155 писал(а):
Немаловажной при обработке сообщения является функция DefWindowProc. Она является универсальной оконной функцией. В оконной функции можно обрабатывать только специфичные для вашей программы сообщения — в остальных случаях можно передавать управление функции DefWindowProc, именно она и придаёт окну «классическое оконное поведение».
, а на стр. 166 там же писал(а):
Назначение функции DispatchMessage на первый взгляд кажется странным — она вызывает функцию-обработчик сообщений окна, которому пришло сообщение. Почему мы не можем вызвать её сами и прибегаем к помощи «посредника»? Дело в том, что окон может быть много, у некоторых окон (кнопок, полей ввода и т.д.) чаще всего обработчиком является функция, назначенная системой. Функция DispatchMessage делает всю «грязную» работу за нас.

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

 Профиль  
                  
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение15.11.2017, 18:12 
Заслуженный участник


20/08/14
11805
Россия, Москва
Не знаю насколько это актуально, но вот сегодня наткнулся на ещё одно "объяснение" олтичий:
Цитата:
Затем у нас вызывается функция DispatchMessage (аргументом которой все так же является ссылка на нашу структуру msg), которая отправляет сообщение в процедуру окна, поскольку главное её предназначение разбирать сообщения, извлеченные функцией GetMessage.
Функция DispatchMessage в коде обработки очереди сообщений потока проверяет, для какого именно класса окна предназначено сообщение и вызывает соответствующую оконную процедуру.
Обратите внимание, что тут возникает один тонкий момент: зачем нам фактически две логики разбора очереди через GetMessage и через WindowProc, ведь можно было обойтись одной, зачем нам нужно вызывать еще отдельную процедура обработки сообщений окна, когда можно обработать сообщение в основном цикле? Так то оно так, но как мы уже упоминали, сообщения могут быть синхронными и асинхронными. Синхронные сообщения помещаются в очередь сообщений потока, соответственно извлекаются и диспетчеризируются они в основном цикле обработки сообщений: при помощи GetMessage, а затем могут быть отправлены в оконную процедуру через связку DispatchMessage+WindowProc. Асинхронные сообщения передаются непосредственно окну путем прямого вызова оконной процедуры. Это как, неужели ядро что-то напрямую вызывает в пользовательском коде? Я думаю, что тут всё несколько иначе и "прямой" передачей (асинхронных сообщений) занимается исключительно функция DispatchMessage, потому как данные сообщения не извлекаются из очереди функцией GetMessage? В любом случае, оконная процедура принимает все типы сообщений, адресованные заданному окну: синхронные и асинхронные. Именно поэтому цикл обработки сообщений у нас выглядит так а не иначе.

 Профиль  
                  
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение15.11.2017, 19:22 
Заслуженный участник


01/06/15
1149
С.-Петербург
А можно почитать про общую идеологию, ссылка на которую есть в стандартной документации к системным функциям Windows:
About Messages and Message Queues. Кроме того, следует отметить, что неправильная обработка очереди сообщений может привести к тому, что зависание пользовательского приложения подвесит всю систему (заблокирует всю очередь).

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 14 ] 

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group