窗口类的诞生(注册自己的窗口类)

 
一.什么是窗口类
    Windows 中运行的程序,大多数都有一个或几个可以看得见的窗口,而在这些窗口被创建起来之前,操作系统怎么知道该怎样创建该窗口,以及用户操作该窗口的各种消息交给谁处理呢?所以 VC 在调用 Windows API CreateWindow 或者 CreateWindowEx )创建窗口之前,要求程序员必须定义一个窗口类(不是传统 C++ 意义上的类)来规定所创建该窗口所需要的各种信息,主要包括:窗口的消息处理函数、窗口的风格、图标、 鼠标、菜单等。其定义如下:
typedef struct tagWNDCLASSA(注:该结构为ANSII版本)
{
         UINT          style ;
         WNDPROC      lpfnWndProc ;
         int           cbClsExtra ;
         int           cbWndExtra ;
         HINSTANCE    hInstance ;
         HICON       hIcon ;
         HCURSOR      hCursor ;
         HBRUSH       hbrBackground ;
         LPCSTR  lpszMenuName ;
         LPCSTR   lpszClassName ;
}
WNDCLASSA, * PWNDCLASSA, NEAR * NPWNDCLASSA, FAR * LPWNDCLASSA ;
style        表示该类窗口的风格,如 style = CS_VREDRAW|CS_HREDRAW 表示窗口在运动或者调整大小时需要重画,关于其它风格可在 MSDN 中查到。
lpfnWndProc 为一指针,指向用户定义的该窗口的消息处理函数。
cbClsExtra  用于在窗口类结构中保留一定空间,用于存在自己需要的某些信息。
cbWndExtra 用于在 Windows 内部保存的窗口结构中保留一定空间。
hInstance   表示创建该窗口的程序的运行实体代号( WinMain 的参数之一)。
hIcon hCursor hbrBackground lpszMenuName 分别表示该窗口的图标、鼠标形状、背景色以及菜单。
lpszClassName 表示该窗口类别的名称,即标识该窗口类的标志。
 
    从上面可以看出一个窗口类就对应一个 WNDCLASSA 结构(这里以 ANSII 为例),当程序员将该结构按自己要求填写完成后,就可以调用 RegisterClass( RegisterClassEx) 函数将该类注册,这样以后凡是要创建该窗口,只需要以该类名( lpszClassName 中指定)为参数调用 CreateWindow ,你看多方便呀,真是一举多得啊!
二.传统SDK中的窗口类
    既然我们知道了什么是窗口类,那我们就将它放到一个传统的SDK程序中,看看是怎样运行的。
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
         static TCHAR szAppName[] = TEXT ("HelloWin") ;
         WNDCLAS wndclass ;
 
         wndclass.style     = CS_HREDRAW | CS_VREDRAW ;
         wndclass.lpfnWndProc = WndProc ;
         ......

         wndclass.lpszClassName    = szAppName ;

 
         RegisterClass (&wndclass);
 
         hwnd = CreateWindow( szAppName,..., NULL) ;
    
         ShowWindow (hwnd, iCmdShow) ;
         UpdateWindow (hwnd) ;     
         while (GetMessage (&msg, NULL, 0, 0))
      {
                 TranslateMessage (&msg) ;
                 DispatchMessage (&msg) ;
         }
         return msg.wParam ;
}
    这是一个标准的Windows程序代码,程序被启动后,填写一个窗口类,然后调用RegisterClass将该类注册,接着创建该窗口,最后显示窗口和进入消息循环。
三.MFC中的窗口类
    当你看到这里,也许你可能会感到奇怪:我在用MFC向导做程序时,并没有进行什么窗口类的填写和注册吗?是的,你没有,但是向导帮你做了。在展示向导是怎么做的之前,请让我先介绍一下预先知识。
    在MFC系统中定义了五个默认的窗口类(这里不包括AFX_WNDCOMMCTLS_REG),分别定义在AFXIMPL.h中:
    #define AFX_WND_REG                  (0x0001)
    #define AFX_WNDCONTROLBAR_REG        (0x0002)
   #define AFX_WNDMDIFRAME_REG          (0x0004)
    #define AFX_WNDFRAMEORVIEW_REG       (0x0008)
    #define AFX_WNDDOLECONTROL_REG       (0x0020)
 
   在WINCORE.cpp定义了这些窗口类对应的字符串名称:
   const TCHAR _afxWnd[] = AFX_WND;
   const TCHAR _afxWndControlBar[] = AFX_WNDCONTROLBAR;
   const TCHAR _afxWndMDIFrame[] = AFX_WNDMDIFRAME;
   const TCHAR _afxWndFrameOrView[] = AFX_WNDFRAMEORVIEW;
   const TCHAR _afxWndOleControl[] = AFX_WNDOLERONTROL;
   
   在AFXIMPL.h中定义了五个AFX_XXX对应的字符串:
   #define AFX_WND                 AFX_WNDCLASS(“WND”)
   #define AFX_WNDCONTROLBAR   AFX_WNDCLASS(“ControlBar”)
   #define AFX_WNDMDIFRAME      AFX_WNDCLASS(“MDIFrame”)
   #define AFX_WNDFRAMEORVIEW AFX_WNDCLASS(“FrameOrView”)
   #define AFX_WNDOLECONTROL   AFX_WNDCLASS(“OleControl”)
 
  看到这里也许有些心急了,其实上面一堆代码只是定义了五个默认窗口类的字符串名称和二进制名称,具体注册行为在全局函数AfxDeferRegisterClass中 


我们现在再来看看AfxDeferRegisterClass是什么样子的:
#define AfxDeferRegisterClass(fClass) /
((afxRegisteredClasses & fClass) ? TRUE:AfxEndDeferRegisterClass(fClass)
   #define afxRegisteredClasses AfxGetModuleState()->m_fRegisteredClasses
 
   BOOL  AFXAPI  AfxEndDeferRegisterClass(short fClass)
   {
       WNDCLASS wndCls;
       wndCls.lpfnWndProc = DefWindowProc;
       if(fClass & AFX_WND_REG)
       {
           wndCls.lpszClassName=_afxWnd;
           AfxRegisterClass(&wndCls);
       }else if(fClass & AFX_WNDOLECONTROL_REG)
       {
           wndCls.lpszClassName=_afxWndOleControl;
           AfxRegisterClass(&wndCls);
       }else if(fClass & AFX_WNDCONTROLBAR_REG)
       {
           wndCls.lpszClassName=_afxWndControlBar;
           AfxRegisterClass(&wndCls);
       }else if(fClass & AFX_WNDMDIFRAME_REG)
       {
           RegisterWithIcon(&wndCls,_afxWndMDIFrame,AFX_IDI_MDIFRAME);
       }else if(fClass & AFX_WNDFRAMEORVIEW_REG)
       {
RegisterWithIcon(&wndCls,_afxWndFrameOrView,AFX_IDI_STD_FRAME);
       }else if(fClass & AFX_WNDCOMMCTLS_REG)
       {
           InitCommonControls();
       }
    }
 
       从上面的代码可以看出,AfxDeferRegisterClass函数首先判断该窗口类是否注册,如已注册则直接返回,否则调用AfxEndDeferRegisterClass进行注册,即注册要求的默认窗口类。其中RegisterWithIcon和InitCommonControls最终也是转化为调用AfxRegisterClass,而AfxRegisterClass函数调用RegisterClass进行注册,啊,终于看到SDK中的RegisterClass了,看到它总有一种亲切感!
   
    有了上面的知识,我们就可以很容易摸清MFC是怎样注册窗口类的了!我们知道Windows上所有看得见的东西,在MFC中都是继承于CWnd类的,而CWnd类创建窗口的成员函数是Create和CreateEx,由于Create最终是调用CreateEx,所以我们只需要看CreateEx函数就行了:
    BOOL CWnd::CreateEx(DWORD dwExStyle, LPCSTSTR lpszClassName,
                        …… LPVOID lpParam)
    {
      CREATESTRUCT cs;
      cs.dwExStyle = dwExStyle;
      … …
      cs.lpCreateParams = lpParam;
 
      PreCreateWindow(cs);
      AfxHookWindowCreate(this);
      HWND hWnd=::CreateWindowEx(cs.dwStyle,cs.lpszClass,…,cs.lpCreateParams);
      ……
    }
 
   啊,一看到CreateWindowEx,亲切感又来了,这不是和SDK中的CreateWindow一样嘛,是创建窗口!既然这样,那么注册窗口肯定在该函数之前,会是谁呢?如果你做过一点MFC程序,你就会对将眼光停留PreCreateWindow上。对!就是它了。
 
   PreCreateWindow函数是CWnd类的一个虚拟函数,提供程序设置待创建窗口的属性(包括窗口类),这样继承于CWnd的类都可以按照自己的要求在PreCreateWindow中设置自己的属性了,而且我们看到MFC也是这样做的:
   BOOL CWnd::PreCreateWindow(CREATESTRUCT &cs)
   {
      if(cs.lpszClass = = NULL)
      {
         AfxDeferRegisterClass(AFX_WND_REG);
         cs.lpszClass = _afxWnd;
      }
      return TRUE;
   }
   BOOL CFrameWnd::PreCreateWindow(CREATESTRUCT &cs)
   {
      if(cs.lpszClass = = NULL)
      {
         AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG);
        cs.lpszClass = _afxWndFrameOrView;
     }
     return TRUE;
 }
BOOL CMDIFrameWnd::PreCreateWindow(CREATESTRUCT &cs)
{
   if(cs.lpszClass = = NULL)
   {
      AfxDeferRegisterClass(AFX_WNDMDIFRAME_REG);
     cs.lpszClass = _afxWndMDIFrame;
 }
   }
   BOOL CMDIChildWnd::PreCreateWindow(CREATESTRUCT &cs)
   {
      return CFrameWnd::PreCreateWindow(cs);
   }
   BOOL CView::PreCreateWindow(CREATESTRUCT &cs)
   {
      if(cs.lpszClass = = NULL)
      {
         AfxDeferRegisterClass(AFX_WNDFRAMEORVIEW_REG);
         cs.lpszClass = _afxWndFrameOrView;
      }
   }
    
就是通过继承的方法,MFC实现常用类的窗口注册(代码并不完全,是从MFC中抽取对我们有意义的一部分代码)。
四.在MFC中注册自己的窗口类
    在MFC中创建一个窗口,就必须是继承于CWnd类的,这样你的CMyWnd类自然就有了PreCreateWindow方法。你想注册有自己个性的窗口类,那么就在该函数中进行吧。也就是在PreCreateWindow函数中注册自己的窗口类,然后将窗口类的类名以及待创建窗口的其它属性(见CREATESTRUCT结构)填写cs,然后返回系统,供系统创建你的窗口。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值