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
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.