设为首页收藏本站language 语言切换
查看: 2520|回复: 0
收起左侧

深入剖析WTL—WTL消息循环机制详解

[复制链接]
发表于 2010-2-25 10:26:20 | 显示全部楼层 |阅读模式
<p >在分析应用程序线程封装的时候,我们介绍了线程会创建一个CMessageLoop对象来处理消息循环,但没有仔细分析这个对象是怎样处理消息循环的。这里我们要详细分析一下WTL中的消息循环机制。<p >WTL消息循环机制实现了消息过滤和空闲处理机制。<p ><center><font color="#000099"><strong>消息过滤</strong></font></center><p >首先看一下CMessageLoop的核心逻辑CMessageLoop.Run()的代码:<p ><ccid_nobr><table align="center" border="1" bordercolordark="#FFFFFF" bordercolorlight="black" cellpadding="2" cellspacing="0" width="550"><tr><td bgcolor="e6e6e6" class="code"><pre><ccid_code>int CMessageLoop.Run()        {                BOOL bDoIdle = TRUE;                int nIdleCount = 0;                BOOL bRet;                for(;;)                {        while(!:eekMessage(&amp;amp;#38;m_msg, NULL, 0, 0, PM_NOREMOVE) &amp;amp;#38;&amp;amp;#38; bDoIdle)                        {                if(!OnIdle(nIdleCount++))                        bDoIdle = FALSE;                        }        bRet = ::GetMessage(&amp;amp;#38;m_msg, NULL, 0, 0);                if(bRet == -1)                {        ATLTRACE2(atlTraceUI, 0, _T(&amp;quot;::GetMessage returned -1 (error)\n&amp;quot;));                continue;        // error, don't process                }        else if(!bRet)        {        ATLTRACE2(atlTraceUI, 0, _T(&amp;quot;CMessageLoop::Run - exiting\n&amp;quot;));                break;                // WM_QUIT, exit message loop        }        if(!PreTranslateMessage(&amp;amp;#38;m_msg))                {                ::TranslateMessage(&amp;amp;#38;m_msg);                :ispatchMessage(&amp;amp;#38;m_msg);                }        if(IsIdleMessage(&amp;amp;#38;m_msg))        {                bDoIdle = TRUE;                nIdleCount = 0;                }        }        return (int)m_msg.wParam;        }</ccid_code></pre></td></tr></table></ccid_nobr><p >在上面的代码中,有三个需要注意的地方。<p >消息循环中,首先调用PeekMessage()判断消息队列中是否有消息。如果没有,则调用OnIdle()函数。这就是调用空闲处理。<p >第二个注意点是,如果有消息,则调用GetMessage()得到消息。然后做判断,如果是错误返回,则对消息并不进行处理。然后再判断是否是WM_QUIT消息,如果是,则退出消息循环,从而结束该界面线程。<p >接下来是第三个注意点。在TranslateMessage()消息之前,调用了成员函数PreTranslateMessage()。这为在TranslateMessage()之前对消息进行处理提供了机会。<p >reTranslateMessage()会遍历CMessageLoop中所有CMessageFilterd对象的PreTranslateMessage()函数,直到其中一个返回为TRUE或它们都返回为FALSE。当有一个返回为TRUE时,即对消息处理了,那么,就不再调用TranslateMessage(),而是进入下一个循环。<p >这种消息过滤机制提供了一种在不同窗口之间传递消息的机制。<p >CMessageFilter是一个C++的接口,即只定义了抽象虚拟函数。<p ><ccid_nobr><table align="center" border="1" bordercolordark="#FFFFFF" bordercolorlight="black" cellpadding="2" cellspacing="0" width="550"><tr><td bgcolor="e6e6e6" class="code"><pre><ccid_code>class CMessageFilter {public:        virtual BOOL PreTranslateMessage(MSG* pMsg) = 0;};</ccid_code></pre></td></tr></table></ccid_nobr><p >这样,任何类想要实现消息过滤,只需实现这个接口。在C++中就采用继承。然后再实现PreTranslateMessage()函数即可。<p >ATL/WTL App Wizard生成的框架窗口中实现PreTranslateMessage()的代码如下:<p ><ccid_nobr><table align="center" border="1" bordercolordark="#FFFFFF" bordercolorlight="black" cellpadding="2" cellspacing="0" width="550"><tr><td bgcolor="e6e6e6" class="code"><pre><ccid_code>BOOL CMainFrame:reTranslateMessage(MSG* pMsg){        if(CFrameWindowImpl&amp;lt;CMainFrame&amp;gt;:reTranslateMessage(pMsg))                return TRUE;        return m_view.PreTranslateMessage(pMsg);}</ccid_code></pre></td></tr></table></ccid_nobr><p >这种消息过滤机制的好处是任何实现了CMessageFilter接口的对象,都可以接受消息过滤。<p >程序通过AddMessageFilter()和RemoveMessageFilter()把这些对象加入到CMessageLoop中。<p ><center><font color="#000099"><strong>空闲处理</strong></font></center><p >空闲处理的机制和消息过滤类似。这里不再介绍。我们要把主要经历放在WTL的框架窗口分析上。稍后,我们将进入这部分内容。<p >(责任编辑:Sunny)                                 <p align="center"></p></p>
您需要登录后才可以回帖 登录 | 论坛注册

本版积分规则

QQ|Archiver|手机版|小黑屋|sitemap|鸿鹄论坛 ( 京ICP备14027439号 )  

GMT+8, 2025-4-12 01:11 , Processed in 0.179494 second(s), 23 queries , Redis On.  

  Powered by Discuz!

  © 2001-2025 HH010.COM

快速回复 返回顶部 返回列表