MFC中消息循环机制
2015-09-01 12:38
225 查看
在MFC中通过重载CWnd类中的虚拟函数PreTranslateMessage,可以改变消息控制流程。
只有经过消息队列的消息才受PreTranslateMessage的影响,使用SendMessage函数发送或其他类似方式直接向窗口发送消息是不经过消息队列的。
在消息处理函数中,不能处理WM_CHAR消息。
SetWindowText会发送WM_CHAR字符消息。
GetMessage在没有消息的时候等待消息,cpu占用率当然低。
PeekMessage没有消息的时候立刻返回,可以在没有消息的时候可以做其他处理,但cpu占用率一般较高。
因为游戏不能靠windows消息驱动,所以要用PeekMessage();
MFC通过CWinApp类中的Pumpmessage函数实现消息循环,但是实际的消息循环代码位于CWinThread中,CWinApp只是从CWinThread继承过来。
流程图:
其简化后的代码大概如下:
BOOL CWinThread::PumpMessage()
{
ASSERT_VALID(this);
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
returnFALSE;
}
#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);
}
returnTRUE;
}
BOOL CWinThread::PreTranslateMessage(MSG*pMsg)
{
ASSERT_VALID(this);
//if this is a thread-message, short-circuit this function
if(pMsg->hwnd == NULL && DispatchThreadMessageEx(pMsg))
returnTRUE;
//walk from target to main window
CWnd*pMainWnd = AfxGetMainWnd();
if(CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg))
returnTRUE;
//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)
returnpMainWnd->PreTranslateMessage(pMsg);
}
returnFALSE; // no special processing
}
BOOL CWinThread::PreTranslateMessage(MSG*pMsg)
{
ASSERT_VALID(this);
//if this is a thread-message, short-circuit this function
if(pMsg->hwnd == NULL && DispatchThreadMessageEx(pMsg))
returnTRUE;
//walk from target to main window
CWnd*pMainWnd = AfxGetMainWnd();
if(CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg))
returnTRUE;
//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)
returnpMainWnd->PreTranslateMessage(pMsg);
}
returnFALSE; // no special processing
}
BOOL CWnd::PreTranslateMessage(MSG* pMsg)
{
//handle tooltip messages (some messages cancel, some may cause it to popup)
AFX_MODULE_STATE*pModuleState = _AFX_CMDTARGET_GETSTATE();
if(pModuleState->m_pfnFilterToolTipMessage != NULL)
(*pModuleState->m_pfnFilterToolTipMessage)(pMsg,this);
//no default processing
returnFALSE;
}
windows消息队列把得到的消息发送到线程消息队列,线程消息队列每次取出一条消息发送到指定窗口,
只有经过消息队列的消息才受PreTranslateMessage的影响,使用SendMessage函数发送或其他类似方式直接向窗口发送消息是不经过消息队列的。
在消息处理函数中,不能处理WM_CHAR消息。
SetWindowText会发送WM_CHAR字符消息。
GetMessage在没有消息的时候等待消息,cpu占用率当然低。
PeekMessage没有消息的时候立刻返回,可以在没有消息的时候可以做其他处理,但cpu占用率一般较高。
因为游戏不能靠windows消息驱动,所以要用PeekMessage();
MFC通过CWinApp类中的Pumpmessage函数实现消息循环,但是实际的消息循环代码位于CWinThread中,CWinApp只是从CWinThread继承过来。
流程图:
其简化后的代码大概如下:
BOOL CWinThread::PumpMessage()
{
ASSERT_VALID(this);
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
returnFALSE;
}
#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);
}
returnTRUE;
}
BOOL CWinThread::PreTranslateMessage(MSG*pMsg)
{
ASSERT_VALID(this);
//if this is a thread-message, short-circuit this function
if(pMsg->hwnd == NULL && DispatchThreadMessageEx(pMsg))
returnTRUE;
//walk from target to main window
CWnd*pMainWnd = AfxGetMainWnd();
if(CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg))
returnTRUE;
//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)
returnpMainWnd->PreTranslateMessage(pMsg);
}
returnFALSE; // no special processing
}
BOOL CWinThread::PreTranslateMessage(MSG*pMsg)
{
ASSERT_VALID(this);
//if this is a thread-message, short-circuit this function
if(pMsg->hwnd == NULL && DispatchThreadMessageEx(pMsg))
returnTRUE;
//walk from target to main window
CWnd*pMainWnd = AfxGetMainWnd();
if(CWnd::WalkPreTranslateTree(pMainWnd->GetSafeHwnd(), pMsg))
returnTRUE;
//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)
returnpMainWnd->PreTranslateMessage(pMsg);
}
returnFALSE; // no special processing
}
BOOL CWnd::PreTranslateMessage(MSG* pMsg)
{
//handle tooltip messages (some messages cancel, some may cause it to popup)
AFX_MODULE_STATE*pModuleState = _AFX_CMDTARGET_GETSTATE();
if(pModuleState->m_pfnFilterToolTipMessage != NULL)
(*pModuleState->m_pfnFilterToolTipMessage)(pMsg,this);
//no default processing
returnFALSE;
}
windows消息队列把得到的消息发送到线程消息队列,线程消息队列每次取出一条消息发送到指定窗口,
相关文章推荐
- Java基础---网络编程
- hdu number sentense yt练手1002
- 0830练习:vim、find、特殊权限
- distinct和group by
- Dapper学习笔记(1)-开始
- 设计模式之facade模式
- Ubuntu 14.04 安装 Vmware Workstation 11
- Centos7安装Docker 1.8总结
- 显示当前元素位置
- Unreal Engine 4.9 Release Notes
- RAD Studio XE8 在APP里实现手机的拨号功能
- 洛谷 1004 dp或最大费用流
- centos下jdk升级
- Angular-UI自动完成输入框AutoComplete[项目中使用]
- 关于JSP页面的验证码简单实现
- 【leetcode每日一题】234.Palindrome Linked List
- hdu oj 1520 Anniversary party(树形dp入门)
- mysql-安装之cmake的编译安装(mysql 5.6以后需要cmake编译安装)
- swift总结1
- mysql-安装之CAMKE编译安装