2014 dxdy logo

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

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




 
 Win32. DispatchMessage vs SendMessage
Сообщение08.10.2017, 15:19 
Аватара пользователя
Стандартный цикл обработки сообщений в 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 
У меня какое-то смутное ощущение, что SendMessage кладёт сообщение в очередь, а DispatchMessage вызывает реальную функцию обработки сообщения. Т.е. при вызове SendMessage сообщение упадёт в очередь (не обязательно нашу же), откуда изымется GetMessage и будет обработано DispatchMessage с вызовом соответствующего обработчика. Если это происходит в рамках одного потока то функциональность может быть и (почти) идентичной (особенно если в коде реализаций этих функций стоят проверки на совпадение хэндлов).
Соответственно DispatchMessage это внутренняя функция и использовать её не нужно, всю функциональность обеспечивают SendMessage или PostMessage, включая и проверку факта обработки.
Повторю, это скорее догадки и подтвердить их не могу.

 
 
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение08.10.2017, 21:51 
worm2, а вам зачем это нужно? DispatchMessage имеет в общем-то вполне конкретное назначение, и это назначение не предусматривает использование возвращаемого значения.

 
 
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение09.10.2017, 07:09 
worm2 в сообщении #1254070 писал(а):
Однако на практике (на примере сообщения WM_KEYDOWN) сталкиваюсь с ситуацией, когда SendMessage, посланный нужному окну, возвращает правильный результат (для WM_KEYDOWN это 0, если окно обработало сообщение и 1, если не обработало), а DispatchMessage всегда возвращает 0
Попробуйте проверить не изменяется ли LastError, вызвав GetLastError до DispatchMessage и после.

 
 
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение09.10.2017, 08:53 
Аватара пользователя
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 
worm2 в сообщении #1254186 писал(а):
Иногда изменяется, иногда нет. Зависимости от обработки/необработки сообщений не выявил.
Интересно... А какие коды возвращаются в GetLastError? Ещё можно SetLastError(0) сделать перед вызовом DispatchMessage.

 
 
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение09.10.2017, 10:51 
Аватара пользователя
Обычно 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 
Аватара пользователя
Спасибо всем, кто откликнулся!
И тем, кто думал над моей проблемой, но ничего не смог придумать, тоже спасибо!
В принципе, теперь более или менее понятно стало, что происходит.
Дело в том, что необработанные сообщения полагается передавать в DefWindowProc. Даже если я вызываю SendMessage, такое тоже может случиться, так что DispatchMessage тут ни при чём. Функция DefWindowProc, как выяснилось, сама "съедает" сообщение, по крайней мере, в моей ситуации (нажатие Esc в Windows 7). Она виновата! Зачем она так делает, так и не понял. Проблему смог решить только оружием массового поражения, перехватив вызов DefWindowProc через таблицу импорта из user32.dll. Наверное, я в самой постановке задачи очень сильно неправ, но вот такого от меня хотели пользователи.

 
 
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение16.10.2017, 15:33 
Советую пролистать книгу Аблязова "Программирование на ассемблере на платформе х86-64".

 
 
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение16.10.2017, 15:46 
as73251, можете пояснить поподробнее, как эта книга связана с обсуждаемой задачей?

 
 
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение16.10.2017, 18:14 
warlock66613 в сообщении #1256069 писал(а):
as73251, можете пояснить поподробнее, как эта книга связана с обсуждаемой задачей?

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

 
 
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение16.10.2017, 18:51 
Аватара пользователя
Аблязов Р.З. в упомянутой книге 2011 года издания на стр. 155 писал(а):
Немаловажной при обработке сообщения является функция DefWindowProc. Она является универсальной оконной функцией. В оконной функции можно обрабатывать только специфичные для вашей программы сообщения — в остальных случаях можно передавать управление функции DefWindowProc, именно она и придаёт окну «классическое оконное поведение».
, а на стр. 166 там же писал(а):
Назначение функции DispatchMessage на первый взгляд кажется странным — она вызывает функцию-обработчик сообщений окна, которому пришло сообщение. Почему мы не можем вызвать её сами и прибегаем к помощи «посредника»? Дело в том, что окон может быть много, у некоторых окон (кнопок, полей ввода и т.д.) чаще всего обработчиком является функция, назначенная системой. Функция DispatchMessage делает всю «грязную» работу за нас.

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

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

 
 
 
 Re: Win32. DispatchMessage vs SendMessage
Сообщение15.11.2017, 19:22 
А можно почитать про общую идеологию, ссылка на которую есть в стандартной документации к системным функциям Windows:
About Messages and Message Queues. Кроме того, следует отметить, что неправильная обработка очереди сообщений может привести к тому, что зависание пользовательского приложения подвесит всю систему (заблокирует всю очередь).

 
 
 [ Сообщений: 14 ] 


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group