SendMessage, PostMessage отличие этих функций в том, что send посылает сообщение и не ждет обработано оно или нет, а post ждет пока сообщение обработается
Абсолютно верный ответ:
существует флаг статуса очереди сообщений — 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.
Здравствуйте, 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.
Здравствуйте, Alexey Shirshov, Вы писали:
AS>После непродолжительной отладки выяснил, что GetMessage вызывает оконную процедуру с помощью некой функции, адрес которой (Prof SP3) 0x77E174C8
А если скачать pdb-шник для USER32? Там имя этой функции наверняка есть.
AS>Однако на счет того, что GetMessage не вызывает оконную процедуру я погорячился. Признаю свою ошибку.
Вот и молодец. Кстати, вот полный список тех, кто это делает:
Обратите внимание, что ::MsgWaitForMultipleObjects() в этом списке нет,
она не обрабатывает синхронные сообщения, но она вернет WAIT_OBJECT_0 + nCount
исли будет получено синхронные сообщение из другой нити. Так что если в ответ на
WAIT_OBJECT_0 + nCount тупо вызывать ::GetMessage(), то ::GetMessage()
обработает синхронный вызов. И будет ждать, пока кто-то еще не
отправит-таки сообщение через ::PostMessage(). Возможно, что вечно.
Именно так и происходит в годе, создаваемом мастером WTL для MultiThreadSDI.
Что я и пытался сказать в прошлом письме.
Почему когда я из одного потока посылаю в др. 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 ом пользоваться не умею?!
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
— оба варианта прекрасно работают внутри
Здравствуйте, 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 и Павел правы.
Неа.
A>Я тоже сначала не поверил. Простейший эксперимент: A>В одном процессе открой окно, напиши в свичере оконной процы A>
A>case WM_USER + 0x100: MessageBepp (0); break;
A>
A>а потом зациклись в пустоте A>
A>for ( ; ; );
A>
A>Во втором процессе найди это окно (по капшану, хотя бы) — и пульни в него WM_USER + 0x100... A>Оно никогда не дойдет . И окно твое "висеть" будет. В прямом смысле слова.
Конечно, а что ты хотел?
A>А вот если ты напишешь хотя бы так: A>
A>while (Get(Peek)Message (...));
A>
A>То твоя мессага приходить будет... И даже бекграунд окна будет перерисовываться (короче все, что присылали из других процессов по SendMessage)
Она не придет! Ты запусти окно и попробуй его закрыть — сообщение WM_CLOSE будет послано, но оно не дойдет до оконной процедуры. Почему перерисовывается фон? Потому что сообщения типа WM_ERASEBKGND, WM_NCPAINT и проч. не ставяться в очередь. Они через GetMessage никогда не проходят. Зачем? Подсистема GDI, прекрасно зная адрес оконной процедуры может напрямую ее вызывать. Зачем ей тратить время на помещение сообщения в очередь? Можно спокойно заменить
while (Get(Peek)Message (...));
на
Sleep(INFINITE);
Все эти сообщения прекрасно дойдут, так что дело не в GetMessage.
A>GetMessage — выгребает с возвращением только PostMessage. Kirill и Павел правы.
Тут я вообще не понял. У GetMessage чель одна — заполнить структуру MSG и удалить сообщение из очереди. Все!
Здравствуйте, Alexey Shirshov, Вы писали:
A>>Во втором процессе найди это окно (по капшану, хотя бы) — и пульни в него WM_USER + 0x100... A>>Оно никогда не дойдет . И окно твое "висеть" будет. В прямом смысле слова. AS>Конечно, а что ты хотел?
Именно этого и хотел. И сообщение (WM_USER + 0x100) посланное из другого процесса никогда не дойдет. И другой процесс, который его послал тоже подвсиснет. A>>А вот если ты напишешь хотя бы так: A>>
A>>while (Get(Peek)Message (...));
A>>
AS>Она не придет! Ты запусти окно и попробуй его закрыть — сообщение WM_CLOSE будет послано, но оно не дойдет до оконной процедуры. Почему перерисовывается фон? Потому что сообщения типа WM_ERASEBKGND, WM_NCPAINT и проч. не ставяться в очередь. Они через GetMessage никогда не проходят. Круто. MSDN читал? WM_ERASEBKGND — не прямое сообщение... Оно вызваеться по BeginPaint... Которое в свою очередь вызываеть через POSTMESSAGE!!! WM_CLOSE — кстати тоже где то через WM_NCLBUTTONDOWN...
А насчет того — что не работает... "Не верь глаза своим"
AS>Зачем? Подсистема GDI, прекрасно зная адрес оконной процедуры может напрямую ее вызывать. Зачем ей тратить время на помещение сообщения в очередь? Можно спокойно заменить Полностью не верно!!! Иначе бы ты спокойно по сотне раз оказывался внутри одного и того же кода! У тебя никогда проги не висли? Вспомни как круто GDI перерисовывает бекграунды у подвисших прог...
AS>Тут я вообще не понял. У GetMessage чель одна — заполнить структуру MSG и удалить сообщение из очереди. Все!
Ну все так все... Каждый имеет право заблуждаться по своему .
Здравствуйте, algod, Вы писали:
A>Здравствуйте, Alexey Shirshov, Вы писали:
[]
A> Круто. MSDN читал? WM_ERASEBKGND — не прямое сообщение... Оно вызваеться по BeginPaint... Которое в свою очередь вызываеть через POSTMESSAGE!!! WM_CLOSE — кстати тоже где то через WM_NCLBUTTONDOWN... A>А насчет того — что не работает... "Не верь глаза своим"
Ты несеш такую чушь, которую опровергать-то трудно!
1. BeginPaint дествительно "посылает" WM_ERASEBKGND, но только если установлен fErase.
2. PostMessage при этом не причем — оконная процедура вызывается напрямую.
Поставь breakpoint на PostMessage — она не будет вызвана системой ни разу! Поставь breakpoint на WM_ERASEBKGND и WM_PAINT и увидишь, что WM_ERASEBKGND срабатывает раньше!
Поставь вместо message pump'a Sleep() и увидешь, что GetMessage здесь вообще не причем!
хъ
A>Полностью не верно!!! Иначе бы ты спокойно по сотне раз оказывался внутри одного и того же кода! У тебя никогда проги не висли? Вспомни как круто GDI перерисовывает бекграунды у подвисших прог...
Это почему? Ты про что?
хъ
A>Ну все так все... Каждый имеет право заблуждаться по своему .
Заблуждайся на здоровье. Я имею обыкновение разбираться с проблемными областями, а не лепетать бесвязные реплики про то, что все не верно и как GDI перерисовывает мои окна.
Здравствуйте, Alexey Shirshov, Вы писали:
AS>Здравствуйте, algod, Вы писали:
A>>GetMessage — выгребает с возвращением только PostMessage. Kirill и Павел правы.
AS>Тут я вообще не понял. У GetMessage чель одна — заполнить структуру MSG и удалить сообщение из очереди. Все!
Помоему написано не двусмыслено! Get(Peek)Message автоматически диспатчит
синхронные сообщения. Не заполняет она структуру MSG для синхронных сообщений!
Еще книжка хорошая есть — Рихтер "Windows для професионалов"
— там про это очень подробно рассказывается.
А если все равно не веришь — попробуй из GetMessage получить хотя бы одно
синхронное сообщение, успехов...
Это еще раз говорит о том, что если человек хочет за фонарным столбом разглядеть дерево, он найдет кучу способов это сделать.
KL>Помоему написано не двусмыслено! Get(Peek)Message автоматически диспатчит KL>синхронные сообщения. Не заполняет она структуру MSG для синхронных сообщений!
Может быть не заполняет. Но тогда как сообщение доставляется в оконную процедуру? Поставь breakpoint на DispatchMessage и он ни разу не сработает. Получается, что Get(Peek)Message просто знают адрес процедуры! Но откуда??
Как такой вот message pump узнаёт адрес оконной процедуры?
while (GetMessage(&msg, NULL, 0, 0));
KL>А если все равно не веришь — попробуй из GetMessage получить хотя бы одно KL>синхронное сообщение, успехов...
Вот если ты такой умный, объясни каким образом GetMessage доставляет оконной процедуре сообщения (синхронные).
Здравствуйте, Alexey Shirshov, Вы писали:
AS>Здравствуйте, Kirill_Luzanov, Вы писали:
AS>[]
KL>>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/messagesandmessagequeues/messagesandmessagequeuesreference/messagesandmessagequeuesfunctions/getmessage.asp. KL>>Там написано: KL>>The GetMessage function retrieves a message from the calling thread's message queue. KL>>The function dispatches incoming sent messages until a KL>>posted message is available for retrieval.
AS>Это еще раз говорит о том, что если человек хочет за фонарным столбом разглядеть дерево, он найдет кучу способов это сделать.
KL>>Помоему написано не двусмыслено! Get(Peek)Message автоматически диспатчит KL>>синхронные сообщения. Не заполняет она структуру MSG для синхронных сообщений!
AS>Может быть не заполняет. Но тогда как сообщение доставляется в оконную процедуру? Поставь breakpoint на DispatchMessage и он ни разу не сработает. Получается, что Get(Peek)Message просто знают адрес процедуры! Но откуда?? Да, КОНЕЧНО ЗНАЮТ. см. далее AS>Как такой вот message pump узнаёт адрес оконной процедуры? AS>
AS>while (GetMessage(&msg, NULL, 0, 0));
AS>
KL>>А если все равно не веришь — попробуй из GetMessage получить хотя бы одно KL>>синхронное сообщение, успехов...
AS>Вот если ты такой умный, объясни каким образом GetMessage доставляет оконной процедуре сообщения (синхронные).
Спасибо за комплимент.
Ты заблудился в трех соснах.
Встречный вопрос — а как ты думаешь как DispatchMessage передает сообщение оконной процедуре — ОТКУДА
эта ф-ция знает как ты говоришь адрес оконной процедуры? Не задумывался? Ведь все что она получает на входе —
это структура MSG. А получаешь ты эту структуру из ф-ции Get(Peek)Message. Или ты думаешь что если ты сделаешь
вызов GetMessage(&msg, NULL, 0, 0) — то получишь в результате (msg.hwnd == NULL)? Типа ты подскзываешь
винде как правильно заполнить структру MSG и если не задашь handle окна — то реакция винды будет ?
Когда ты вызываешь SendMessage — ты указываешь handle окна которому направляется сообщение.
Внутри эта ф-ция заполняте структру MSG. Операционная система ЗНАЕТ к какому окну относится какая оконная процедура
(для этого ты РЕГИСТРИРУЕШЬ класс окна, в информации о классе ты УКАЗЫВАЕШЬ АДРЕС ОКОННОЙ ПРОЦЕДУРЫ,
а потом при создании окна ЯВНО указываешь к какому классу оно(окно) принадлежит).
А по твоей логике получается что в виндах есть ф-ции так сказать приближенные к трону —
которые знают внутреннюю информацию — и есть типа ф-ции "простолюдины" —
которые далеки от придворных дел.
Ф-ций Get(Peek)Message ЗНАЮТ адреса нужных оконных процедур
(точнее это знает OC частью API которой эти ф-ции являтся ).
Короче говоря, никаких GetWindowLong GetMessage не вызывает. Но, как я сам убедился, сообщения каким-то образом она все-таки в оконную процедуру передает.
Меня смутило то, что TaskManager не может закрыть окно, имеющее "пустой" цикл
while (GetMessage(&msg, NULL, 0, 0));
Наверняка он посылает WM_CLOSE асинхронно. Я не перестаю удивляться ребятам из мелкософта: ну что им мешало использовать SendMessageTimeout?
После непродолжительной отладки выяснил, что GetMessage вызывает оконную процедуру с помощью некой функции, адрес которой (Prof SP3) 0x77E174C8. Она находится непосредственно перед IsWindowEnabled. Эта функция вызывает еще одну, та еще одну и наконец мы попадаем в оконную процедуру.
Покапался я в книжках и нашел (у Pietrek'а), что адрес оконной процедуры лежит по смещению 0x28 в структуре WND. Насколько я понимаю, из HWND можно лекго получить указатель на эту структуру, так что обращатся к GetWindowLong не нужно.
В общем, тема требует дальнейшего изучения...
Однако на счет того, что GetMessage не вызывает оконную процедуру я погорячился. Признаю свою ошибку.
DWORD* GetWndPointer(HWND hwnd) // hwnd is the handle of any window in the system
{
DWORD user32_si; //user32 shared info; gSharedInfo
DWORD pWND;
DWORD local_correction;
// 0x58180 is the offset of gSharedInfo in "user32.dll"
user32_si=(DWORD)GetModuleHandle("user32.dll")+0x58180;
pWND=*(DWORD*)(user32_si+4);
pWND+=LOWORD(hwnd)*12;
pWND=*(DWORD*)pWND; // now pWND points to the real WND structure above 2 GB
// and this is a writable memory if we were running in system mode (ring 0)
// but in user mode (ring 3) we could't even read it
// this is something like 0xA03xxxxx this is where I want to
// write
/*
local_correction=*((DWORD *)0x7ffde6e8);
// [7ffde6e8] - the value that must be subtracted from the pointer above 2 GB
// in order to get user-mode accessible pointer to the window structure
pWND-=local_correction;
// the new pointer points to read only memory but it is mapped to the same physical address as the
// pointer above 2 GB, that is before the correction is made
*/return (DWORD*)pWND;
}
[]
БП>А если скачать pdb-шник для USER32? Там имя этой функции наверняка есть.
Нету.
БП>Вот и молодец. Кстати, вот полный список тех, кто это делает:
БП>DialogBox БП>DialogBoxIndirect БП>DialogBoxIndirectParam БП>DialogBoxParam БП>GetMessage БП>MessageBox БП>PeekMessage БП>SendMessage
Буду знать. Спасибо.
хъ
Так гдеж ты был, когда я просил посмотреть статью про WTL? Я эту фичу не смог объяснить. А Влад уже все сверстал.
БП>Именно так и происходит в годе, создаваемом мастером WTL для MultiThreadSDI. БП>Что я и пытался сказать в прошлом письме.