MFC深入浅出--消息映射

    技术2022-05-19  21

    Windows程序靠消息的流动维护生命。消息的一般处理方式是在窗口函数中借助一个大大的switch/case比较操作,判别消息再调用对应的处理程序.为了简化比较操作,也让程序代码更模块化一些,提供了一种消息映射表做法,把消息和其处理程序关联起来。

     当我们的类库成立后,若其中与消息有关的类(暂且叫“消息标志类”,MFC之中就是CCmdTarget)都是一条线式地继承,我们应该为每一个“消息标志类”准备一个消息映射表,并且将基类与派生类的消息映射表连接起来。当窗口函数作消息比较时,就引导它沿这条线走。  MFC中用来处理消息的C++类,并不呈单线发展。作为application framework的重要结构之一的document/view,也具有处理消息的能力。因此消息的遍历路线也有横流的机会。  消息如何流动,暂且先不管。我们先建立整个攀爬路线网就是所谓的消息映射表(Message Map).将消息和表格中元素比较,然后调用对应的处理程序,这种操作称为消息映射(Message Mapping).  为了尽量降低对正常(一般)类声明和定义的影响,希望最好能想RTTI和Dynamic Creation一样,用一两个宏就完成消息映射表的建构。 首先定义一个数据结构:  struct AFX_MSGMAP  {     AFX_MAGMAP * pBaseMessageMap;     AFX_MSGMAP_ENTRY * lpEnteries; } 其中AFX_MSGMAP_ENTRY的定义如下: struct AFX_MSGMAP_ENTRY //MFC 4.0 format {  UINT nMessage; //windows message  UINT nCode;    //control code or WM_NOTIFY code  UINT nID;    //control ID(or o for windows message)  UINT nLastID;    //used for entries specifying a range og control id s UINT nSig;    //signature type (action) or pointer to message  AFX_PMSG pfn;    /runtime to call ( or special value) } typedef void (CCmdTarget::*AFX_PMSG) (void)   然后我们定义一个宏: #define DECLARE_MESSAGE_MAP() /  static AFX_MESSAGE_ENTRY messageEntries[]; /  static AFX_MSGMAP messageMap;/  virtual AFX_MSGMAP * GetMessageMap() const; DECLARE_MESSAGE_MAP的内容填充工作由三个宏完成: #define BEGIN_MESSAGE_MAP(theClass,baseClass) /  AFX_MSGMAP * theClass::GetMessageMap() const /  { return &theClass::messageMap; } /  AFX_MSGMAP theClass::messageMap = /   (&(baseClass::messageMap),/ (AFX_MSGMAP_ENTRY *)&(theClass::_messageEntries));/      AFX_MSGMAP_ENTRY theClass::messageEntries[] = / {  #define ON_COMMAND (id,memberFxn) /     (WM_COMMAND,0,(WORD)id, (WORD)id,AfxSig_vv,(AFX_PMSG)memberFxn),  #define END_MESSAGE_MAP( )/     (0,0,0,0,AfxSig_end, (AFX_PMSG)0 ) / }; 其中的AfxSig_end定义为: enum AfxSig {     AfxSig_end = 0, //{marks end of message map}     AfxSig_vv, };  AfxSig_XX用来描述消息处理程序memberFxn的类型(参数和返回值)。  下面是以Cview为例的程序: class Cview : public CWnd {  public:         DECLARE_MESSAGE_MAP() }; #define CviewId 122 BEGIN_MESSAGE_MAP( Cview , CWnd )  ON_COMMAND( CviewId,0 ) END_MESSAGE_MAP() 上述代码展开后: class CView : public CWnd {  public:         static AFX_MSGMAP_ENTRY _messAgeENtries();     static AFX_MSGMAP messageMap;     virtual AFX_MSGMAP * GetMessageMap() const; }; AFX_MSGMAP * CView::GetMessageMap() const /  { return &CView::messageMap; } /  AFX_MSGMAP CView::messageMap = /   (&(CWnd::messageMap),/ (AFX_MSGMAP_ENTRY *)&(CView::_messageEntries));/      AFX_MSGMAP_ENTRY CView::messageEntries[] = / {     (WM_COMMAND,0,(WORD)122,(WORD)122,1,(AFX_PMSG)0 ),     (0,0,0,0,AfxSig_end, (AFX_PMSG)0 ) }; 我们还可以定义各种类似ON_COMMAND这样的宏,把各式各样的消息与特定的处理程序关联起来。MFC中有ON_WN_PAINT,ON_WM_CREATE,ON_WM_SIZE 等等。   范例程序 MFC.H #define TURE 1 #define FALSE 0 typedef const char * LPCSTR ; typedef char * LPSTR; typedef unsigned long DWORD; typedef int BOOL; typedef unsigned char BYTE; typedef unsigned short WORD; typedef int INT; typedef unsigned int UINT; typedef long LONG; #define WM_COMMAND 0x0111 #define CObjectid 0xffff #define CCmdTargetid 1 #define CWinThreadid 11 #define CWinAppid 111 #define CMyWinApp 1111 #define CWndid 12 #define CFrameWndid 121 #define CMyFrameWndid 1211 #define CViewid    122 #define CMyViewid 1221 #define CDocument 13 #define CMyDocid 131 #include <iostream.h> struct AFX_MSGMAP  {     AFX_MAGMAP * pBaseMessageMap;     AFX_MSGMAP_ENTRY * lpEnteries; } #define DECLARE_MESSAGE_MAP() /  static AFX_MESSAGE_ENTRY messageEntries[]; /  static AFX_MSGMAP messageMap;/  virtual AFX_MSGMAP * GetMessageMap() const; #define BEGIN_MESSAGE_MAP(theClass,baseClass) /  AFX_MSGMAP * theClass::GetMessageMap() const /  { return &theClass::messageMap; } /  AFX_MSGMAP theClass::messageMap = /   (&(baseClass::messageMap),/ (AFX_MSGMAP_ENTRY *)&(theClass::_messageEntries));/      AFX_MSGMAP_ENTRY theClass::messageEntries[] = / { #define END_MESSAGE_MAP( )/     (0,0,0,0,AfxSig_end, (AFX_PMSG)0 ) / }; //message map signature value and macros in separate header #include afxmsg_.h class CObject {   public:     CObject::CObject() { } CObject::~CObject() { } Virtual CRuntimeClass *GetRuntimeClass() const; BOOL IsKindOf(const CRuntimeClass *pCLass) const;  Public:     static CRuntimeClass classCObject;     virtual void Sayhell() {cout<< Hello CObject/n ;} }; class CCmdTarget : public CObject {   public:     CCmdTarget:: CCmdTarget () { } CCmdTarget::~CCmdTarget () { } DECLARE_MESSAGE_MAP() //base class= no(()) macros }; typedef void (CCmdTarget:: *AFX_PMSG) (void); struct AFX_MSGMAP_ENTRY //MFC 4.0 format {  UINT nMessage; //windows message  UINT nCode;    //control code or WM_NOTIFY code  UINT nID;    //control ID(or o for windows message)  UINT nLastID;    //used for entries specifying a range og control id s UINT nSig;    //signature type (action) or pointer to message  AFX_PMSG pfn;    /runtime to call ( or special value) }   class CwinThread : public CCmdTarget {  DECLARE_DYNAMIC(CWinThread)   public:     CwinThread:: CwinThread () { }     CwinThread::~ CwinThread () { }     Virtual BOOL InitInstance(){ Return TRUE; } virtual int Run(){ return 1; } }; class CWnd; class CWinApp : public CwinThread {  DECLARE_DYNAMIC(CWinApp)   public:     CWinApp * m_pCurrentWinApp;     CWnd * m_pMainWnd;   Public:     CWinApp::CWinApp() { pCurrentWinApp = this ;}     CWinApp::~CWinApp() { }     virtual BOOl InitApplication () {         Return TRUE;     }     virtual BOOL InitInstance () {        return TRUE;     }     virtual int Run () {        return CWinThread::Run(); } DECLARE_MESSAGE_MAP() }; typedef void (CWnd::*AFX_PMSGW) (void) //like AFX_PMSG but for CWnd derived classes only Class CDocument : public CCmdTarget {   public:     Cdocument:: Cdocument() { } Cdocument::~ Cdocument() { } DECLARE_MESSAGE_MAP() }; Class CWnd : public CCmdTarget {   public:     CWnd:: CWnd () { } CWnd::~CWnd () { } Virtual BOOL Create(); BOOL CreateEx(); virtual BOOL PreCreateWindow(); DECLARE_MESSAGE_MAP() }; Class CFrameWnd : public CWnd {  DECLARE_DYNCREATE(CFrameWnd)   public:     CFrameWnd:: CFrameWnd () { }     CFrameWnd::~CFrameWnd () { }     BOOL Create ();     Virtual BOOL PreCreateWindow(); DECLARE_MESSAGE_MAP()   }; Class CView : public CWnd { DECLARE_DYNAMIC(CView)   public:     CView:: CView () { } CView::~ CView () { } DECLARE_MESSAGE_MAP() }; //global function CWinApp *AfxGetApp();     AFXMSG_.H enum AfxSig {     AfxSig_end = 0, //{marks end of message map}     AfxSig_vv, }; #define ON_COMMAND(id,memberFxn) /     (WM_COMMAND,0,(WORD)id,(WORD)id,AfxSig_vv,(AFX_PMSG)memberFxn),   MFC.CPP #include my.h //本该包含mfc.h,但为了CmyWinapp的定义 extern CmyWinApp theApp ; //external global object BOOL CWnd::Create() {     return TRUE; } BOOL CWnd::CreateEx() {     PreCreateWindow();     return TRUE; } BOOL CWnd::PreCreateWindow() {     return TRUE; } BOOL CframeWnd::Create() {     CreateEx();     return TRUE; } BOOL CframeWnd::PreCreateWindow() {     return TRUE; } //global function CWinApp * AfxApp() {   return theApp.m_pCurrentWinApp; } AFX_MSGMAP * CCmdTarget::GetMessageMap() const {     return &CCmdTarget::messageMap; } AFX_MSGMAP CCmdTarget::messageMap = {     NULL;     &CCmdTarget::_messageEntries[0] }; AFX_MSGMAP_ENTRY CCmdTarget::messageEntries = {     (0,0,CCmdTargetid , 0, AfxSig_end , 0) }; BEGIN_MESSAGE_MAP(CWnd,CCmdTarget) ON_COMMAND(CWndid ,0) END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CFrameWnd, CWnd) ON_COMMAND(CFrameWndid,0) END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CDocument,CCmdTarget) ON_COMMAND(CDocumentid,0) END_MESSAGE_MAP()   BEGIN_MESSAGE_MAP(CView,CWnd) ON_COMMAND(CViewid ,0) END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CwinApp ,CCmdTarget) ON_COMMAND(CWinAppid,0) END_MESSAGE_MAP()     MY.H #include <iostream.h> #include mfc.h class CmyWinApp : public CWinApp {   public:     CmyWinApp:: CmyWinApp() { }     CmyWinApp::~ CmyWinApp() { } virtual BOOL InitInstance(); DECLARE_MESSAGE_MAP() }; class CMyFrameWnd : public CframeWnd {   public:     CMyFrameWnd(); ~CMyFrameWnd() {} DECLARE_MESSAGE_MAP() }; class CmyDoc : public Cdocument { public:     CmyDoc:: CmyDoc() { }     CmyDoc::~ CmyDoc() { } DECLARE_MESSAGE_MAP() }; class CMyView : public CView {  public:    CMyView:: CMyView () { }     CMyView::~ CMyView () { } DECLARE_MESSAGE_MAP() };     MFC.CPP #include my.h CmyWinApp theApp; //global object BOOL CMyWinAPP::InitInstance() {     m_pMainWnd = new CmyFrameWnd;     return TRUE; } CmyFrameWnd::CmyFrameWnd() {     Create(); } BEGIN_MESSAGE_MAP(CMyWinApp ,CWinApp) ON_COMMAND(CMyWinAppid,0) END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CMyFrameWnd ,CFrameWnd) ON_COMMAND(CMyFrameWndid,0) END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CMyDoc ,CDocument) ON_COMMAND(CMyDocid,0) END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CMyView ,CView) ON_COMMAND(CMyViewid,0) END_MESSAGE_MAP() Void printlpEntries(AFX_MSGMAP_ENTRY * lpEntry) {  struct {  int classid;  char *classname; } classinfo[] = {      CCmdTargetid , CCmdTarget ,      CWinThreadid , CWinThread , CWinAppid , CWinApp ,      CMyWinAppid , CMyWinApp ,      CWndid , CWnd ,      CFrameWndid , CFrameWnd ,      CMyFrameWndid, CMyFrameWnd ,      CViewid , CView ,      CMyViewid , CMyView ,      CDocument , CDocument ,     CMyDocid , CMyDoc , }; for(int I=0;classinfo[I].classid!=0;I++) {         if(classinfo[I].classid=lpEntry->nID)        {            cout<<lpEntry->nID<< ;            cout<<classinfo[I].classname<<endl;            break; } } } void MsgMapPrinting(AFX_MSGMAP *pMessageMap) {     for(;pMessage!=NULL;pMessageMap = PmessageMap->pBasemessageMap)     {     AFX_MSG_ENTRY * lpEntry= pMessageMap->lpentried;     PrintflpEntries(lpEntry); } } //main() void main() {     CwinApp *pApp = AfxGetApp();     pApp->InitApplication();     pApp->InitInstance(); pApp->Run();        CMyDoc *pMyDoc = new CMyDoc; CMyView *pMyView = new CMyView; CFrameWnd *pMyFrame = (CFrameWnd *)pApp->m_ppMainWnd; AFX_MSGMAP * pMessageMap = pMyView->GetMessageMap(); Cout<<endl<< CMyView Message Map: <<endl; MsgMapPrinting(pMessageMap); pMessageMap = pMyDoc->GetMessageMap(); Cout<<endl<< CMyDoc Message Map: <<endl; MsgMapPrinting(pMessageMap); pMessageMap = pMyFrame->GetMessageMap(); Cout<<endl<< C pMyFrameWnd Message Map: <<endl; MsgMapPrinting(pMessageMap); pMessageMap = pApp->GetMessageMap(); Cout<<endl<< CMyWinApp Message Map: <<endl; MsgMapPrinting(pMessageMap); }

    最新回复(0)