Chinaunix首页 | 论坛 | 博客
  • 博客访问: 14490721
  • 博文数量: 5645
  • 博客积分: 9880
  • 博客等级: 中将
  • 技术积分: 68081
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-28 13:35
文章分类

全部博文(5645)

文章存档

2008年(5645)

我的朋友

分类:

2008-04-28 20:52:03

下载本文示例代码
  MFC中的窗口创建及窗口消息映射   我经常碰到有人问我有关窗口创建的问题,他们经常把用HWND描述的系统窗口对象和用CWnd描述的MFC的窗口对象混淆不清。这两者之间是紧密联系在一起的,但是MFC为了自身的管理,在CWnd中加了一些额外的内容,包括如何从HWND生成CWnd。  在MFC中,有几种典型的窗口对象,CWnd描述的一般窗口对象,CView描述的视图对象,CFrameWnd描述的SDI框窗对象,CMDIFrameWnd描述的MDI框窗对象等等。在这一章中,主要讨论下述内容:  MFC中窗口的创建  MFC的消息映射机制(MESSAGE MAP)  对于上面两点MFC的设计者们使用了很高的技巧来确保应用程序的代码尽可能小,其中的技巧和隐藏在它们背后的思想值得我们学习。下面对各项内容进行讨论。  MFC中窗口的创建  在Window下,创建窗口可以使用两个函数,CreateWindow()和CreateWindowEx(),它们都需要一个参数,这个参数是标识窗口类的字符串。所以,如果要创建窗口,一般的做法是,先使用RegisterClass()或RegisterClassEx()注册一个窗口类,然后使用该窗口类来创建窗口。在前面我也提到过,注册窗口类的最主要目的是为系统提供窗口函数的地址,以便被DispatchMessage()之类的函数回。  在MFC中,创建窗口的函数是CWnd或其派生类的Create()或CreateEx方法,注册窗口类一般使用AfxRegisterWndClass(),在这个全局函数中,并没有发现窗口函数地址这样的参数,因此脑子里自然就会有这样的问题:窗口函数在哪里?它是如何同窗口关联的?下面我们将对MFC的一些与此有关的代码进行仔细分析,回答上述两个问题。  窗口函数  在MFC中,有一个全局的函数AfxWndProc(),正如下面的注释所示,它就是CWnd及所有从它派生的窗口类的窗口函数,它的实现如下:  // The WndProc for all CWnd's and derived classes  LRESULT CALLBACK  AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)  {   // special message which identifies the window as using AfxWndProc   if (nMsg == WM_QUERYAFXWNDPROC)   return 1;   // all other messages route through message map   CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);   ASSERT(pWnd != NULL);   ASSERT(pWnd->m_hWnd == hWnd);   return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);  }  AfxCallWndProc()调用pWnd对象的虚拟函数WindowProc(),它的代码如下:  LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)  {   // 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;  }上面的代码中,OnWndMsg()是用来处理该窗口消息的函数,如果某条消息没有被OnWndMsg()处理,也就是该窗口没有提供处理该消息的函数,它就调用DefWindowProc()进行处理,DefWindowProc()也是一个虚拟函数,看看它的代码:  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)    return ::DefWindowProc(m_hWnd, nMsg, wParam, lParam);   else   return ::CallWindowProc(pfnWndProc, m_hWnd, nMsg, wParam, lParam);  }DefWindowProc()的策略很简单,调用基类的窗口函数m_pfnSuper来处理该消息。  通过上面的分析,可以得出这样的结论:与其说AfxWndProc()是MFC的唯一窗口函数,还不如说AfxWndProc()是MFC的窗口消息分发中心。正是由于有了这个消息分发中心,才使得MFC的应用程序能够用有限的几个窗口类,作出各种形形色色的窗口,使得在应用程序中,增加CWnd的派生类,并不增加系统中窗口类的个数,将对系统资源的使用控制在一个稳定的范围之内。  注册窗口类除了提供窗口函数外,还指定该窗口的一些外观,如是否有标题条,窗口缺省背景等等。在MFC框架中,有框窗、视图和控制条(CControlBar)等,它们除了操作行为不同外,外观等也不相同,所以MFC注册了几种缺省的窗口类。在MFC中,有一个全局函数AfxEndDeferRegisterClass(LONG fToRegister),它用来注册MFC预定义的窗口类,包括同框窗、视图所对应的窗口类。由于它的代码占的篇幅很长,而且实现也很简单,所以就不列出它的代码了,如果你有兴趣,可以在wincore.cpp中找到它的实现代码。共2页。 1 2 8 :   MFC中的窗口创建及窗口消息映射   我经常碰到有人问我有关窗口创建的问题,他们经常把用HWND描述的系统窗口对象和用CWnd描述的MFC的窗口对象混淆不清。这两者之间是紧密联系在一起的,但是MFC为了自身的管理,在CWnd中加了一些额外的内容,包括如何从HWND生成CWnd。  在MFC中,有几种典型的窗口对象,CWnd描述的一般窗口对象,CView描述的视图对象,CFrameWnd描述的SDI框窗对象,CMDIFrameWnd描述的MDI框窗对象等等。在这一章中,主要讨论下述内容:  MFC中窗口的创建  MFC的消息映射机制(MESSAGE MAP)  对于上面两点MFC的设计者们使用了很高的技巧来确保应用程序的代码尽可能小,其中的技巧和隐藏在它们背后的思想值得我们学习。下面对各项内容进行讨论。  MFC中窗口的创建  在Window下,创建窗口可以使用两个函数,CreateWindow()和CreateWindowEx(),它们都需要一个参数,这个参数是标识窗口类的字符串。所以,如果要创建窗口,一般的做法是,先使用RegisterClass()或RegisterClassEx()注册一个窗口类,然后使用该窗口类来创建窗口。在前面我也提到过,注册窗口类的最主要目的是为系统提供窗口函数的地址,以便被DispatchMessage()之类的函数回。  在MFC中,创建窗口的函数是CWnd或其派生类的Create()或CreateEx方法,注册窗口类一般使用AfxRegisterWndClass(),在这个全局函数中,并没有发现窗口函数地址这样的参数,因此脑子里自然就会有这样的问题:窗口函数在哪里?它是如何同窗口关联的?下面我们将对MFC的一些与此有关的代码进行仔细分析,回答上述两个问题。  窗口函数  在MFC中,有一个全局的函数AfxWndProc(),正如下面的注释所示,它就是CWnd及所有从它派生的窗口类的窗口函数,它的实现如下:  // The WndProc for all CWnd's and derived classes  LRESULT CALLBACK  AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)  {   // special message which identifies the window as using AfxWndProc   if (nMsg == WM_QUERYAFXWNDPROC)   return 1;   // all other messages route through message map   CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);   ASSERT(pWnd != NULL);   ASSERT(pWnd->m_hWnd == hWnd);   return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);  }  AfxCallWndProc()调用pWnd对象的虚拟函数WindowProc(),它的代码如下:  LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)  {   // 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;  }上面的代码中,OnWndMsg()是用来处理该窗口消息的函数,如果某条消息没有被OnWndMsg()处理,也就是该窗口没有提供处理该消息的函数,它就调用DefWindowProc()进行处理,DefWindowProc()也是一个虚拟函数,看看它的代码:  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)    return ::DefWindowProc(m_hWnd, nMsg, wParam, lParam);   else   return ::CallWindowProc(pfnWndProc, m_hWnd, nMsg, wParam, lParam);  }DefWindowProc()的策略很简单,调用基类的窗口函数m_pfnSuper来处理该消息。  通过上面的分析,可以得出这样的结论:与其说AfxWndProc()是MFC的唯一窗口函数,还不如说AfxWndProc()是MFC的窗口消息分发中心。正是由于有了这个消息分发中心,才使得MFC的应用程序能够用有限的几个窗口类,作出各种形形色色的窗口,使得在应用程序中,增加CWnd的派生类,并不增加系统中窗口类的个数,将对系统资源的使用控制在一个稳定的范围之内。  注册窗口类除了提供窗口函数外,还指定该窗口的一些外观,如是否有标题条,窗口缺省背景等等。在MFC框架中,有框窗、视图和控制条(CControlBar)等,它们除了操作行为不同外,外观等也不相同,所以MFC注册了几种缺省的窗口类。在MFC中,有一个全局函数AfxEndDeferRegisterClass(LONG fToRegister),它用来注册MFC预定义的窗口类,包括同框窗、视图所对应的窗口类。由于它的代码占的篇幅很长,而且实现也很简单,所以就不列出它的代码了,如果你有兴趣,可以在wincore.cpp中找到它的实现代码。共2页。 1 2 8 : 下载本文示例代码


进入MFC讲坛的前言(三)进入MFC讲坛的前言(三)进入MFC讲坛的前言(三)进入MFC讲坛的前言(三)进入MFC讲坛的前言(三)进入MFC讲坛的前言(三)进入MFC讲坛的前言(三)进入MFC讲坛的前言(三)进入MFC讲坛的前言(三)进入MFC讲坛的前言(三)进入MFC讲坛的前言(三)进入MFC讲坛的前言(三)进入MFC讲坛的前言(三)进入MFC讲坛的前言(三)进入MFC讲坛的前言(三)
阅读(67) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~