窗口封装类与Windows窗口实例的关系-2、亲自动手创建窗口封装类

为了更通俗地阐释CWnd类的封装机制,下面自己动手,模拟CWnd编写一个简单的窗口封装类,名为CBaseWnd,并使用这个类重新实现示例6.1的功能。

6.2.1  实例代码
示例6.2是实现代码,其中定义了3个类,说明如下:

q     CBaseWnd相当于CWnd的窗口基类,封装了窗口创建与销毁、窗口状态和风格操作、窗口消息处理等功能,其中的消息处理函数定义为虚拟函数。

q     CMainWnd类派生于CBaseWnd,用于创建应用程序主窗口,其中重载了几个消息处理虚函数,实现特定的消息处理。

q     CMapHWD类被CBaseWnd类合成,用于管理窗口句柄与窗口封装类的映射关系。CBaseWnd实例与Windows窗口句柄是一一对应的,实例对象只能操作与其建立映射关系的Windows窗口。在CBaseWnd类中定义了一个静态成员:

static CMapHWD MapHWND;

所以,所有的CBaseWnd实例都使用这个公共成员管理窗口句柄的映射关系。在创建窗口时建立映射,在销毁窗口时删除映射。

示例清单6.2(模拟MFC的CWnd窗口封装类)

///////////////////////////////////////////////////BaseWnd.h: interface for the CBaseWnd and CMapHWD class.

#if !defined(AFX_BASEWND_H__7496A1A1_2C75_448D_93C7_FFA39F780483__INCLUDED_)

#define AFX_BASEWND_H__7496A1A1_2C75_448D_93C7_FFA39F780483__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

 

#ifndef proc_msg

#define proc_msg virtual LRESULT

#endif

class CBaseWnd;

//定义映射链表的结点,存储封装类实例和其对应的窗口句柄

typedef struct _HWNDMAPCWND

{

         _HWNDMAPCWND()

         {

         Next=NULL;

         Top=NULL;

         pWnd=NULL;

         WndHandle=NULL;

         }

         _HWNDMAPCWND(HWND hWnd,CBaseWnd* WndPtr)

         {

         Next=NULL;

         Top=NULL;

         pWnd=WndPtr;

         WndHandle=hWnd;

         }

         CBaseWnd* pWnd;//存储封装类指针

         HWND WndHandle;//存储窗口句柄指针

         _HWNDMAPCWND * Next;//指向下一个结点

         _HWNDMAPCWND * Top;//指向上一个结点

}HWNDMAPCWND;

// CMapHWD使用HWNDMAPCWND构造映射链表,并对其进行插入、删除等管理

class CMapHWD

{

public:

         CMapHWD()

         {

         pMapList=&m_Tail;

         }

         bool Remove(HWND hWnd);

         bool insert(HWND hWnd,CBaseWnd* pWnd);

         CBaseWnd* GetWndPtr(HWND hWnd)const;

         HWND GetHWnd(CBaseWnd* pWnd)const;

private:

         HWNDMAPCWND* pMapList;

         HWNDMAPCWND m_Tail;

};

class CBaseWnd 

{

public:

         CBaseWnd();

         virtual ~CBaseWnd();

//创建与销毁窗口

         virtual BOOL Create(LPCTSTR lpszClassName,

                  LPCTSTR lpszWindowName, DWORD dwStyle,

                  const RECT& rect,

                  HWND pParentWnd, UINT nID,HINSTANCE hInst,

                  LPVOID lpParam = NULL);

         BOOL DestroyWindow();

//操作窗口状态和风格

         DWORD GetStyle() const;

         DWORD GetExStyle() const;

         BOOL ModifyStyle(DWORD dwRemove,DWORD StyleType, DWORD dwAdd, UINT nFlags = 0);

         void MoveWindow(int x, int y, int nWidth, int nHeight,

                                   BOOL bRepaint = TRUE);

        

BOOL ShowWindow(int nCmdShow);

         void UpdateWindow();

         BOOL SetWindowPos(const HWND  pWndInsertAfter, int x, int y,

                                   int cx, int cy, UINT nFlags);

         //菜单操作

HMENU GetMenu() const;

         BOOL SetMenu(HMENU Menu);

//操作窗口句柄

         BOOL Attach(HWND hWndNew);//与窗口句柄建立映射关系

         HWND Detach();//删除映射关系

         static HWND GetSafeHwnd(CBaseWnd* pWnd);

         static CBaseWnd* FromHandle(HWND hWnd);

         //窗口消息相关函数

         LRESULT SendMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0);

         BOOL PostMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0);

         //消息处理,相当于窗口函数

         virtual LRESULT WindowProc( UINT message, WPARAM wParam, LPARAM lParam );

         static LRESULT CALLBACK MyBaseWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

////////////////////////////////////////以下为每个窗口消息定义一个虚拟函数进行处理////////////////////////////// 

protected:

//       proc_msg  OnCreate(LPCREATESTRUCT lpCreateStruct);

         proc_msg  OnDestroy();

         proc_msg  OnCommand(WPARAM wParam, LPARAM lParam);

         proc_msg  OnPaint();

        

         proc_msg  OnLButtonDown(UINT nFlags,POINT point);

         proc_msg  OnRButtonDown(UINT nFlags, POINT point);

         proc_msg  OnMouseMove(UINT nFlags, POINT point);

         proc_msg  OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);

         proc_msg  OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);

         //......

public:

         LRESULT Default(UINT message,WPARAM wParam,LPARAM lParam);

         HWND m_hWnd;

protected:

         void SubWindowClass();

         WNDPROC m_SuperWndProc;

private:

         static CMapHWD MapHWND;

};

#endif

////////////////////////////////// BaseWnd.cpp: implementation of the CBaseWnd and CMapHWD class.

#include "stdafx.h"

#include "BaseWnd.h"

 

CMapHWD CBaseWnd::MapHWND;

extern CBaseWnd* pMainWnd;//指向应用程序主窗口

bool CMapHWD::Remove(HWND hWnd)

{

         HWNDMAPCWND*pList=pMapList;

         if(NULL==pList)

                  return false;

         while(pList!=NULL&&pList->pWnd!=NULL)

         {

           if(pList->WndHandle==hWnd)

           {

           HWNDMAPCWND* temp;

           temp=pList;

           if(pList->Next!=NULL)

           {

                    if(pList->Top!=NULL)

                    {

                            pList->Top->Next=pList->Next;

                            pList->Next->Top=pList->Top;

                            delete temp;

                    } else {

                            pList->Next->Top=NULL;

                            pMapList=pList->Next;

                            delete temp;

                     }

           } else if(pList->Top!=NULL){

                    pList->Top->Next=NULL;

                    delete temp;

           }

  else{

                    delete temp;

                    pMapList=NULL;

           }

           return true;

           }

        pList=pList->Next;        

         }

         return false;

}

bool CMapHWD::insert(HWND hWnd,CBaseWnd* pWnd)

{

         if(NULL==pMapList){

         pMapList=&m_Tail;

         }

         HWNDMAPCWND*pList=new HWNDMAPCWND(hWnd,pWnd);

         if(NULL==pList)

                  return false;

         pList->Next=pMapList;

         pMapList->Top=pList;

         pMapList=pList;

         return true;

}

CBaseWnd* CMapHWD::GetWndPtr(HWND hWnd)const

{

         HWNDMAPCWND*pList=pMapList;

         if(NULL==pList)

                  return false;

         while(pList->pWnd!=NULL)

         {

           if(pList->WndHandle==hWnd)

           { return pList->pWnd;}

          pList=pList->Next;;

         }

         return NULL;

}

HWND CMapHWD::GetHWnd(CBaseWnd* pWnd)const

{

         HWNDMAPCWND*pList=pMapList;

         if(NULL==pList)

                  return false;

         while(pList->pWnd!=NULL)

         {

           if(pList->pWnd==pWnd)

           { return pList->WndHandle;}

          pList=pList->Next;;

         }

         return NULL;

}

CBaseWnd::CBaseWnd()

{        m_hWnd=NULL;}

CBaseWnd::~CBaseWnd()

{

if(::IsWindow(m_hWnd))

         DestroyWindow();

}

BOOL CBaseWnd::Create(LPCTSTR lpszClassName,

                  LPCTSTR lpszWindowName, DWORD dwStyle,

                  const RECT& rect,

                  HWND ParentWnd, UINT nID,HINSTANCE hInst,

                  LPVOID lpParam)

{

         if(dwStyle&WS_CHILD){

                  if(!::IsWindow(ParentWnd))

                          return false;

         }

  HWND hwnd=::CreateWindow(lpszClassName, lpszWindowName,

                  dwStyle,

                  rect.left, rect.top,

                  rect.right-rect.left, rect.bottom-rect.top,

                  ParentWnd,

                  (HMENU)nID, hInst,lpParam);

  if(hwnd!=NULL)

  {//与创建的窗口建立映射关系

         Attach(hwnd);

         SubWindowClass();

         return true;

  }

  else return false;

}

HMENU CBaseWnd::GetMenu() const

{

if(::IsWindow(m_hWnd))

 return ::GetMenu(m_hWnd);

else return NULL;

}

BOOL CBaseWnd::SetMenu(HMENU Menu)

{

if(::IsWindow(m_hWnd))

 return ::SetMenu(m_hWnd, Menu);

else return false;

}

BOOL CBaseWnd::DestroyWindow()

{

if (m_hWnd == NULL)

                  return FALSE;

         BOOL bResult = ::DestroyWindow(m_hWnd);

//删除映射关系

         Detach();

         return bResult;

}

BOOL CBaseWnd::Attach(HWND hWndNew)

{

         if(!::IsWindow(hWndNew))

                  return false;

         if(m_hWnd != NULL)

                  return false;

         if(FromHandle(hWndNew) != NULL)

                  return false;

         if(MapHWND.insert(hWndNew,this))

         {

         m_hWnd=hWndNew;

         return TRUE;

         }

         return false;

}

HWND CBaseWnd::Detach()

{

         HWND hWnd = m_hWnd;

         if (hWnd != NULL)

         {

                  MapHWND.Remove(m_hWnd);

                  m_hWnd = NULL;

         }

         return hWnd;

}

HWND CBaseWnd::GetSafeHwnd(CBaseWnd*pWnd)

{

if(NULL!=pWnd)

{ return      MapHWND.GetHWnd(pWnd);

}

return NULL;

}

CBaseWnd* CBaseWnd::FromHandle(HWND hWnd)

{

if(NULL!=hWnd)

{ return      MapHWND.GetWndPtr(hWnd);

}

return NULL;

}

void CBaseWnd::GetWindowRect(RECT &rcWindow) const

{

              if(::IsWindow(m_hWnd))

                  ::GetWindowRect(m_hWnd, &rcWindow);

}

void CBaseWnd::GetClientRect(RECT &rcClient) const

{

                  if(::IsWindow(m_hWnd))

                  ::GetClientRect(m_hWnd, &rcClient);

}

BOOL CBaseWnd::ShowWindow(int nCmdShow)

{

         if(::IsWindow(m_hWnd))

         {        return ::ShowWindow(m_hWnd,nCmdShow);

         }

         return false;

}

void CBaseWnd::UpdateWindow()

{

         if(::IsWindow(m_hWnd))

         {                ::UpdateWindow(m_hWnd);

         }

}

BOOL CBaseWnd::SetWindowPos(const HWND  pWndInsertAfter, int x, int y,

int cx, int cy, UINT nFlags)

{

         if(!::IsWindow(m_hWnd))

                  return false;

         return ::SetWindowPos(m_hWnd,  pWndInsertAfter,

                          x, y, cx, cy, nFlags);

}

DWORD CBaseWnd::GetStyle() const

{

         if(::IsWindow(m_hWnd))

         {                return ::GetWindowLong(m_hWnd,GWL_STYLE);

       }

         return 0;

}

DWORD CBaseWnd::GetExStyle() const

{

if(::IsWindow(m_hWnd))

         {        return ::GetWindowLong(m_hWnd,GWL_EXSTYLE);

       }

         return 0;

}

BOOL CBaseWnd::ModifyStyle(DWORD dwRemove, DWORD StyleType,DWORD dwAdd, UINT nFlags)

{

         if(!::IsWindow(m_hWnd))

                  return false;

         if(StyleType!=GWL_STYLE&&StyleType!=GWL_EXSTYLE)

                  return false;

         DWORD dwStyle = ::GetWindowLong(m_hWnd, StyleType);

         DWORD dwNewStyle = (dwStyle & ~dwRemove) | dwAdd;

         if (dwStyle == dwNewStyle)

                  return FALSE;

 

         ::SetWindowLong(m_hWnd, StyleType, dwNewStyle);

         if (nFlags != 0)

         {        ::SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0,

                          SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | nFlags);

         }

         return TRUE;

}

void CBaseWnd::MoveWindow(int x, int y, int nWidth, int nHeight,BOOL bRepaint)

{

         if(!::IsWindow(m_hWnd))

                  return;

         ::MoveWindow(m_hWnd, x, y, nWidth, nHeight, bRepaint);

}

LRESULT CBaseWnd::WindowProc( UINT message, WPARAM wParam, LPARAM lParam )

{

         switch (message)

         {

         case WM_KEYDOWN:

                  return OnKeyDown(wParam,lParam&0xFF,(lParam>>16)&0xFF);

                 

         case WM_KEYUP:

                  return OnKeyUp(wParam,lParam&0xFF,(lParam>>16)&0xFF);

                 

         case WM_COMMAND:

                  return OnCommand(wParam,lParam);

                 

         case WM_LBUTTONDOWN:

                  POINT lPoint;

                  lPoint.x=lParam&0xFF;

                  lPoint.y=(lParam>>16)&0xFF;

                  return OnLButtonDown(wParam,lPoint);

                 

         case WM_RBUTTONDOWN:

                  POINT rPoint;

                  rPoint.x=lParam&0xFF;

                  rPoint.y=(lParam>>16)&0xFF;

                  return OnRButtonDown(wParam,rPoint);

                 

         case WM_PAINT:

                  return OnPaint();

                 

         case WM_DESTROY:

                  return OnDestroy();

                  break;

         default:

                  //调用默认的消息处理过程处理当前消息

                  return Default(message, wParam, lParam);

   }

       return 0;

}

LRESULT CALLBACK CBaseWnd::MyBaseWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

         //处理窗口消息的窗口函数

  if(hWnd!=NULL)

  {

           CBaseWnd* pWnd=CBaseWnd::FromHandle(hWnd);

           if(pWnd!=NULL)

                    return pWnd->WindowProc(message, wParam, lParam);

  }

       return 0;

  }

LRESULT CBaseWnd::SendMessage(UINT message, WPARAM wParam, LPARAM lParam)

{

         if(IsWindow(m_hWnd))

         {        return ::SendMessage(m_hWnd,message,wParam,lParam);

         }

         return -1;

}

BOOL CBaseWnd::PostMessage(UINT message, WPARAM wParam, LPARAM lParam)

{

         if(IsWindow(m_hWnd))

         {return ::PostMessage(m_hWnd,message,wParam,lParam);

         }

         return false;

}

/////////////////message process///////////////////

LRESULT CBaseWnd::OnDestroy()

{

         LRESULT ret=0;

         if(::IsWindow(m_hWnd))

         {

          ret=Default(WM_DESTROY,0,0);

         }

         if(NULL!=pMainWnd)

         {

                  if(MapHWND.GetWndPtr(m_hWnd)==pMainWnd)

                          ::PostQuitMessage(0);

         }

         if(NULL!=m_hWnd)

         {Detach();}

         return ret;

}

LRESULT CBaseWnd::OnCommand(WPARAM wParam, LPARAM lParam)

{

 return Default(WM_COMMAND,wParam,lParam);

}

LRESULT CBaseWnd::OnPaint()

{ return Default(WM_PAINT,0,0);

}

LRESULT CBaseWnd::OnLButtonDown(UINT nFlags, POINT point)

{

return Default(WM_LBUTTONDOWN,(WPARAM)nFlags,(LPARAM)MAKELONG (point.y,point.x));

}

LRESULT CBaseWnd::OnRButtonDown(UINT nFlags, POINT point)

{return Default(WM_RBUTTONDOWN,(WPARAM)nFlags, (LPARAM)MAKELONG(point.y,point.x));

}

LRESULT CBaseWnd::OnMouseMove(UINT nFlags, POINT point)

{ return Default(WM_MOUSEMOVE,(WPARAM)nFlags, (LPARAM)MAKELONG(point.y,point.x));

}

LRESULT CBaseWnd::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)

{ return Default(WM_KEYDOWN,(WPARAM)nChar, (LPARAM)MAKELONG(nFlags,nRepCnt));

}

LRESULT CBaseWnd::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)

{ return Default(WM_KEYUP,(WPARAM)nChar, (LPARAM)MAKELONG(nFlags,nRepCnt));

}

void CBaseWnd::SubWindowClass()

{/*为方便地处理窗口消息,将关联的窗口子类化,即将静态成员函数MyBaseWndProc()设置为处理窗口消息的窗口过程,并将原始的窗口过程保存在成员m_SuperWndProc中,在消息处理的最后调用*/

         if(NULL==m_hWnd)

                  return;

         m_SuperWndProc = (WNDPROC)SetWindowLong(m_hWnd, GWL_WNDPROC,

                                                     (DWORD)MyBaseWndProc);

         if(m_SuperWndProc==MyBaseWndProc)

                  m_SuperWndProc=NULL;

}

LRESULT CBaseWnd::Default(UINT message, WPARAM wParam, LPARAM lParam)

{

         //默认的消息处理函数。如果窗口已被子类化,则调用原始的窗口过程

         if(NULL!=m_SuperWndProc)

                  return ::CallWindowProc(m_SuperWndProc, m_hWnd,message,wParam, lParam);

return ::DefWindowProc(m_hWnd, message, wParam, lParam);

}

///////////////////////// MainWnd.h: interface for the CMainWnd class.

#if !defined(AFX_MAINWND_H__F3B00F31_F2DD_488F_BA2D_0892A9E8FE6F__INCLUDED_)

#define AFX_MAINWND_H__F3B00F31_F2DD_488F_BA2D_0892A9E8FE6F__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

#include "BaseWnd.h"

class CMainWnd : public CBaseWnd 

{

public:

         CMainWnd();

         virtual ~CMainWnd();

protected:

//根据需要,重载消息处理虚函数,处理相应消息

         proc_msg OnPaint();

         proc_msg OnLButtonDown(UINT nFlags,POINT point);

         proc_msg OnRButtonDown(UINT nFlags, POINT point);

};

#endif

//////////////////////////// MainWnd.cpp : implementation of the CMainWnd class

#include "stdafx.h"

#include "MainWnd.h"

CMainWnd::CMainWnd(){}

CMainWnd::~CMainWnd(){}

LRESULT CMainWnd::OnPaint(void)

{

PAINTSTRUCT ps;

HDC dc = BeginPaint(m_hWnd, &ps);

                          RECT rt;

                          GetClientRect(rt);

                          ::SetBkColor(dc,::GetSysColor(COLOR_BACKGROUND));

                          ::SetTextColor(dc,RGB(255,255,255));

DrawText(dc, "My window created by class CMainWnd,simulating CWnd of MFC",-1,&rt, DT_CENTER);

 

         EndPaint(m_hWnd, &ps);

         return CBaseWnd::OnPaint();

}

LRESULT CMainWnd::OnLButtonDown(UINT nFlags,POINT point)

{                int ScreenWidth;

                  int ScreenLength;

                  RECT rcWindow;

                 

                  GetWindowRect(rcWindow);

                   ScreenWidth=GetSystemMetrics(SM_CXSCREEN);

                   ScreenLength=GetSystemMetrics(SM_CYSCREEN);

                  //单击鼠标,设置窗口位置

                  SetWindowPos(HWND_TOP,ScreenWidth/4,

                          ScreenWidth/4,ScreenLength/2,ScreenLength/2,SWP_SHOWWINDOW);

                  Sleep(300);

 

                  SetWindowPos(HWND_TOP,ScreenWidth/3,

                          ScreenWidth/3,ScreenLength/3,ScreenLength/3,SWP_SHOWWINDOW);

                  Sleep(100);

                  SetWindowPos(HWND_TOP,ScreenWidth/4,

                          ScreenWidth/4,ScreenLength/2,ScreenLength/2,SWP_SHOWWINDOW);

                  Sleep(100);

                  SetWindowPos(HWND_TOP,rcWindow.left,rcWindow.top,

                          rcWindow.right-rcWindow.left,rcWindow.bottom-rcWindow.top,

                          SWP_SHOWWINDOW);

 

                  return CBaseWnd::OnLButtonDown(nFlags,point);

}

LRESULT CMainWnd::OnRButtonDown(UINT nFlags, POINT point)

{        //右击鼠标,隐藏、显示窗口

                  ShowWindow(SW_HIDE);

                  Sleep(300);

                  ShowWindow(SW_SHOW);

                  return CBaseWnd::OnRButtonDown(nFlags,point);

}

/////////////////////////////////////////////// c222.cpp : Defines the entry point for the application.

#include "stdafx.h"

#include "mainWnd.h"

#define szWindowClass "MyClassName"

#define szTitle "MyWindow"

 

ATOM MyRegisterClass(HINSTANCE hInstance);

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

 

CBaseWnd* pMainWnd=NULL;

 

int APIENTRY WinMain(HINSTANCE hInstance,

                     HINSTANCE hPrevInstance,

                     LPSTR lpCmdLine,

                     int nCmdShow)

{

       MSG msg;

         HWND hWnd=NULL;

   //注册窗口类

         MyRegisterClass(hInstance);

 

CMainWnd MyWnd;//指向应用程序主窗口

RECT rt;

rt.left=0,rt.top=0, rt.right=CW_USEDEFAULT,rt.bottom=0;

//使用封装类操作窗口

if(!MyWnd.Create(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW|WS_BORDER,

       rt,NULL, NULL, hInstance))

return false;

   //显示主窗口

         pMainWnd=&MyWnd;

   MyWnd.ShowWindow(nCmdShow);

   MyWnd.UpdateWindow();

 

         //先创建主窗口,然后进入消息循环

         while (GetMessage(&msg, NULL, 0, 0))

         {                TranslateMessage(&msg);

                          DispatchMessage(&msg);

         }

         //收到WM_QUIT消息,退出

         return msg.wParam;

}

ATOM MyRegisterClass(HINSTANCE hInstance)

{……}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

return ::DefWindowProc(hWnd, message, wParam, lParam);

}

6.2.2  原理分析
通过6.2.1小节的代码,建立了一个比较粗糙的窗口封装类,并用它编写了一个简单的应用程序。CBaseWnd类既可以创建主窗口,也可以创建子窗口,该类是模拟CWnd编写的,有些代码是直接从CWnd类中复制的,目的是帮助我们理解CWnd的封装机制。

一个窗口封装类主要包括映射Windows窗口句柄、通过该句柄操作系统窗口、为需要处理的窗口消息提供处理函数等几个方面内容。CBaseWnd较圆满地解决了前两个问题,但在消息处理方面做得不够理想。

CBaseWnd使用虚拟函数处理消息(MFC使用消息映射机制),派生类重载虚拟函数即可实现特定的消息处理。由于窗口是在创建完成后与类对象关联并子类化的,所以WM_ CREATE之前的窗口消息,封装类无法接收,但可以采用系统钩子或全局子类化的方法解决这个问题(关于子类化的详细阐述参见8.6节)。在本例中,为弥补这个缺陷,CBase Wnd::Create()已定义为虚拟函数,如果用户需要在WM­_CREATE消息到来之际完成必要的操作,例如创建子窗口,可以通过重载Create()虚函数实现。由于不可能为所有的命令消息定义虚拟函数,所以具体的命令消息如菜单、按钮、加速键,只能通过重载OnCommand()函数进行细分处理。另外,该类没有为子窗口传递系统消息和反射通知消息(见第9章)。

当然,CBaseWnd没有父类,因而缺少如CCmdTarget基类的支撑。

posted on 2011-05-09 18:11  carekee  阅读(896)  评论(0编辑  收藏  举报