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

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

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


                     图9…5 画出FrameWnd 窗口收到命令消息后的四个尝试路径。第3章曾经以一个简单的 



                     DOS 程序仿真出这样的绕行路线。 



576 


…………………………………………………………Page 639……………………………………………………………

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



                          CWinThread       CWinApp       CMyWinApp 



                                                                  



                                               ; ; ; ; ;      ; ; ; ; ; 



                                             0;0;0;0;0;0    0;0;0;0;0;0 

                                                                          CView         CMyView 



                                                                                                           m 

                                                                                                            e 

    CCmdTarget              CWnd         CFrameWnd       CMyFrameWnd 

                                                                                                            s 

                                                                            ; ; ; ; ;      ; ; ; ; ; 

                                                                                                            s 

                                                                           0;0;0;0;0;0    0;0;0;0;0;0       a 



                               ; ; ; ; ;       ; ; ; ; ;      ; ; ; ; ; 

         ; ; ; ; ;                                                                                          g 

                             0;0;0;0;0;0     0;0;0;0;0;0    0;0;0;0;0;0          WM_MAND                 e 

       0;0;0;0;0;0 



                          CDocument     CMyDocument 



                                                    

                                                            当CMyFrameWnd 收到WM_MAND , 



                                                            消息唧筒尝试数种绕行路线,使命令消息有 

                               ; ; ; ; ;       ; ; ; ; ;    机会经过任何一个类别。图中的     



                             0;0;0;0;0;0     0;0;0;0;0;0    即绕行的优先次序(请参考图9…4 )。 



          图9…5 FrameWnd 窗口收到命令消息后的四个尝试路径。第 3 章曾经以一 



                 个简单的DOS 程序仿真出这样的绕行路线。 



OnCmdMsg 是各类别专门用来对付命令消息的函数。每一个「可接受命令消息之对象」 



 (mand Target )在处理命令消息时都会(都应该)遵循一个游戏规则:调用另一个 



目标类别的OnCmdMsg 。这才能够将命令消息传送下去。如果说AfxWndProc  是消息流 



动的「唧筒」,各类别的OnCmdMsg 就是消息流动的「转辙器」。 



以下我举一个具体例子。假设命令消息从Scribble 的【Edit/Clear All 】发出,其处理常 



式位在CScribbleDoc,下面是这个命令消息的流浪过程: 



                                                                                                             577 


…………………………………………………………Page 640……………………………………………………………

                第篇    深入  MFC  程式設計 



                 1。 MDI 主窗口( CMDIFrameWnd ) 收到命令消息WM_MAND, 其ID 为 



                  ID_EDIT_CLEAR_ALL 。 



                 2。 MDI 主窗口把命令消息交给目前作用中的MDI 子窗口(CMDIChildWnd)。 



                 3。 MDI 子窗口给它自己的子窗口(也就是View )一个机会。 



                 4。 View 检查自己的Message Map 。 



                 5。 View 发现没有任何处理例程可以处理此命令消息,只好把它传给Document 。 



                 6。 Document 检查自己的Message Map ,它发现了一个吻合项: 



                   BEGIN_MESSAGE_MAP(CScribbleDoc; CDocument) 



                       ON_MAND(ID_EDIT_CLEAR_ALL; OnEditClearAll) 



                       。。。 



                   END_MESSAGE_MAP() 



                 于是调用该函数,命令消息的流动路线也告终止。 



                 如果上述的步骤6 仍没有找到处理函数,那么就: 



                 7。 Document 把这个命令消息再送到Document Template 对象去。 



                 8。 还是没被处理,于是命令消息回到View 。 



                 9。 View 没有处理,于是又回给MDI 子窗口本身。 



                10。 传给CWinApp 对象…无主消息的终极归属。 



                 图9…6 是构成「消息邦浦」之各个函数的调用次序。此图可以对前面所列之各个 



                 源代码组织出一个大局观来。 



578 


…………………………………………………………Page 641……………………………………………………………

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



          AfxWndProc 

           AfxWndProc 

                                  message 



        AfxCallWndProc 

         AfxCallWndProc 



       CWnd::WindowProc 

       CWnd::WindowProc 



       CWnd::OnWndMsg 

        CWnd::OnWndMsg                                     ::DefWindowProc 

                           CWnd::DefWindowProc             ::DefWindowProc 

                           CWnd::DefWindowProc 



                                                         AfxFindMessageEntry 

 WM_MAND               regular window message         AfxFindMessageEntry 



 CFrameWnd::Onmand 

 CFrameWnd::Onmand 

                                                            msg handler 



      CWnd::Onmand 

       CWnd::Onmand 



  CFrameWnd::OnCmdMsg 

  CFrameWnd::OnCmdMsg 



              

                                           

       CView::OnCmdMsg 

        CView::OnCmdMsg                          CWnd::OnCmdMsg             

                                                 CWnd::OnCmdMsg 

                                              (CCmdTarget::OnCmdMsg) 

                                             (CCmdTarget::OnCmdMsg) 



   CWnd::OnCmdMsg          CDocument::OnCmdMsg 

    CWnd::OnCmdMsg         CDocument::OnCmdMsg                      CWinApp::OnCmdMsg 

                                                                    CWinApp::OnCmdMsg 

(CCmdTarget::OnCmdMsg) 

(CCmdTarget::OnCmdMsg)                                            (CCmdTarget::OnCmdMag) 

                                                                  (CCmdTarget::OnCmdMag) 

                           CCmdTarget::OnCmdMsg 

                            CCmdTarget::OnCmdMsg 

        DispatchCmdMsg 

        DispatchCmdMsg 

                                                  DispatchCmdMsg       DispatchCmdMsg 

                                                   DispatchCmdMsg      DispatchCmdMsg 

                              DispatchCmdMsg 

                              DispatchCmdMsg 

       msg handler   FALSE                                      FALSE                FALSE 

                                           FALSE  msg handler          msg handler 

                             msg handler 



           图9…6 构成 「消息邦浦」之各个函数的调用次序 



                                                                                         579 


…………………………………………………………Page 642……………………………………………………………

                 第篇    深入  MFC  程式設計 



             罗塞达碑石:AfxSig_xx 的奥秘 



                大架构建立起来了,但我还没有很仔细地解释在消息映射「网」中的_messageEntries '' 



                数组内容。为什么消息经由推动引擎(上一节谈的那整套家伙)推过这些数组,就可以 



                找到它的处理例程? 



                Paul DiLascia 在他的文章(! ¨ Meandering Through the Maze of MFC Message and mand 



                Routing!  ¨,Microsoft Systems Journal ,1995/07)中形容这些数组之内一笔一笔的记录像 



                是罗塞达碑石,呵呵,就靠它们揭开消息映射的最后谜底了。 



                 罗塞达碑石(Rosetta Stone ),1799 年拿破仑远征埃及时,由一名官员在尼罗河口罗塞 



                 达发现,揭开了古埃及象形文字之谜。石碑是黑色玄武岩,高114 公分,厚28 公分,宽 



                 72 公分。经法国学者Jean…Francois Champollion 研究后,世人因得顺利研读古埃及文献。 



                 消息映射表的每一笔记录是这样的形式: 



                 struct AFX_MSGMAP_ENTRY 

                 { 

                     UINT nMessage;   // windows message 

                     UINT nCode;      // control code or WM_NOTIFY code 

                     UINT nID;        // control ID (or 0 for windows messages) 

                     UINT nLastID;    // used for entries specifying a range of control id's 

                     UINT nSig;       // signature type (action) or pointer to message # 

                     AFX_PMSG pfn;    // routine to call (or special value) 

                 }; 



                 内中包括一个Windows 消息、其控制组件ID  以及通告码(notification code ,对消息的 



                 更多描述,例如EN_CHANGED 或CBN_DROPDIOWN 等)、一个签名记号、以及一个 



                 CCmdTarget 衍生类别的成员函数。任何一个ON_ 宏会把这六个项目初始化起来。例 



                 如: 



                 #define ON_WM_CREATE ()  

                   { WM_CREATE; 0; 0; 0; AfxSig_is;  

                     (AFX_PMSG)(AFX_PMSGW)(int (AFX_MSG_CALL CWnd::*)(LPCREATESTRUCT))OnCreate }; 



                 你看到了可怕的类型转换动作,这完全是为了保持类型安全(type…safe )。 



580 


…………………………………………………………Page 643……………………………………………………………

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



有一个很莫名其妙的东西:AfxSig_ 。要了解它作什么用,你得先停下来几分钟,想想另 



一个问题:当上一节的推动引擎比对消息并发现吻合之后,就调用对应的处理例程,但 



它怎么知道要交给消息处理例程哪些参数呢?要知道,不同的消息处理例程需要不同的 



参数(包括个数和类型),而其函数指针(AFX_PMSG )却都被定义为这付德行: 



   typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void); 



这么简陋的信息无法表现应该传递什么样的参数,而这正是AfxSig_ 要贡献的地方。当 



推动引擎比对完成,欲调用某个消息处理例程lpEntry…》pfn 时,动作是这样子地(出现 



在CWnd::OnWndMsg 和DispatchCmdMsg  中): 



 union MessageMapFunctions mmf; 

 mmf。pfn = lpEntry…》pfn; 



 switch (lpEntry…》nSig) 

 { 

 case AfxSig_is: 

         lResult = (this…》*mmf。pfn_is)((LPTSTR)lParam); 

         break; 



 case AfxSig_lwl: 

         lResult = (this…》*mmf。pfn_lwl)(wParam; lParam); 

         break; 



 case AfxSig_vv: 

         (this…》*mmf。pfn_vv)(); 

         break; 

 。。。 

 } 



注意两样东西:MessageMapFunctions 和AfxSig_ 。AfxSig_ 定义于AFXMSG_。H 档: 



 enum AfxSig 

 { 

         AfxSig_end = 0;     // 'marks end of message map' 



         AfxSig_bD;      // BOOL (CDC*) 

         AfxSig_bb;      // BOOL (BOOL) 

         AfxSig_bWww;    // BOOL (CWnd*; UINT; UINT) 

         AfxSig_hDWw;    // HBRUSH (CDC*; CWnd*; UINT) 

         AfxSig_hDw;     // HBRUSH (CDC*; UINT) 



                                                                                      581 


…………………………………………………………Page 644……………………………………………………………

                   第篇    深入  MFC  程式設計 



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