博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MFC中PreTranslateMessage函数浅析
阅读量:2354 次
发布时间:2019-05-10

本文共 5293 字,大约阅读时间需要 17 分钟。

 作用:
   
   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继承过来。其简化后的代码大概如下: 


Title  
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(虽然也会调用其他函数,但是这个最为关键),其代码如下: 


Title
  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 。同时这里满足了虚函数层层条用的条件(1 自类窗口对象附值给父类指针,2 PreTranslateMessage为虚函数),所以这个循环是:从 "子类" --> "父类" 方向层层运行 PreTranslateMessage函数,再由 "子窗口" --> "父窗口" 层层运行,直到发现该消息在某个类中被 "return True" 才停止。


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

源码:

Title

BOOL CWinThread::PumpMessage()

{
  return AfxInternalPumpMessage();
}

BOOL AFXAPI AfxInternalPumpMessage()

{
 _AFX_THREAD_STATE *pState = AfxGetThreadState();

 if (!::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))

 {
#ifdef _DEBUG
  TRACE(traceAppMsg, 1, _T("CWinThread::PumpMessage - Received WM_QUIT.\n"));
   pState->m_nDisablePumpCount++; // application must die
#endif
  // Note: prevents calling message loop things in 'ExitInstance'
  // will never be decremented
  return FALSE;
 }

#ifdef _DEBUG

  if (pState->m_nDisablePumpCount != 0)
 {
   TRACE(traceAppMsg, 0, _T("Error: CWinThread::PumpMessage called when not permitted.\n"));
   ASSERT(FALSE);
 }
#endif

#ifdef _DEBUG

 _AfxTraceMsg(_T("PumpMessage"), &(pState->m_msgCur));
#endif

  // process this message

 if (pState->m_msgCur.message != WM_KICKIDLE && !AfxPreTranslateMessage(&(pState->m_msgCur)))

 {
  ::TranslateMessage(&(pState->m_msgCur));
  ::DispatchMessage(&(pState->m_msgCur));
 }
  return TRUE;
}
BOOL __cdecl AfxPreTranslateMessage(MSG* pMsg)
{
  CWinThread *pThread = AfxGetThread();
  if( pThread )
 return pThread->PreTranslateMessage( pMsg );
  else
 return AfxInternalPreTranslateMessage( pMsg );
}
BOOL CWinThread::PreTranslateMessage(MSG* pMsg)
{
 ASSERT_VALID(this);
 return AfxInternalPreTranslateMessage( pMsg );
}
BOOL AfxInternalPreTranslateMessage(MSG* pMsg)
{
// ASSERT_VALID(this);

 CWinThread *pThread = AfxGetThread();

 if( pThread )
 {
  // if this is a thread-message, short-circuit this function
  if (pMsg->hwnd == NULL && pThread->DispatchThreadMessageEx(pMsg))
   return TRUE;
 }

 // walk from target to main window

 CWnd* pMainWnd = AfxGetMainWnd();
 if (CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg))
  return TRUE;

 // in case of modeless dialogs, last chance route through main

 //   window's accelerator table
 if (pMainWnd != NULL)
 {
   CWnd* pWnd = CWnd::FromHandle(pMsg->hwnd);
   if (pWnd->GetTopLevelParent() != pMainWnd)
   return pMainWnd->PreTranslateMessage(pMsg);
 }

 return FALSE;   // no special processing

}

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: accelerato

rs)

  }

  // got to hWndStop window without interest

  if (hWnd == hWndStop)
   break;
 }
 return FALSE;       // no special processing
}

转载地址:http://ezytb.baihongyu.com/

你可能感兴趣的文章
CSS实现居中的7种方法
查看>>
Charles拦截不到请求
查看>>
gitlab/github 多账户下设置 ssh keys
查看>>
Mac版 charles安装与破解
查看>>
keydown、keypress、keyup的使用
查看>>
区块链是否做好了迎接法币的准备?为什么银行如此看好加密货币?
查看>>
加密货币--Cryptocurrency
查看>>
Myeclipse的不足之一,struts 配置 action
查看>>
input /button链接方法
查看>>
CSS,font-family,好看,常用,中文,字体(更新中)
查看>>
Redis---基础知识:数据类型、持久化机制、虚拟内存、高级特性、应用场景
查看>>
Python3---获取延迟、提前的时间、日期---datetime、time
查看>>
Python3+selenium+Chrome---获取表格(tbody)中数据(tr)的详细内容----a & td内容的获取
查看>>
Docker/Podman使用提高----Dockerfile的制作基础及常见的问题
查看>>
Jenkins持续部署---centos7+Docker+Github+Flask项目-------补丁篇
查看>>
C语言基础---指针数组----初始化方式&常量指针数组、指针常量数组
查看>>
C语言基础---数组、指针之间的相同与不同
查看>>
类的继承的应用场景
查看>>
python3 + selenium------Chrome和Firefox 驱动的使用和版本对应
查看>>
pycharm不同测试框架的设置、unittest测试案例
查看>>