友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
第三电子书 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

深入浅出MFC第2版(PDF格式)-第105部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!


                   { 

                     LRESULT lResult; 

                     。。。 

                     TRY 

                     { 

                        。。。 

                        lResult = pWnd…》WindowProc (message; wParam; lParam); 

                     } 

                     。。。 

                     return lResult; 

                   } 



                  MFC 2。5  的CWinApp::Run 调用PumpMessage ,后者又调用::DispatchMessage ,把消息源 



                  源推往AfxWndProc    (如上),最后流向pWnd…》WindowProc  去。拿SDK 程序的本质来 



                  做比对,这样的逻辑十分容易明白。 



                  MFC 4。x 仍旧使用AfxWndProc  作为消息唧筒的起点,但其间却隐藏了许多关节。 



                  但愿你记忆犹新,第6章曾经说过,MFC 4。x 适时地为我们注册Windows 窗口类别(在 



                  第一次产生该种型式之窗口之前)。这些个Windows 窗口类别的窗口函数各是「窗口所 



                  对应之C++ 类别中的DefWindowProc 成员函数」,请参考第 6章 「CFrameWnd::Create 



                  产生主窗口」一节。这就和MFC 2。5  的作法(所有窗口类别共享同一个窗口函数)有了 



                  明显的差异。那么,推动消息的心脏,也就是CWinThread::PumpMessage  中调用 



                  的::DispatchMessage (请参考第 6章 「CWinApp::Run 程序生命的活水源头」一节), 



                  照说应该把消息唧到对应之C++ 类别的DefWindowProc 成员函数去。但是,我们发现 



                  MFC 4。x  中仍然保有和MFC 2。5 相同的AfxWndProc ,仍然保有AfxCallWndProc ,而且 



                  它们扮演的角色也没有变。 



562 


…………………………………………………………Page 625……………………………………………………………

                                                   第9章   訊息映射與命令繞行   



事实上,MFC 4。x  利用hook ,把看似无关的动作全牵联起来了。所谓hook ,是Windows 



程序设计中的一种高阶技术。通常消息都是停留在消息队列中等待被所隶属之窗口抓 



取,如果你设立hook ,就可以更早一步抓取消息,并且可以抓取不属于你的消息,送往 



你设定的一个所谓「滤网函数(filter )」。 



请查阅Win32 API 手册中有关于SetWindowsHook 和SetWindowsHookEx 两函数,以获 



得更多的hook 信息。(可参考Windows 95           A Developer s Guide 一书第6章Hooks ) 



MFC 4。x  的hook 动作是在每一个CWnd 衍生类别之对象产生之际发生,步骤如下: 



// in WINCORE。CPP (MFC 4。x) 



// 请回顾第6章「CFrameWnd::Create产生主窗口」一节 



BOOL CWnd::CreateEx(。。。) 

 { 

     。。。 

     PreCreateWindow(cs);   // 第6章曾经详细讨论过此一函数。 

     AfxHookWindowCreate(this); 

     HWND hWnd = ::CreateWindowEx(。。。); 

     。。。 

 } 



                  (        ) 

 // in WINCORE。CPP  MFC 4。x 

void AFXAPI AfxHookWindowCreate(CWnd* pWnd) 

 { 

    。。。 

    pThreadState…》m_hHookOldCbtFilter =  ::SetWindowsHookEx(WH_CBT; 

            _AfxCbtFilterHook; NULL; ::GetCurrentThreadId()); 

    。。。 

 } 



 WH_CBT 是众多hook 类型中的一种,意味着安装一个puter…Based Training  (CBT ) 



 滤网函数。安装之后,Windows 系统在进行以下任何一个动作之前,会先调用你的滤网 



 函数: 



令一个窗口成为作用中的窗口(HCBT_ACTIVATE ) 



产生或摧毁一个窗口(HCBT_CREATEWND 、HCBT_DESTROYWND ) 



最大化或最小化一个窗口(HCBT_MINMAX ) 



                                                                                563 


…………………………………………………………Page 626……………………………………………………………

                    第篇    深入  MFC  程式設計 



                      搬移或缩放一个窗口(HCBT_MOVESIZE ) 



                      完成一个来自系统菜单的系统命令(HCBT_SYSTEMMAND ) 



                      从系统队列中移去一个鼠标或键盘消息 (HCBT_KEYSKIPPED  、 



                       HCBT_CLICKSKIPPED ) 



                    因此,经过上述hook 安装之后,任何窗口即将产生之前,滤网函数_AfxCbtFilterHook  一 



                    定会先被调用: 



                    _AfxCbtFilterHook(int code; WPARAM wParam; LPARAM lParam) 

                     { 

                        _AFX_THREAD_STATE* pThreadState = AfxGetThreadState(); 

                        if (code != HCBT_CREATEWND) 

                        { 

                                // wait for HCBT_CREATEWND just pass others on。。。 

                                return CallNextHookEx(pThreadState…》m_hHookOldCbtFilter; code; 

                                        wParam; lParam); 

                        } 

                        。。。 

                                if (!afxData。bWin31) 

                                { 

                                        // perform subclassing right away on Win32 

                                        _AfxStandardSubclass((HWND)wParam); 

                                } 

                                else 

                                { 

                                   。。。 

                                } 

                        。。。 

                        LRESULT lResult = CallNextHookEx(pThreadState…》m_hHookOldCbtFilter; code; 

                                wParam; lParam); 

                        return lResult; 

                     } 



                    void AFXAPI _AfxStandardSubclass(HWND hWnd) 

                     { 

                        。。。 

                        // subclass the window with standard AfxWndProc 

                        oldWndProc = (WNDPROC)SetWindowLong (hWnd; GWL_WNDPROC; 

                                (DWORD)AfxGetAfxWndProc ()); 

                     } 



                    WNDPROC AFXAPI AfxGetAfxWndProc() 

                     { 



564 


…………………………………………………………Page 627……………………………………………………………

                                                         第9章   訊息映射與命令繞行   



    。。。 

    return &AfxWndProc; 

} 



啊,非常明显,上面的函数合力做了偷天换日的勾当:把「窗口所属之Windows 窗口类 



别」中所记录的窗口函数,改换为AfxWndProc 。于是,::DispatchMessage 就把消息源源 



推往AfxWndProc  去了。 



这种看起来很迂回又怪异的作法,是为了包容新的3D Controls                         (细节就容我省略了吧), 



并与MFC 2。5 兼容。下图把前述的hook 和subclassing 动作以流程图显示出来: 



  CFrameWnd::LoadFrame 

   CFrameWnd::LoadFrame 



    CFrameWnd::Create 

     CFrameWnd::Create 



      CWnd::CreateEx 

       CWnd::CreateEx                              安装WH_CBT hook ,设定滤网函数 



                                                   为_AfxCbtFilterHook 

                      AfxHookWindowCreate(this) 

                       AfxHookWindowCreate(this) 



                        ::SetWindowsHookEx(WH_CBT; _AfxCbtFilterHook ;。。。) 

                         ::SetWindowsHookEx(WH_CBT; _AfxCbtFilterHook ;。。。) 



     ::CreateWindowEx 

      ::CreateWindowEx 



                        _AfxCbtFilterHook     窗口产生之前一刻,由于曾安装过 

                         _AfxCbtFilterHook     WH_CBT hook,所以滤网函数 



                                              _AfxCbtFilterHook 会先被唤起。 

                       _AfxStandardSubclass 

                       _AfxStandardSubclass 



                     SetWindowLong(hWnd; GWL_WNDPROC;&AfxWndProc) 

                      SetWindowLong(hWnd; GWL_WNDPROC;&AfxWndProc) 



                                                             WND structure 

                                         subclassing 动作;改                   各种消息,来自 

                                           变窗口函数。              extra bytes ::DispatchMessage 



                message mapping and                                        的唧送,或由操作 

                   mand routing                                         系统直接送达。 



                (through message map)                                      CWL_WNDPROC 

                       。 

                                                             &AfxWndProc 



    message handler 

     message handler 



                                                                                         565 


…………………………………………………………Page 628……………………………………………………………

                  第篇    深入  MFC  程式設計 



                  不能稍息,我们还没有走出迷宫!AfxWndProc  只是消息两万五千里长征的第一站! 



           两万五千里长征消息的流动 



                  一个消息从发生到被攫取,直至走向它的归宿,是一条漫漫长路。上一节我们来到了漫 



                  漫长路的起头AfxWndProc ,这一节我要带你看看消息实际上如何推动。 



                  消息的流动路线已隐隐有脉络可寻, 此脉络是指由BEGIN_MESSAGE_MAP 和 



                  END_MESSAGE_MAP  以及许许多多ON_ WM_xxx 宏所构成的消息映射网。但是唧筒与 



                  方向盘是如何设计的?一切的线索还是要靠源代码透露: 



                                     (       ) 

                  // in WINCORE。CPP  MFC 4。x 

                  LRESULT CALLBACK AfxWndProc (HWND hWnd; UINT nMsg; WPARAM wParam; LPARAM lParam) 

                   { 

                          。。。 

                          // messages route through message map 

                          CWnd* pWnd = CWnd::FromHandlePermanent(hWnd); 

                          return AfxCallWndProc (pWnd; hWnd; nMsg; wParam; lParam); 

                   } 



                  LRESULT AFXAPI AfxCallWndProc (CWnd* pWnd; HWND hWnd; UINT nMsg; 

                          WPARAM wParam = 0; LPARAM lParam = 0) 

                   { 

                      。。。 

                      // delegate to object's WindowProc 

                      lResult = pWnd…》WindowProc (nMsg; wParam; lParam); 

                      。。。 

                      return lResult; 

                   } 



                  整个MFC  中,拥有虚拟函数WindowProc 者包括CWnd、CControlBar、COleControl、 



                  COlePropertyPage、CDialog、CReflectorWnd、CParkingWnd。一般窗口(例如Frame 视 



                  窗、View 窗口)都衍生自CWnd,所以让我们看看CWnd::WindowProc。这个函数相当 



                  于C++  中的窗口函数: 



                                     (       ) 

                  // in WINCORE。CPP  MFC 4。x 

                  LRESULT CWnd::WindowProc (UINT message; WPARAM wParam; LPARAM lParam) 



566 


…………………………………………………………Page 629……………………………………………………………

                                                           第9章   訊息映射與命令繞行   



     { 

             // OnWndMsg does most of the work; except for DefWindowProc call 

             LRESULT lResult = 0; 

             if (!OnWndMsg (message; wParam; lParam; &lResult)) 

                     lResult = DefWindowProc (message; wParam; lParam); 

             return lResult; 

     } 



     LRESULT CWnd::DefWindowProc (UINT nMsg; WPARAM wParam; LPARAM lParam) 

     { 

         if (m_pfnSuper != NULL) 

                 return ::CallWindowProc(m_pfnSuper; m_hWnd; nMsg; wParam; lParam); 



         WNDPROC pfnWndProc; 

         if ((pfnWndProc = *GetSuperWndProcAddr()) == NULL) 

          
返回目录 上一页 下一页 回到顶部 0 0
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!