SendMessage vs PostMessage
От: DrMom  
Дата: 20.02.03 22:53
Оценка:
Почему когда я из одного потока посылаю в др. WM_QUIT при помощи SendMessage, то GetMessage не возвращает 0, а когда использую PostMessage, то все нормально??? В чем разница? Самое интерестное, что Spy++ пишет что сообщение послано — принято. Помогите плиз.
Re: SendMessage vs PostMessage
От: Алексей Владимирович Миронов Россия  
Дата: 21.02.03 01:06
Оценка: 7 (2)
Здравствуйте, 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.

Re[2]: SendMessage vs PostMessage
От: DrMom  
Дата: 21.02.03 03:46
Оценка:
Здравствуйте, Алексей Владимирович Миронов, Вы писали:

АВМ>Это Вам только кажется, что все нормально.




АВМ>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[3]: SendMessage vs PostMessage
От: IceHand  
Дата: 21.02.03 04:04
Оценка: -3
SendMessage, PostMessage отличие этих функций в том, что send посылает сообщение и не ждет обработано оно или нет, а post ждет пока сообщение обработается
Re[4]: SendMessage vs PostMessage
От: Аноним  
Дата: 21.02.03 05:04
Оценка:
Здравствуйте, IceHand, Вы писали:

IH>SendMessage, PostMessage отличие этих функций в том, что send посылает сообщение и не ждет обработано оно или нет, а post ждет пока сообщение обработается


Наоборот.
Re[5]: SendMessage vs PostMessage
От: DrMom  
Дата: 21.02.03 06:18
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, IceHand, Вы писали:


IH>>SendMessage, PostMessage отличие этих функций в том, что send посылает сообщение и не ждет обработано оно или нет, а post ждет пока сообщение обработается


А>Наоборот.


Господа, не надо заниматься пустой болтовней. Вы бы хоть посмотрели, что я спрашивал. Чем объяснять мне разницу между SM и PM, лучше ответили бы на мой вопрос. За полезный ответ готов балами отблагодарить.
Re[6]: SendMessage vs PostMessage
От: algod Украина  
Дата: 21.02.03 06:50
Оценка:
DM>Господа, не надо заниматься пустой болтовней. Вы бы хоть посмотрели, что я спрашивал. Чем объяснять мне разницу между SM и PM, лучше ответили бы на мой вопрос. За полезный ответ готов балами отблагодарить.

SM напрямую вызывает каллбек твоего окна, проходит сквозь свичер —
и вылетает, так ничего и не сделав....
PM заганяет WB_QUIT в стек сообщений, откуда оно потом забираеться GetMessage
— и GetMessage возвращет 0.
В первом случае до GetMessage даже не доходит...

з.ы. А спай — прав... Оконная процедура таки получила соббщение...
Другой вопрос как...
There is no bug
Re[7]: SendMessage vs PostMessage
От: Рек Россия  
Дата: 21.02.03 07:22
Оценка:
Здравствуйте, 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ообщение из очереди, вызовет
оконную процедуру изнутри напрямую, не возвращая управление?
Re[8]: SendMessage vs PostMessage
От: algod Украина  
Дата: 21.02.03 07:49
Оценка:
Здравствуйте, Рек, Вы писали:

Рек>


Рек>Мелкие терминологические замечания:

Рек>...
Но ты же меня понял? Тогда — зачем эти вечные споры о терминологии

Рек>Кстати вопрос:

Рек>Если делать SM из другого потока (не из потока, создавшего окно),
Рек>то прямого вызова оконной процедуры происходить не будет?
Будет! Читаем МСДН:
If the specified window was created by a different thread, the system switches to that thread and calls the appropriate window procedure. Messages sent between threads are processed only when the receiving thread executes message retrieval code. The sending thread is blocked until the receiving thread processes the message.

SM гарантированно возвращает код "оконной процедуры". Если в этот момент оконная проца другого потока подвиснет — подвиснешь и ты.

(для справки есть еще SendMessageTimeout — тоже самое, что SM, но более расчитано на работу с многозадачностью )

Рек>Всё будет проходить через очередь?

Рек>Вариант И GetMessage в этом случае вернёт 0?
Рек>Или GetMessage всё равно, выгребая sm-cообщение из очереди, вызовет
Рек>оконную процедуру изнутри напрямую, не возвращая управление?

См. выше....
There is no bug
Re[9]: SendMessage vs PostMessage
От: Рек Россия  
Дата: 21.02.03 12:03
Оценка:
Здравствуйте, algod, Вы писали:

A>Здравствуйте, Рек, Вы писали:


Рек>>


Рек>>Мелкие терминологические замечания:

Рек>>...
A> Но ты же меня понял? Тогда — зачем эти вечные споры о терминологии

Рек>>Кстати вопрос:

Рек>>Если делать SM из другого потока (не из потока, создавшего окно),
Рек>>то прямого вызова оконной процедуры происходить не будет?
A> Будет! Читаем МСДН:
A>If the specified window was created by a different thread, the system switches to that thread and calls the appropriate window procedure. Messages sent between threads are processed only when the receiving thread executes message retrieval code. The sending thread is blocked until the receiving thread processes the message.

A>SM гарантированно возвращает код "оконной процедуры". Если в этот момент оконная проца другого потока подвиснет — подвиснешь и ты.


A> (для справки есть еще SendMessageTimeout — тоже самое, что SM, но более расчитано на работу с многозадачностью )


Рек>>Всё будет проходить через очередь?

Рек>>Вариант И GetMessage в этом случае вернёт 0?
Рек>>Или GetMessage всё равно, выгребая sm-cообщение из очереди, вызовет
Рек>>оконную процедуру изнутри напрямую, не возвращая управление?
A>
A> См. выше....

Правильно ли я понял,
что SM-сообщения обрабатываются внутри GetMessage (прямым колом)
и никогда не попадают в DispatchMessagе?
В том числе и тогда когда сообщение пришло из другого потока.
Так?
Re[10]: SendMessage vs PostMessage
От: algod Украина  
Дата: 21.02.03 12:39
Оценка:
Здравствуйте, Рек, Вы писали:

Рек>Правильно ли я понял,

Рек>что 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 );
}


Грубая реализация SendMessage:

LRESULT SendMessage
  ( HWND hWnd
  , UINT Msg
  , WPARAM wParam
  , LPARAM lParam)
{
// ***********************
//  Что то тут есть: проверка на валидность оконного хендла, синхранизация многопоточности етс.
// ***********************

  return CallWindowProc
    ( (WNDPROC) GetWindowLong (lpmsg->hwnd, GWL_WNDPROC)
    , lpmsg->message
    , lpmsg->wParam
    , lpmsg->lParam );
}


Я не знаю досконально внутренний механизм этих функций, но судя по всему, оно где то рядом...
Теоретически можно поробовать реализовать стандартный оконный луп через CallWindowProc или
SendMessage — и посмотреть что получиться...

з.ы. кстати — сейчас попробую, и напишу
There is no bug
Re[10]: SendMessage vs PostMessage
От: algod Украина  
Дата: 21.02.03 12:48
Оценка:
Рек>Правильно ли я понял,
Рек>что SM-сообщения обрабатываются внутри GetMessage (прямым колом)
Рек>и никогда не попадают в DispatchMessagе?
Рек>В том числе и тогда когда сообщение пришло из другого потока.
Рек>Так?

В продолжение темы:
SM, CallWindowProc
— оба варианта прекрасно работают внутри
while(GetMessage(...) {...}

DispatchMessage — нужен только для таймера
There is no bug
Re[2]: SendMessage vs PostMessage
От: Valerio Россия linkedin.com/in/boronin
Дата: 22.02.03 10:45
Оценка: 13 (2)
Абсолютно верный ответ:
существует флаг статуса очереди сообщений — QS_QUIT
он выставляется как раз именно PostQuitMessage, а не PostMessage
при этом WM_QUIT вообще не добавляется к очереди сообщений

когда поток вызывает GetMessage or PeekMessage система проверяет состояние очередей потока и если видит установленный флаг QS_QUIT просто возвращает WM_QUIT и сбрасывает флаг

при этом помню интересный sideeffect от такого поведения для WM_QUIT:
фрагмент
PostQuitMessage(0);
PostMessage(hwnd,msg,wparam,lparam);

и здесь все сообщения после 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.
Re[11]: SendMessage vs PostMessage
От: Kirill_Luzanov  
Дата: 12.03.03 15:18
Оценка:
Здравствуйте, 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 :
LRESULT SendMessage(HWND hWnd, UINT Msg , WPARAM wParam , LPARAM lParam)
{
   DWORD dwThreadID = System::GetWindowNativeThreadID(hWnd);
   System::MessageQueue* pQueue = System::GetThreadMessageQueue(dwThreadID);
   MSG msg(Msg, wParam, lParam)
   return pQueue->AddSync(&msg);
}

LRESULT System::MessageQueue::AddSync(MSG* pMsg)
{
   SyncMSGWrapper SyncMsg(pMsg);
   m_mtx.Lock();
   m_list.push_back(&SyncMsg)
   m_mtx.Unlock();
   m_NewMsgEvent.Set();
   if(WaitForXXXX(SyncMsg.m_ProcessedEvent.GetHandle(), INFINITE) == WAIT_OBJECT_0)
      return SyncMsg.GetResult();
   else
      обработка ошибок
}

BOOL GetMessage(MSG* pMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax)
{
   System::MessageQueue* pQueue = System::GetThreadMessageQueue(::GetCurrentThreadID());
   return pQueue->GetMessage(pMsg, hWnd, wMsgFilterMin,wMsgFilterMax);
}

BOOL System::MessageQueue::GetMessage(MSG* pMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax)
{
   if(::GetCurrentThreadID() != m_dwNativeThreadID)
       return -1;
   while(TRUE)
   {
    m_mtx.Lock();
    if(m_list.empty())
    {
        if(WaitForXXX(m_NewMsgEvent.GetHandle(), INFINiTE) == WAIT_OBJECT_0)
            break;
    }
    else
    {
      for(iter i = m_list.begin(); i != m_list.end(); ++i)
      {
          SystemMSG* pMSG = *i;
          if(pMSG->IsSync())
          {
             FindAndCallWindowProc(pMSG);
             pMsg->m_ProcessedEvent.Set();
             m_list.erase(i);
          }
      }
      // далее поиск на соотв фильтру асинхронного сообщения и возврат
      // первого подходящего
       
    }
  }
}

Think different
Re[12]: SendMessage vs PostMessage
От: Kirill_Luzanov  
Дата: 12.03.03 15:36
Оценка:
Здравствуйте, Kirill_Luzanov, Вы писали:


KL> НЕВЕРНО!!! Если поток не вызывает GetMessage или PeekMessage сообщение НИКОГДА не будет обработанно!

KL>SendMessage НЕ ВЫЗЫВАЕТ напрямую оконную процедуру — если бы это было так — то оконная процедура вызывалсь бы
KL>в ТЕКУЩЕМ потоке — а не потоке ВЛАДЕЮЩЕМ очередью сообщений!!!
KL>В WINDOWS ВСЕ СООБЩЕНИЯ ДЛЯ ПОТОКА ОБРАБАТЫАЮТСЯ ТОЛЬКО В САМОМ ПОТОКЕ!
KL>Так что прав — Pek.
Забыл уточнить — SendMessage может вызвать оконную процедуру напрямую ТОЛЬОКО если
она вызывается в родном для окна потоке. Иначе см. выше.
И соотв. слегка изм. псевдокод:
LRESULT SendMessage(HWND hWnd, UINT Msg , WPARAM wParam , LPARAM lParam)
{
   DWORD dwThreadID = System::GetWindowNativeThreadID(hWnd);
   System::MessageQueue* pQueue = System::GetThreadMessageQueue(dwThreadID);
   if(GetCurrentThreadId() == pQueue->GetNativeThredId())
      вызывается оконная процедура
   else
   {
     MSG msg(Msg, wParam, lParam)
     return pQueue->AddSync(&msg);
   }
}
далее смотри мой предыдущий пост...
Think different
Re[13]: SendMessage vs PostMessage
От: algod Украина  
Дата: 12.03.03 16:23
Оценка:
Здравствуйте, Kirill_Luzanov, Вы писали:

KL>Здравствуйте, Kirill_Luzanov, Вы писали:


KL>Забыл уточнить — SendMessage может вызвать оконную процедуру напрямую ТОЛЬОКО если

KL>она вызывается в родном для окна потоке. Иначе см. выше.
KL>И соотв. слегка изм. псевдокод:
KL>
KL>LRESULT SendMessage(HWND hWnd, UINT Msg , WPARAM wParam , LPARAM lParam)
KL>{
KL>   DWORD dwThreadID = System::GetWindowNativeThreadID(hWnd);
KL>   System::MessageQueue* pQueue = System::GetThreadMessageQueue(dwThreadID);
KL>   if(GetCurrentThreadId() == pQueue->GetNativeThredId())
KL>      вызывается оконная процедура
KL>   else
KL>   {
KL>     MSG msg(Msg, wParam, lParam)
KL>     return pQueue->AddSync(&msg);
KL>   }
KL>}
KL>далее смотри мой предыдущий пост...
KL>


Ладно... Частично сглючил... Как раз из за того, что ты описал в последнем посте .
Ведь все таки PostMessage выгребаеться из очереди . Хотя он для того и создан
There is no bug
Re[14]: SendMessage vs PostMessage
От: Kirill_Luzanov  
Дата: 12.03.03 17:13
Оценка:
Здравствуйте, algod, Вы писали:

A>Здравствуйте, Kirill_Luzanov, Вы писали:


KL>>Здравствуйте, Kirill_Luzanov, Вы писали:


KL>>Забыл уточнить — SendMessage может вызвать оконную процедуру напрямую ТОЛЬОКО если

KL>>она вызывается в родном для окна потоке. Иначе см. выше.
KL>>И соотв. слегка изм. псевдокод:
KL>>
KL>>LRESULT SendMessage(HWND hWnd, UINT Msg , WPARAM wParam , LPARAM lParam)
KL>>{
KL>>   DWORD dwThreadID = System::GetWindowNativeThreadID(hWnd);
KL>>   System::MessageQueue* pQueue = System::GetThreadMessageQueue(dwThreadID);
KL>>   if(GetCurrentThreadId() == pQueue->GetNativeThredId())
KL>>      вызывается оконная процедура
KL>>   else
KL>>   {
KL>>     MSG msg(Msg, wParam, lParam)
KL>>     return pQueue->AddSync(&msg);
KL>>   }
KL>>}
KL>>далее смотри мой предыдущий пост...
KL>>


A> Ладно... Частично сглючил... Как раз из за того, что ты описал в последнем посте .

A>Ведь все таки PostMessage выгребаеться из очереди . Хотя он для того и создан
Со всеми бывает...

Чтобы до конца расставить все точки над "и" резюмирую:
Если вызывающий SendMessage поток явл. РОДНЫМ для окна — сообщение в очередь сообщений
потока НЕ помещается — а НАПРЯМУЮ передается соотв. оконной процедуре.
Если вызвывающий SendMessage поток НЕ ЯВЛ. РОДНЫМ для окна — SendMessage НЕ ВЫЗЫВАЕТ
напрямую оконную процедуру (- если бы это было так — то оконная процедура вызывалсь бы
в ТЕКУЩЕМ потоке — а не потоке ВЛАДЕЮЩЕМ очередью сообщений) — а помещает его в очередь
и ждет обработки сообщения соотв.ф-циями (GetMessage и т.п.) РОДНОГО для окна потока!!!
В WINDOWS ВСЕ СООБЩЕНИЯ ДЛЯ ПОТОКА ОБРАБАТЫАЮТСЯ ТОЛЬКО В САМОМ ПОТОКЕ!
Обработка очереди сообщений:
Если поток не вызывает GetMessage или PeekMessage — то сообщения из ДРУГИХ
потоков НИКОГДА не будут обработанны!
Синхронные сообщения (из других потоков (см. выше)) имеют наибольший приоритет
и обрабатываются в первую очередь! Они обрабатываются автоматически
(перенаправляются в оконную процедру) внутри
вызова потоком Get(Peek)Message.
Используя Get(Peek)Message можно выбрать из очереди только асинхронное собщение.

Ну вроде все...
Think different
Re[15]: SendMessage vs PostMessage
От: Блудов Павел Россия  
Дата: 13.03.03 03:42
Оценка:
Здравствуйте, Kirill_Luzanov, Вы писали:

KL>Если поток не вызывает GetMessage или PeekMessage — то сообщения из ДРУГИХ

KL>потоков НИКОГДА не будут обработанны!

Маленькое дополнение.
::SendMessage(hwndОкнаИзДругойНити) не вернется, до тех пор, пока оконная процедура
жтого окна не отработает. Тем не менее, эта оконная процедура может в свою очередь
сделать ::SendMessage(hwndОкнаИзНитиСделавшейSendMessage), и это сообщение тоже
будет обработано.

Дело в том, что если ::SendMessage() должна сидеть и ждать, пока отработает
другая нить, то она обрабатывает вызовы ::SendMessage() из других нитей
для "своих" окон. ::PostMessage() для "своих" окон не будут обработаны до
::Get/PeekMessage().

И еще интересный момент.
Если было послано сообщение из лругой нити, то ::MsgWaitForMutliObjs() вернет
WAITOBJECT_0 + nObjects, как если бы в очереди завелось сообщение,
и следующий вызов ::GetMessage() "дернет" напрямую оконную процедуру,
но не вернется, так как ему нечего возвращать.

Довольно популярная ошибка, даже WTL-ный мастер вставляет ее в проекты
MultiThreadedSDI.

Павел.
Re[16]: SendMessage vs PostMessage
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 13.03.03 04:45
Оценка:
Здравствуйте, Блудов Павел, Вы писали:

[]

БП>И еще интересный момент.

БП>Если было послано сообщение из лругой нити, то ::MsgWaitForMutliObjs() вернет
БП>WAITOBJECT_0 + nObjects, как если бы в очереди завелось сообщение,
БП>и следующий вызов ::GetMessage() "дернет" напрямую оконную процедуру,
БП>но не вернется, так как ему нечего возвращать.

БП>Довольно популярная ошибка, даже WTL-ный мастер вставляет ее в проекты

БП>MultiThreadedSDI.

Вот те здрасте! GetMessage вызывает напрямую оконную процедуру? Это ты где такое вычитал? Хе-хе.
GetMessage только и делает, что дожидается сообщения в очереди и заполняет структуру MSG. Все! Ничего она не вызывает!
А в WTL какой-то другой глюк.
Re[17]: SendMessage vs PostMessage
От: algod Украина  
Дата: 13.03.03 08:05
Оценка:
Здравствуйте, 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 и Павел правы.
There is no bug
Re[18]: SendMessage vs PostMessage
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 13.03.03 08:53
Оценка:
Здравствуйте, algod, Вы писали:

[]

A>А ты проверь, как я .


Неа.

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 и удалить сообщение из очереди. Все!
Re[19]: SendMessage vs PostMessage
От: algod Украина  
Дата: 13.03.03 09:37
Оценка:
Здравствуйте, 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 и удалить сообщение из очереди. Все!


Ну все так все... Каждый имеет право заблуждаться по своему .
There is no bug
Re[20]: SendMessage vs PostMessage
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 13.03.03 09:52
Оценка:
Здравствуйте, 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 перерисовывает мои окна.
Re[19]: SendMessage vs PostMessage
От: Kirill_Luzanov  
Дата: 13.03.03 13:22
Оценка:
Здравствуйте, Alexey Shirshov, Вы писали:

AS>Здравствуйте, algod, Вы писали:


A>>GetMessage — выгребает с возвращением только PostMessage. Kirill и Павел правы.


AS>Тут я вообще не понял. У GetMessage чель одна — заполнить структуру MSG и удалить сообщение из очереди. Все!


Не ну народ — это не серьезно!
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/messagesandmessagequeues/messagesandmessagequeuesreference/messagesandmessagequeuesfunctions/getmessage.asp.
Там написано:
The GetMessage function retrieves a message from the calling thread's message queue.
The function dispatches incoming sent messages until a
posted message is available for retrieval.

Помоему написано не двусмыслено! Get(Peek)Message автоматически диспатчит
синхронные сообщения. Не заполняет она структуру MSG для синхронных сообщений!
Еще книжка хорошая есть — Рихтер "Windows для професионалов"
— там про это очень подробно рассказывается.

А если все равно не веришь — попробуй из GetMessage получить хотя бы одно
синхронное сообщение, успехов...
Think different
Re[20]: SendMessage vs PostMessage
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 13.03.03 14:34
Оценка:
Здравствуйте, Kirill_Luzanov, Вы писали:

[]

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.

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

KL>Помоему написано не двусмыслено! Get(Peek)Message автоматически диспатчит

KL>синхронные сообщения. Не заполняет она структуру MSG для синхронных сообщений!

Может быть не заполняет. Но тогда как сообщение доставляется в оконную процедуру? Поставь breakpoint на DispatchMessage и он ни разу не сработает. Получается, что Get(Peek)Message просто знают адрес процедуры! Но откуда??
Как такой вот message pump узнаёт адрес оконной процедуры?
while (GetMessage(&msg, NULL, 0, 0));


KL>А если все равно не веришь — попробуй из GetMessage получить хотя бы одно

KL>синхронное сообщение, успехов...

Вот если ты такой умный, объясни каким образом GetMessage доставляет оконной процедуре сообщения (синхронные).
Re[21]: SendMessage vs PostMessage
От: Kirill_Luzanov  
Дата: 13.03.03 15:17
Оценка:
Здравствуйте, 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 которой эти ф-ции являтся ).
Think different
Re[21]: SendMessage vs PostMessage
От: algod Украина  
Дата: 13.03.03 15:32
Оценка: 3 (1)
Здравствуйте, Alexey Shirshov:

В дополние сказанному Kirill_Luzanov.
Если бы ты читал то, что было написанно раньше то заметил бы следуюющий код:

GetWindowLong(hwnd, GWL_WINDOWPROC);

Используя который можно получить текущюю оконную процу.

Кроме всего есть:
BOOL GetClassInfo( 
HINSTANCE hInstance, 
LPCTSTR lpClassName, 
LPWNDCLASS lpWndClass); 

int GetClassName(
  HWND hWnd,           
  LPTSTR lpClassName,  
  int nMaxCount        
);


с помощью которых можно получить предефайнутую (в классе) оконную процу.
There is no bug
Re[22]: SendMessage vs PostMessage
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 14.03.03 06:45
Оценка:
Здравствуйте, Kirill_Luzanov, Вы писали:

[]

Короче говоря, никаких GetWindowLong GetMessage не вызывает. Но, как я сам убедился, сообщения каким-то образом она все-таки в оконную процедуру передает.

Меня смутило то, что TaskManager не может закрыть окно, имеющее "пустой" цикл

while (GetMessage(&msg, NULL, 0, 0));


Наверняка он посылает WM_CLOSE асинхронно. Я не перестаю удивляться ребятам из мелкософта: ну что им мешало использовать SendMessageTimeout?

После непродолжительной отладки выяснил, что GetMessage вызывает оконную процедуру с помощью некой функции, адрес которой (Prof SP3) 0x77E174C8. Она находится непосредственно перед IsWindowEnabled. Эта функция вызывает еще одну, та еще одну и наконец мы попадаем в оконную процедуру.

Покапался я в книжках и нашел (у Pietrek'а), что адрес оконной процедуры лежит по смещению 0x28 в структуре WND. Насколько я понимаю, из HWND можно лекго получить указатель на эту структуру, так что обращатся к GetWindowLong не нужно.

В общем, тема требует дальнейшего изучения...

Однако на счет того, что GetMessage не вызывает оконную процедуру я погорячился. Признаю свою ошибку.
Re[23]: SendMessage vs PostMessage
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 14.03.03 06:51
Оценка:
Здравствуйте, Alexey Shirshov, Вы писали:

[]

Кстати, нашел в google.
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;
}


Не проверял, но выглядит правдоподобно.
Re[23]: SendMessage vs PostMessage
От: Блудов Павел Россия  
Дата: 14.03.03 09:05
Оценка: 14 (1)
Здравствуйте, Alexey Shirshov, Вы писали:

AS>После непродолжительной отладки выяснил, что GetMessage вызывает оконную процедуру с помощью некой функции, адрес которой (Prof SP3) 0x77E174C8


А если скачать pdb-шник для USER32? Там имя этой функции наверняка есть.

AS>Однако на счет того, что GetMessage не вызывает оконную процедуру я погорячился. Признаю свою ошибку.


Вот и молодец. Кстати, вот полный список тех, кто это делает:

DialogBox
DialogBoxIndirect
DialogBoxIndirectParam
DialogBoxParam
GetMessage
MessageBox
PeekMessage
SendMessage

Обратите внимание, что ::MsgWaitForMultipleObjects() в этом списке нет,
она не обрабатывает синхронные сообщения, но она вернет WAIT_OBJECT_0 + nCount
исли будет получено синхронные сообщение из другой нити. Так что если в ответ на
WAIT_OBJECT_0 + nCount тупо вызывать ::GetMessage(), то ::GetMessage()
обработает синхронный вызов. И будет ждать, пока кто-то еще не
отправит-таки сообщение через ::PostMessage(). Возможно, что вечно.

Именно так и происходит в годе, создаваемом мастером WTL для MultiThreadSDI.
Что я и пытался сказать в прошлом письме.

Павел.
Re[24]: SendMessage vs PostMessage
От: Alexey Shirshov Россия http://wise-orm.com
Дата: 14.03.03 09:11
Оценка:
Здравствуйте, Блудов Павел, Вы писали:

[]

БП>А если скачать pdb-шник для USER32? Там имя этой функции наверняка есть.


Нету.

БП>Вот и молодец. Кстати, вот полный список тех, кто это делает:


БП>DialogBox

БП>DialogBoxIndirect
БП>DialogBoxIndirectParam
БП>DialogBoxParam
БП>GetMessage
БП>MessageBox
БП>PeekMessage
БП>SendMessage

Буду знать. Спасибо.

хъ

Так гдеж ты был, когда я просил посмотреть статью про WTL? Я эту фичу не смог объяснить. А Влад уже все сверстал.

БП>Именно так и происходит в годе, создаваемом мастером WTL для MultiThreadSDI.

БП>Что я и пытался сказать в прошлом письме.

Понял. Спасибо.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.