Почему когда я из одного потока посылаю в др. WM_QUIT при помощи SendMessage, то GetMessage не возвращает 0, а когда использую PostMessage, то все нормально??? В чем разница? Самое интерестное, что Spy++ пишет что сообщение послано — принято. Помогите плиз.
Здравствуйте, DrMom, Вы писали:
DM>Почему когда я из одного потока посылаю в др. WM_QUIT при помощи SendMessage, то GetMessage не возвращает 0, а когда использую PostMessage, то все нормально??? В чем разница? Самое интерестное, что Spy++ пишет что сообщение послано — принято. Помогите плиз.
Это Вам только кажется, что все нормально.
MSDN, например, утверждает следующее (тема WM_QUIT):
The WM_QUIT message is not associated with a window and therefore will never be received through a window's window procedure. It is retrieved only by the GetMessage or PeekMessage functions.
Do not post the WM_QUIT message using the PostMessage function; use PostQuitMessage.
Здравствуйте, Алексей Владимирович Миронов, Вы писали:
АВМ>Это Вам только кажется, что все нормально.
АВМ>MSDN, например, утверждает следующее (тема WM_QUIT):
АВМ>
АВМ>The WM_QUIT message is not associated with a window and therefore will never be received through a window's window procedure. It is retrieved only by the GetMessage or PeekMessage functions.
АВМ>Do not post the WM_QUIT message using the PostMessage function; use PostQuitMessage.
Весьма занимательно!!! А где это написано, если точнее? Такие вещи надо в избранное добавлять.
SendMessage, PostMessage отличие этих функций в том, что send посылает сообщение и не ждет обработано оно или нет, а post ждет пока сообщение обработается
Re[4]: SendMessage vs PostMessage
От:
Аноним
Дата:
21.02.03 05:04
Оценка:
Здравствуйте, IceHand, Вы писали:
IH>SendMessage, PostMessage отличие этих функций в том, что send посылает сообщение и не ждет обработано оно или нет, а post ждет пока сообщение обработается
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, IceHand, Вы писали:
IH>>SendMessage, PostMessage отличие этих функций в том, что send посылает сообщение и не ждет обработано оно или нет, а post ждет пока сообщение обработается
А>Наоборот.
Господа, не надо заниматься пустой болтовней. Вы бы хоть посмотрели, что я спрашивал. Чем объяснять мне разницу между SM и PM, лучше ответили бы на мой вопрос. За полезный ответ готов балами отблагодарить.
DM>Господа, не надо заниматься пустой болтовней. Вы бы хоть посмотрели, что я спрашивал. Чем объяснять мне разницу между SM и PM, лучше ответили бы на мой вопрос. За полезный ответ готов балами отблагодарить.
SM напрямую вызывает каллбек твоего окна, проходит сквозь свичер —
и вылетает, так ничего и не сделав....
PM заганяет WB_QUIT в стек сообщений, откуда оно потом забираеться GetMessage
— и GetMessage возвращет 0.
В первом случае до GetMessage даже не доходит...
з.ы. А спай — прав... Оконная процедура таки получила соббщение...
Другой вопрос как...
Здравствуйте, algod, Вы писали:
DM>>Господа, не надо заниматься пустой болтовней. Вы бы хоть посмотрели, что я спрашивал. Чем объяснять мне разницу между SM и PM, лучше ответили бы на мой вопрос. За полезный ответ готов балами отблагодарить.
A>SM напрямую вызывает каллбек твоего окна, проходит сквозь свичер — A>и вылетает, так ничего и не сделав.... A>PM заганяет WB_QUIT в стек сообщений, откуда оно потом забираеться GetMessage A>- и GetMessage возвращет 0. A>В первом случае до GetMessage даже не доходит...
A>з.ы. А спай — прав... Оконная процедура таки получила соббщение... A>Другой вопрос как...
Мелкие терминологические замечания:
"каллбек твоего окна" — это наверное "оконная процедура".
"стек сообщений" — наверное всё-таки "очередь сообщеий".
Кстати вопрос:
Если делать SM из другого потока (не из потока, создавшего окно),
то прямого вызова оконной процедуры происходить не будет?
Всё будет проходить через очередь?
Вариант И GetMessage в этом случае вернёт 0?
Или GetMessage всё равно, выгребая sm-cообщение из очереди, вызовет
оконную процедуру изнутри напрямую, не возвращая управление?
SM гарантированно возвращает код "оконной процедуры". Если в этот момент оконная проца другого потока подвиснет — подвиснешь и ты.
(для справки есть еще SendMessageTimeout — тоже самое, что SM, но более расчитано на работу с многозадачностью )
Рек>Всё будет проходить через очередь? Рек>Вариант И GetMessage в этом случае вернёт 0? Рек>Или GetMessage всё равно, выгребая sm-cообщение из очереди, вызовет Рек>оконную процедуру изнутри напрямую, не возвращая управление?
Правильно ли я понял,
что SM-сообщения обрабатываются внутри GetMessage (прямым колом)
и никогда не попадают в DispatchMessagе?
В том числе и тогда когда сообщение пришло из другого потока.
Так?
Здравствуйте, Рек, Вы писали:
Рек>Правильно ли я понял, Рек>что SM-сообщения обрабатываются внутри GetMessage (прямым колом) Рек>и никогда не попадают в DispatchMessagе? Рек>В том числе и тогда когда сообщение пришло из другого потока. Рек>Так?
Извини — наверное где то неправильно выразился GetMessage — забирает следующее сообщение из очереди. И ничего более... Оно не вызывает оконную процедуру.
вот DispatchMessagе — уже вызывает оконную процедуру, исходя из параметров полученых из GetMessage, по пути обработав таймер.
SendMessage напрямую вызывает оконную процу (с синхронизацией, естественно).
Т.е., грубо говоря, содержимое DispatchMessagе можно представить как:
LRESULT
DispatchMessage
( CONST MSG *lpmsg )
{
// ***********************
// Обработка каллбека таймера, если обрабатываем сообщение WM_TIMER, если такой имееться
// ***********************
// Возможно что то еще: проверки на валидность оконного хендла, етс.
// ***********************return SendMessage
( lpmsg->hwnd,
, lpmsg->message
, lpmsg->wParam
, lpmsg->lParam );
}
Я не знаю досконально внутренний механизм этих функций, но судя по всему, оно где то рядом...
Теоретически можно поробовать реализовать стандартный оконный луп через CallWindowProc или
SendMessage — и посмотреть что получиться...
Рек>Правильно ли я понял, Рек>что SM-сообщения обрабатываются внутри GetMessage (прямым колом) Рек>и никогда не попадают в DispatchMessagе? Рек>В том числе и тогда когда сообщение пришло из другого потока. Рек>Так?
В продолжение темы: SM, CallWindowProc
— оба варианта прекрасно работают внутри
Абсолютно верный ответ:
существует флаг статуса очереди сообщений — QS_QUIT
он выставляется как раз именно PostQuitMessage, а не PostMessage
при этом WM_QUIT вообще не добавляется к очереди сообщений
когда поток вызывает GetMessage or PeekMessage система проверяет состояние очередей потока и если видит установленный флаг QS_QUIT просто возвращает WM_QUIT и сбрасывает флаг
при этом помню интересный sideeffect от такого поведения для WM_QUIT:
фрагмент
и здесь все сообщения после WM_QUIT будут обработаны ДО WM_QUIT
АВМ>
АВМ>The WM_QUIT message is not associated with a window and therefore will never be received through a window's window procedure. It is retrieved only by the GetMessage or PeekMessage functions.
АВМ>Do not post the WM_QUIT message using the PostMessage function; use PostQuitMessage.
... << RSDN@Home 1.0 beta 6 >>
Valery A. Boronin, RSDN Team, linkedin.com\in\boronin
R&D Mgmt & Security. AppSec & SDL. Data Protection and Systems Programming. FDE, DLP, Incident Management. Windows Filesystems and Drivers.
Здравствуйте, algod, Вы писали:
A>Здравствуйте, Рек, Вы писали:
Рек>>Правильно ли я понял, Рек>>что SM-сообщения обрабатываются внутри GetMessage (прямым колом) Рек>>и никогда не попадают в DispatchMessagе? Рек>>В том числе и тогда когда сообщение пришло из другого потока. Рек>>Так?
A>Извини — наверное где то неправильно выразился A>GetMessage — забирает следующее сообщение из очереди. И ничего более... Оно не вызывает оконную процедуру.
A>вот DispatchMessagе — уже вызывает оконную процедуру, исходя из параметров полученых из GetMessage, по пути обработав таймер.
A>SendMessage напрямую вызывает оконную процу (с синхронизацией, естественно). НЕВЕРНО!!! Если поток не вызывает GetMessage или PeekMessage сообщение НИКОГДА не будет обработанно!
SendMessage НЕ ВЫЗЫВАЕТ напрямую оконную процедуру — если бы это было так — то оконная процедура вызывалсь бы
в ТЕКУЩЕМ потоке — а не потоке ВЛАДЕЮЩЕМ очередью сообщений!!! В WINDOWS ВСЕ СООБЩЕНИЯ ДЛЯ ПОТОКА ОБРАБАТЫАЮТСЯ ТОЛЬКО В САМОМ ПОТОКЕ!
Так что прав — Pek.
Синхронные сообщения имеют наибольший приоритет и обрабатываются в первую очередь!
Они обрабатываются автоматически
(перенаправляются в оконную процедру) внутри вызова потоком Get(Peek)Message.
Используя Get(Peek)Message можно выбрать из очереди только асинхронное собщение.
A>Т.е., грубо говоря, содержимое DispatchMessagе можно представить как: A>
A>LRESULT
A>DispatchMessage
A> ( CONST MSG *lpmsg )
A>{
A>// ***********************
A>// Обработка каллбека таймера, если обрабатываем сообщение WM_TIMER, если такой имееться
A>// ***********************
A>// Возможно что то еще: проверки на валидность оконного хендла, етс.
A>// ***********************
A> return SendMessage
A> ( lpmsg->hwnd,
A> , lpmsg->message
A> , lpmsg->wParam
A> , lpmsg->lParam );
A>}
A>
A>Грубая реализация SendMessage:
A>
A>LRESULT SendMessage
A> ( HWND hWnd
A> , UINT Msg
A> , WPARAM wParam
A> , LPARAM lParam)
A>{
A>// ***********************
A>// Что то тут есть: проверка на валидность оконного хендла, синхранизация многопоточности етс.
A>// ***********************
A> return CallWindowProc
A> ( (WNDPROC) GetWindowLong (lpmsg->hwnd, GWL_WNDPROC)
A> , lpmsg->message
A> , lpmsg->wParam
A> , lpmsg->lParam );
A>}
A>
A>Я не знаю досконально внутренний механизм этих функций, но судя по всему, оно где то рядом... A>Теоретически можно поробовать реализовать стандартный оконный луп через CallWindowProc или A>SendMessage — и посмотреть что получиться...
A>з.ы. кстати — сейчас попробую, и напишу
Все не так
ПСЕВДОКОД Windows :
KL> НЕВЕРНО!!! Если поток не вызывает GetMessage или PeekMessage сообщение НИКОГДА не будет обработанно! KL>SendMessage НЕ ВЫЗЫВАЕТ напрямую оконную процедуру — если бы это было так — то оконная процедура вызывалсь бы KL>в ТЕКУЩЕМ потоке — а не потоке ВЛАДЕЮЩЕМ очередью сообщений!!! KL>В WINDOWS ВСЕ СООБЩЕНИЯ ДЛЯ ПОТОКА ОБРАБАТЫАЮТСЯ ТОЛЬКО В САМОМ ПОТОКЕ! KL>Так что прав — Pek.
Забыл уточнить — SendMessage может вызвать оконную процедуру напрямую ТОЛЬОКО если
она вызывается в родном для окна потоке. Иначе см. выше.
И соотв. слегка изм. псевдокод:
Здравствуйте, Kirill_Luzanov, Вы писали:
KL>Здравствуйте, Kirill_Luzanov, Вы писали:
KL>Забыл уточнить — SendMessage может вызвать оконную процедуру напрямую ТОЛЬОКО если KL>она вызывается в родном для окна потоке. Иначе см. выше. KL>И соотв. слегка изм. псевдокод: KL>
Ладно... Частично сглючил... Как раз из за того, что ты описал в последнем посте .
Ведь все таки PostMessage выгребаеться из очереди . Хотя он для того и создан
Здравствуйте, algod, Вы писали:
A>Здравствуйте, Kirill_Luzanov, Вы писали:
KL>>Здравствуйте, Kirill_Luzanov, Вы писали:
KL>>Забыл уточнить — SendMessage может вызвать оконную процедуру напрямую ТОЛЬОКО если KL>>она вызывается в родном для окна потоке. Иначе см. выше. KL>>И соотв. слегка изм. псевдокод: KL>>
A> Ладно... Частично сглючил... Как раз из за того, что ты описал в последнем посте . A>Ведь все таки PostMessage выгребаеться из очереди . Хотя он для того и создан Со всеми бывает...
Чтобы до конца расставить все точки над "и" резюмирую:
Если вызывающий SendMessage поток явл. РОДНЫМ для окна — сообщение в очередь сообщений
потока НЕ помещается — а НАПРЯМУЮ передается соотв. оконной процедуре.
Если вызвывающий SendMessage поток НЕ ЯВЛ. РОДНЫМ для окна — SendMessage НЕ ВЫЗЫВАЕТ
напрямую оконную процедуру (- если бы это было так — то оконная процедура вызывалсь бы
в ТЕКУЩЕМ потоке — а не потоке ВЛАДЕЮЩЕМ очередью сообщений) — а помещает его в очередь
и ждет обработки сообщения соотв.ф-циями (GetMessage и т.п.) РОДНОГО для окна потока!!! В WINDOWS ВСЕ СООБЩЕНИЯ ДЛЯ ПОТОКА ОБРАБАТЫАЮТСЯ ТОЛЬКО В САМОМ ПОТОКЕ!
Обработка очереди сообщений:
Если поток не вызывает GetMessage или PeekMessage — то сообщения из ДРУГИХ
потоков НИКОГДА не будут обработанны!
Синхронные сообщения (из других потоков (см. выше)) имеют наибольший приоритет
и обрабатываются в первую очередь! Они обрабатываются автоматически
(перенаправляются в оконную процедру) внутри
вызова потоком Get(Peek)Message.
Используя Get(Peek)Message можно выбрать из очереди только асинхронное собщение.
Здравствуйте, Kirill_Luzanov, Вы писали:
KL>Если поток не вызывает GetMessage или PeekMessage — то сообщения из ДРУГИХ KL>потоков НИКОГДА не будут обработанны!
Маленькое дополнение.
::SendMessage(hwndОкнаИзДругойНити) не вернется, до тех пор, пока оконная процедура
жтого окна не отработает. Тем не менее, эта оконная процедура может в свою очередь
сделать ::SendMessage(hwndОкнаИзНитиСделавшейSendMessage), и это сообщение тоже
будет обработано.
Дело в том, что если ::SendMessage() должна сидеть и ждать, пока отработает
другая нить, то она обрабатывает вызовы ::SendMessage() из других нитей
для "своих" окон. ::PostMessage() для "своих" окон не будут обработаны до
::Get/PeekMessage().
И еще интересный момент.
Если было послано сообщение из лругой нити, то ::MsgWaitForMutliObjs() вернет
WAITOBJECT_0 + nObjects, как если бы в очереди завелось сообщение,
и следующий вызов ::GetMessage() "дернет" напрямую оконную процедуру, но не вернется, так как ему нечего возвращать.
Довольно популярная ошибка, даже WTL-ный мастер вставляет ее в проекты
MultiThreadedSDI.
[]
БП>И еще интересный момент. БП>Если было послано сообщение из лругой нити, то ::MsgWaitForMutliObjs() вернет БП>WAITOBJECT_0 + nObjects, как если бы в очереди завелось сообщение, БП>и следующий вызов ::GetMessage() "дернет" напрямую оконную процедуру, БП>но не вернется, так как ему нечего возвращать.
БП>Довольно популярная ошибка, даже WTL-ный мастер вставляет ее в проекты БП>MultiThreadedSDI.
Вот те здрасте! GetMessage вызывает напрямую оконную процедуру? Это ты где такое вычитал? Хе-хе.
GetMessage только и делает, что дожидается сообщения в очереди и заполняет структуру MSG. Все! Ничего она не вызывает!
А в WTL какой-то другой глюк.
Здравствуйте, Alexey Shirshov, Вы писали:
AS>Здравствуйте, Блудов Павел, Вы писали:
AS>Вот те здрасте! GetMessage вызывает напрямую оконную процедуру? Это ты где такое вычитал? Хе-хе. AS>GetMessage только и делает, что дожидается сообщения в очереди и заполняет структуру MSG. Все! Ничего она не вызывает! AS>А в WTL какой-то другой глюк.
А ты проверь, как я . Я тоже сначала не поверил. Простейший эксперимент:
В одном процессе открой окно, напиши в свичере оконной процы
case WM_USER + 0x100: MessageBepp (0); break;
а потом зациклись в пустоте
for ( ; ; );
Во втором процессе найди это окно (по капшану, хотя бы) — и пульни в него WM_USER + 0x100...
Оно никогда не дойдет . И окно твое "висеть" будет. В прямом смысле слова.
А вот если ты напишешь хотя бы так:
while (Get(Peek)Message (...));
То твоя мессага приходить будет... И даже бекграунд окна будет перерисовываться (короче все, что присылали из других процессов по SendMessage)
GetMessage — выгребает с возвращением только PostMessage. Kirill и Павел правы.