PreTranslateMessage

来源:互联网 发布:一个小公司的网络管理 编辑:程序博客网 时间:2024/06/09 13:39

PreTranslateMessage是消息在送给TranslateMessage函数之前被调用的,绝大多数本窗口的消息都要通过这里,比较常用,当需要在MFC之前处理某些消息时,常常要在这里添加代码. 
      

       MFC 消息控制流最具特色的地方是CWnd类的虚拟函数PreTranslateMessage(),通过重载这个函数,可以改变MFC的消息控制流程,甚至可以作一个全新的控制流出来。只有穿过消息队列的消息才受PreTranslateMessage()影响,采用SendMessage()或其他类似的方式向窗口直接发送的而不经过消息队列的消息根本不会理睬PreTranslateMessage()的存在。 

       是否调用TranslateMessage()和DispatchMessage()是由一个名称为PreTranslateMessage()函数的返回值决定的,如果该函数返回TRUE,则不会把该消息分发给窗口函数处理。

传给PreTranslateMessage()的消息是未经翻译过的消息,它没有经过TranslateMessage()处理。可以在该函数中使用(pMsg->wParam==VK_RETURN)来拦截回车键。wParam中存放的是键盘上字符的虚拟码。

PeekMessage和GetMessage的区别:

GetMessage在没有消息的时候等待消息,cpu当然低

PeekMessage没有消息的时候立刻返回,所以cpu占用率高。

因为游戏不能靠windows消息驱动,所以要用PeekMessage();

     PretranslateMessage 的实现,不得不谈到MFC消息循环的实现。MFC通过CWinApp类中的Pumpmessage函数实现消息循环,但是实际的消息循环代码位于 CWinThread中,CWinApp只是从CWinThread继承过来。其简化后的代码大概如下:
  BOOL CWinThread::PumpMessage()
  {
  _AFX_THREAD_STATE *pState = AfxGetThreadState();
  
  ::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))
  
  if (!AfxPreTranslateMessage(&(pState->m_msgCur)))
  {
  ::TranslateMessage(&(pState->m_msgCur));
  ::DispatchMessage(&(pState->m_msgCur));
  }
  return TRUE;
  }
  可以看到,PumpMessage在实际的TranslateMessage和DispatchMessage发生之前会调用 AfxPreTranslateMessage,AfxPreTranslateMessage又会调用 CWnd::WalkPreTranslateTree(虽然也会调用其他函数,但是这个最为关键),其代码如下:
  BOOL PASCAL CWnd::WalkPreTranslateTree(HWND hWndStop, MSG* pMsg)
  {
  ASSERT(hWndStop == NULL || ::IsWindow(hWndStop));
  ASSERT(pMsg != NULL);
  
  // walk from the target window up to the hWndStop window checking
  // if any window wants to translate this message
  
  for (HWND hWnd = pMsg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
  {
  CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
  if (pWnd != NULL)
  {
  // target window is a C window
  if (pWnd->PreTranslateMessage(pMsg))
  return TRUE; // trapped by target window (eg: accelerators)
  }
  
  // got to hWndStop window without interest
  if (hWnd == hWndStop)
  break;
  }
  return FALSE; // no special processing
  }
  
  可以看到,代码还是很直接的。从接受到消息的窗口层层往上遍历,并调用PretranslateMessage看是否返回TRUE,是则结束,否则继续。
  这里有一个地方非常关键:CWnd *pWnd = CWnd::FromHandlePermanent(hWnd) 这一句代码从当前AfxModuleThreadState拿到Permanent句柄表,从而找到hWnd对应的CWnd


MFC 中PreTranslateMessage是GetMessage(...)函数的下一级操作,即GetMessage(...)从消息队列中获取消息后,交由PreTranslateMessage()处理,若其返回FALSE则再交给TranslateMessage和 DispatchMessage处理(进入WindowProc);  
如果用SendMessage,   则消息直接交到WindowProc处理,所以GetMessage不会取得SendMessage的消息,当然PreTranslateMessage也就不会被调用。   [Page]
如果用PostMessage,则消息进入消息队列,由GetMessage取得,PreTranslateMessage就有机会进行处理。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/wzyzb/archive/2009/03/05/3959564.aspx

 

 

PeekMessage GetMessage和PumpMessage

1. GetMessage()可以理解为WaitForSingleObject变种,他的特点就是必须要等到一个消息,否则函数不返回 PeekMessage()立即返回,从他的返回值判断是否瞥到一个消息,是的话返回Non-Zero否则返回空值 此点类似于Windows的另外2消息相关函数: PostMessage 和SendMessage 2.

1. GetMessage()可以理解为WaitForSingleObject变种,他的特点就是必须要等到一个消息,否则函数不返回

    PeekMessage()立即返回,从他的返回值判断是否瞥到一个消息,是的话返回Non-Zero否则返回空值

    此点类似于Windows的另外2消息相关函数:

     PostMessage 和SendMessage

2. PeekMessage()可由参数控制是否将瞥到的Msg从消息队列移除

                  wRemoveMsg = PM_NOREMOVE  不移除

                  wRemoveMsg = PM_REMOVE   移除

    而GetMessage()执行后消息肯定从消息队列移除

    但是有点需要注意,对于WM_PAINT消息,执行PeekMessage函数,就算传入PM_REMOVE,消息也不会从消息队列移除,而GetMessage也不会移除WM_PAINT消息,它只有在被成功处理后才会从消息队列Remove

3. GetMessage返回值Non-zero时,证明获得一个非WM_QUIT消息,Zero证明获得WM_QUIT。所以GetMessage一个典型的应用就是通过其返回值来决定是否要结束消息循环进而结束主程序

4. GetMessage和PeekMessage可以协作使用,用来Pump Message

    PumpMessage(void)

 

 

{

 

MSG msg;

while(::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))

 

{

 

BOOL bRet = GetMessage(&msg, NULL, 0, 0);

if(bRet > 0)

 

{

 

TranslateMessage(&msg);

 

DispatchMessage(&msg);

 

else if(0 == bRet)

 

PostQuitMessage(0);

 

else

// Error, ignored

}

}

}

此函数可用来延续消息循环(在消息循环不小心被阻塞了时),比如在多线程编程时,经常会用到MsgWaitForMultipleObjects来等待某个核心对象进入激发状态,包括调用线程接受到消息时,而在接收到线程消息时,必须要延续此消息给Windows系统,这时就要用到PumpMessage了,下面是例程:

Handle hHandle;

 

DWORD result = MsgWaitForMultipleObjects(1, &m_hHandle, FALSE, INFINITE, QS_ALLINPUT);

if(result ==(WAIT_OBJECT_0 + 1))

 

{

PumpMessage();

}

 

 

 

 

{

}

{

}

void