PeekMessage与GetMessage PumpMessage()

通过GetMessagePeekMessage函数得到消息并推动消息的处理!

其函数原型如下:

//thrdcore.cpp  BOOL CWinThread::PumpMessage() 

{  ASSERT_VALID(this);  //如果是WM_QUIT就退出函数(return FALSE),这将导致程序结束

                           if (!::GetMessage(&m_msgCur, NULL, NULL, NULL)) 

             { 

              #ifdef _DEBUG  if (afxTraceFlags & traceAppMsg)   TRACE0("CWinThread::PumpMessage - Received WM_QUIT.n");                                                       m_nDisablePumpCount++; // application must die  // Note: prevents calling message loop things in 'ExitInstance'  // will never be decremented  #endif  return FALSE;       } 

           #ifdef _DEBUG  if (m_nDisablePumpCount != 0)    

  {  TRACE0("Error: CWinThread::PumpMessage called when not permitted.n");  ASSERT(FALSE);      }  

#endif 

#ifdef _DEBUG  if (afxTraceFlags & traceAppMsg)  

_AfxTraceMsg(_T("PumpMessage"), &m_msgCur);  #endif  // process this message  if (m_msgCur.message != WM_KICKIDLE && !PreTranslateMessage(&m_msgCur)) 

    {  ::TranslateMessage(&m_msgCur); //键转换  ::DispatchMessage(&m_msgCur);  //派送消息  } 

}

所以,PumpMessage是一个“消息泵”,它其实就是调用GetMessage函数从消息队列中取出一个消息并从队列中删除此消息,然后使用 TranslateMessage 转换消息之后将消息派送出去 DispatchMessage。
注意GetMessagePeekMessage有所区别,这里比较适合用GetMessage取消息(当然使用PeekMessage也可以),两者区别详见: 《PeekMessage与GetMessage》

如下实例非对话框程序的消息循环机制

//thrdcore.cpp  // main running routine until thread exits  int CWinThread::Run()  {  ASSERT_VALID(this);        // for tracking the idle time state  BOOL bIdle = TRUE;  LONG lIdleCount = 0;  // acquire and dispatch messages until a WM_QUIT message is received.  for (;;) {  // phase1: check to see if we can do idle work  while (bIdle && !::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE))  {  // call OnIdle while in bIdle state  if (!OnIdle(lIdleCount++))  bIdle = FALSE; // assume "no idle" state  }       // phase2: pump messages while available      do {  // pump message, but quit on WM_QUIT  if (!PumpMessage())  return ExitInstance();         // reset "no idle" state after pumping "normal" message        if (IsIdleMessage(&m_msgCur))  {  bIdle = TRUE;  lIdleCount = 0;  }        } while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE)); 
   } //无限循环,退出条件是收到WM_QUIT消息。  ASSERT(FALSE); // not reachable  } 


这是一个无限循环,他的退出条件是收到WM_QUIT消息: 
if (!PumpMessage()) 
return ExitInstance();

PumpMessage中,如果收到WM_QUIT消息,那么返回FALSE,所以ExitInstance()函数执行,跳出循环,返回程序的退出代码。所以,一个程序要退出,只用在代码中调用函数

VOID PostQuitMessage( int nExitCode )。指定退出代码nExitCode就可以退出程序。

下面讨论一下这个函数Run的流程,分两步:

1,第一个内循环phase1bIdle代表程序是否空闲。他的意思就是,如果程序是空闲并且消息队列中没有要处理的消息,那么调用虚函数OnIdle进行空闲处理。在这个处理中将更新UI界面(比如工具栏按钮的enabledisable状态),删除临时对象(比如用FromHandle得到的对象指针。由于这个原因,在函数之间传递由FromHandle得到的对象指针是不安全的,因为他没有持久性)OnIdle是可以重载的,你可以重载他并返回TRUE使消息循环继续处于空闲状态。

NOTEMS用临时对象是出于效率上的考虑,使内存有效利用,并能够在空闲时自动撤销资源。关于由句柄转换成对象,可以有若干种方法。一般是先申明一个对象obj,然后使用obj.Attatch来和一个句柄绑定。这样产生的对象是永久的,你必须用obj.Detach来释放对象。

2 ,第二个内循环 phase2 。在这个循环内先启动 消息泵(PumpMessage) , 如果不是 WM_QUIT 消息, 消息泵将消息发送出去(::DispatchMessage) 。消息的目的地是消息结构中的 hwnd 字段所对应的窗口。

总结
PumpMessage起到消息泵的作用,其原理就是使用GetMessage或PeekMessage函数从消息队列中逐个读取消息,然后进行必要处理之后再发送出去。我们可以使用PumpMessage默认处理过程,当然也可以自己修改消息处理的方式。通常我们在我们自己设计窗口时也会自己设计消息循环方式,例如以下代码:

void CProgressWnd::PeekAndPump(BOOL bCancelOnESCkey /*= TRUE*/) { if (m_bModal && ::GetFocus() != m_hWnd) SetFocus(); MSG msg; while (::PeekMessage(&msg, NULL,0,0,PM_NOREMOVE)) { if (bCancelOnESCkey && (msg.message == WM_CHAR) && (msg.wParam == VK_ESCAPE)) OnCancel(); // Cancel button disabled if modal, so we fake it. if (m_bModal && (msg.message == WM_LBUTTONUP)) { CRect rect; m_CancelButton.GetWindowRect(rect); if (rect.PtInRect(msg.pt)) OnCancel(); } if (!AfxGetApp()->PumpMessage()) { ::PostQuitMessage(0); return; } } }

其中是指使用PumpMessage函数自己设计了消息处理过程,我们不需要知道PumpMessage函数内部做了什么处理(当然,经过之前的PumpMessage源码解析你也知道了),只要知道它就是消息处理的核心动力,起到取消息、转换消息并发送消息的作用就行了!而while循环的 :: PeekMessage (&msg, NULL,0,0, PM_NOREMOVE )只是检测消息队列中是否存在消息罢了( PM_NOREMOVE 说明了这一点),如果有消息就调用PumpMessage去消息并处理发送,若果消息队列为空则推出循环。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值