Windows程序靠消息的流動維護生命。消息的一般處理方式是在窗口函數中藉助一個大大的switch/case比較操作,判別消息再調用對應的處理程序.爲了簡化比較操作,也讓程序代碼更模塊化一些,提供了一種消息映射表做法,把消息和其處理程序關聯起來。
MFC深入淺出--消息映射
當我們的類庫成立後,若其中與消息有關的類(暫且叫“消息標誌類”,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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.