MFC深入淺出--消息映射

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);
}
發佈了21 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章