消息映射機制
SDK編程中,一般處理消息的方法就是使用switch/case判斷消息的類型,然後進行響應。更模塊化的方法是使用第一章介紹的消息映射表的方法,把消息和消息處理函數關聯起來。
應該爲每個需要處理消息的類構建一個消息映射表,並將基類與派生類的消息映射表連接起來。當窗口函數比較消息時,就沿着這條繼承路線傳遞下去。 爲了實現這個目的我們仍然使用兩個宏,完成這個功能複雜的構建。
首先定義一個數據結構:
//消息映射表元素類型。
struct AFX_MSGMAP_ENTRY
{
UINT nMessage;
UINT nCode;
UINT nID;
UINT nLastID;
UINT nSig;
AFX_PMSG pfn;
};
struct AFX_MSGMAP
{
AFX_MSGMAP *pBaseMessageMap;//指向基類的本結構。
AFX_MSGMAP_ENTRY*lpEntries;//本類的消息映射表。
};
在定義一個宏:
define DECLARE_MESSAGE_MAP\
static AFX_MSGMAP_ENTRY _messageEntries[];\
static AFX_MSGMAP messageMap;\
virtual AFX_MSGMAP*GetMessageMap()const;
該宏相當於在類中聲明兩個static數據成員和一個虛成員函數。
它們的定義由以下三個宏實現:
#define BEGIN_MESSAGE_MAP(class_name,base_class)\
AFX_MSGMAP*class_name::GetMessageMap()const\
{return &class_name::message;}\
AFX_MSGMAP messageMap=\
{&base_class::messageMap,class_name::_messageEntries}\
AFX_MSGMAP_ENTRY _messageEntries[]=\
{
#define ON_COMMAND(id,memFunc)\
WM_COMMAND,0,id,id,AFx_sig_vv\
,(AFX_PMSG)memFunc },\
#define END_MESSAGE_MAP()\
{0,0,0,0,AfxSig_end,(AFX_PMSG)0}\
以CView爲例,下面的代碼:
class CWnd :public CWnd
{
public:
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CView,CWnd)
ON_COMMAND(CViewid,0)
END_MESSAGE_MAP()
展開後變爲:
class CView :public CWnd
{
public:
static AFX_MESSAGE_ENTRY _messageEntries[];
static AFX_MSGMAP messageMap;
virtual AFX_MSGMAP*GetMessageMap()const;
};
AFX_MSGMAP*CView::GetMessageMap()const
{
return &CView::messagemMap;
}
AFX_MSGMAP CView::messageMap=
{
&(CWnd::messageMap),
(AFX_MSGMAP_ENTRY*)&(CView::_messageEntries)
};
AFX_MSGMAP_ENTRY CView::_messageEntries[]=
{
{WM_COMMAND,0,122,122,1,(AFX_PMSG)0},
{0,0,0,0,0,(AFX_PMSG)0}
}
爲了驗證整個消息映射表,我們在每個類的消息映射表中添加了一個空的消息,這是爲了做點標記,用於標示消息映射表的最後一個消息。MFC當然不是這樣實現的。
/* CCmdTarget是消息傳遞的終點,因此在實現時需要特殊處理,這一點容易出錯,要特別注意。
class CCmdTarget:public CObject
{
DECLARE_DYNCREATE(CCmdTarget)
DECLARE_MESSAGE_MAP()
public:
CCmdTarget()
{
//cout<<"CCmdTarget constructor!"<<endl;
//CreateObject();
}
~CCmdTarget()
{
//cout<<"CCmdTarget destructor!"<<endl;
}
public:
};
IMPLEMENT_DYNCREATE(CCmdTarget,CObject)
AFX_MSGMAP CCmdTarget::messageMap=
{NULL,CCmdTarget::_messageEntries};
AFX_MSGMAP_ENTRY CCmdTarget::_messageEntries[]=
{
{0,0,10,0,AfxSig_end,0},
{0,0,0,0,AfxSig_end,0}
};
AFX_MSGMAP*CCmdTarget::GetMessageMap()const
{
return &CCmdTarget::messageMap;
}
以下爲包含動態創建、類型識別、消息映射的完整代碼:
- #include<iostream>
- #include<windows.h>
- #include<string>
- using namespace std;
- class CCmdTarget;
- typedef void (CCmdTarget::*AFX_PMSG)(void);
- //消息映射表元素類型。
- enum AfxSig
- {
- AfxSig_end=0,
- AfxSig_vv,
- };
- struct AFX_MSGMAP_ENTRY
- {
- UINT nMessage;
- UINT nCode;
- UINT nID;
- UINT nLastID;
- UINT nSig;
- AFX_PMSG pfn;
- };
- struct AFX_MSGMAP
- {
- AFX_MSGMAP *pBaseMessageMap;//指向基類的本結構。
- AFX_MSGMAP_ENTRY*lpEntries;//本類的消息映射表。
- };
- #define DECLARE_MESSAGE_MAP()\
- public:\
- static AFX_MSGMAP_ENTRY _messageEntries[];\
- static AFX_MSGMAP messageMap;\
- virtual AFX_MSGMAP*GetMessageMap()const;\
- #define BEGIN_MESSAGE_MAP(class_name,base_class)\
- AFX_MSGMAP*class_name::GetMessageMap()const\
- {return &class_name::messageMap;}\
- AFX_MSGMAP class_name::messageMap={&base_class::messageMap,class_name::_messageEntries};\
- AFX_MSGMAP_ENTRY class_name::_messageEntries[]=\
- {
- #define ON_COMMAND(id,memFunc)\
- {WM_COMMAND,0,id,id,AfxSig_vv,(AFX_PMSG)memFunc },\
- #define END_MESSAGE_MAP()\
- {0,0,0,0,AfxSig_end,(AFX_PMSG)0}\
- };
- class CObject;
- class CRuntimeClass
- {
- public:
- char* m_lpszClassName;//對象所屬類名
- int m_nObjectSize;//對象大小
- int m_wSchema;//模式號
- CObject*(PASCAL*m_pfnCreateObject)();//構建函數,抽象類爲NULL
- CRuntimeClass *m_pBaseClasss;//基類CRuntimeClass對象指針。
- static CRuntimeClass *pFirstClass;//鏈表頭指針。static
- CRuntimeClass *m_pNextClass;//下一指針。
- public:
- CObject*CreateObject()
- {
- if(m_pfnCreateObject==NULL)
- {
- cout<<"該類型不支持動態創建!!"<<endl;
- return NULL;
- }
- CObject*pClass=(*m_pfnCreateObject)();
- return pClass;
- }
- static CRuntimeClass*Load()
- {
- cout<<"請輸入要動態創建的類名:";
- string s;
- cin>>s;
- for(CRuntimeClass*pClass=pFirstClass;pClass;pClass=pClass->m_pBaseClasss)
- {
- if(pClass->m_lpszClassName==s)
- {
- return pClass;
- }
- }
- return NULL;
- }
- };
- class AFX_CLASSINIT
- {
- public:
- AFX_CLASSINIT(CRuntimeClass*pNewClass)//構造函數
- {
- pNewClass->m_pNextClass=CRuntimeClass::pFirstClass;
- CRuntimeClass::pFirstClass =pNewClass;
- }
- };
- /************************************************************************/
- /* 動態類型識別宏定義
- //與CRuntimeClass類中的構建函數相區別。此處的CreateObject函數在每個類中都以static成員函數存在,用以
- //初始化類型型錄表,而CRuntimeClass中的CreateObject用於調用每個類的構建函數。僅僅是函數名相同罷了。*/
- /************************************************************************/
- #define DECLARE_DYNAMIC(class_name)\
- public:\
- static CRuntimeClass Class##class_name;\
- virtual CRuntimeClass*GetRuntimeClass()const;\
- #define DECLARE_DYNCREATE(class_name)\
- DECLARE_DYNAMIC(class_name)\
- static CObject*PASCAL CreateObject();\
- #define RUNTIME_CLASS(class_name)\
- (&class_name::Class##class_name)\
- #define _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,wSchema,pfnNew)\
- class CRuntimeClass class_name::Class##class_name ={\
- #class_name,\
- sizeof(class_name),wSchema,pfnNew,RUNTIME_CLASS(base_class_name),NULL};\
- static AFX_CLASSINIT _init##class_name( RUNTIME_CLASS(class_name));\
- CRuntimeClass *class_name::GetRuntimeClass()const\
- {return &class_name::Class##class_name;}//此處將class_name寫成了classname花了一兩天才查出來。啊啊啊啊啊。20120605
- #define IMPLEMENT_DYNAMIC(class_name,base_class_name)\
- _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL)\
- #define IMPLEMENT_DYNCREATE(class_name,base_class_name)\
- CObject*PASCAL class_name::CreateObject(){return new class_name;}\
- _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,class_name::CreateObject)\
- /************************************************************************/
- /* 對CObject特殊處理。 */
- /************************************************************************/
- class CObject
- {
- public:
- CObject()
- {
- //cout<<"CObject constructor!"<<endl;
- }
- ~CObject()
- {
- //cout<<"CObject destructor!"<<endl;
- }
- public:
- virtual CRuntimeClass*GetRuntimeClass();
- static CRuntimeClass ClassCObject;
- public:
- bool IsKindOf(CRuntimeClass*pClass)
- {
- CRuntimeClass *pThis=GetRuntimeClass();
- for(;pThis;pThis=pThis->m_pBaseClasss)
- {
- if(pThis==pClass)
- {
- return true;
- }
- }
- return false;
- }
- };
- class CRuntimeClass CObject:: ClassCObject=
- {
- "CObject",sizeof(CObject),0xFFFF,NULL,NULL,NULL
- };
- static AFX_CLASSINIT _init_CObject(&CObject:: ClassCObject);
- CRuntimeClass *CObject::GetRuntimeClass()
- {
- return &CObject::ClassCObject;
- }
- CRuntimeClass*CRuntimeClass::pFirstClass=NULL;
- /************************************************************************/
- /* CCmdTarget是消息傳遞的終點,因此在實現時不能使用BEGIN_MESSAGE_MAP */
- /************************************************************************/
- class CCmdTarget:public CObject
- {
- DECLARE_DYNCREATE(CCmdTarget)
- DECLARE_MESSAGE_MAP()
- public:
- CCmdTarget()
- {
- //cout<<"CCmdTarget constructor!"<<endl;
- //CreateObject();
- }
- ~CCmdTarget()
- {
- //cout<<"CCmdTarget destructor!"<<endl;
- }
- public:
- };
- IMPLEMENT_DYNCREATE(CCmdTarget,CObject)
- AFX_MSGMAP CCmdTarget::messageMap=
- {NULL,CCmdTarget::_messageEntries};
- AFX_MSGMAP_ENTRY CCmdTarget::_messageEntries[]=
- {
- {0,0,10,0,AfxSig_end,0},
- {0,0,0,0,AfxSig_end,0}
- };
- AFX_MSGMAP*CCmdTarget::GetMessageMap()const
- {
- return &CCmdTarget::messageMap;
- }
- class CWnd:public CCmdTarget
- {
- DECLARE_DYNCREATE(CWnd)
- DECLARE_MESSAGE_MAP()
- public:
- CWnd()
- {
- //cout<<"CWnd constructor"<<endl;
- }
- ~CWnd()
- {
- //cout<<"CWnd destructor"<<endl;
- }
- public:
- virtual bool Create()
- {
- cout<<"CWnd::Create"<<endl;
- CreateEx();
- return true;
- }
- bool CreateEx()
- {
- cout<<"CWnd::CreateEx"<<endl;
- PreCreateWindow();
- return true;
- }
- virtual bool PreCreateWindow()
- {
- cout<<"CWnd::PreCreateWindow"<<endl;
- return true;
- }
- };
- IMPLEMENT_DYNCREATE(CWnd,CCmdTarget)
- class CView :public CWnd
- {
- DECLARE_DYNCREATE(CView)
- DECLARE_MESSAGE_MAP()
- public:
- CView()
- {
- //cout<<"CView constructor"<<endl;
- }
- ~CView()
- {
- //cout<<"CView destructor"<<endl;
- }
- };
- IMPLEMENT_DYNCREATE(CView,CWnd)
- class CFrameWnd:public CWnd
- {
- DECLARE_DYNCREATE(CFrameWnd)
- DECLARE_MESSAGE_MAP()
- public:
- CFrameWnd()
- {
- //cout<<"CFrameWnd constructor"<<endl;
- }
- ~CFrameWnd()
- {
- //cout<<"CFrameWnd destructor"<<endl;
- }
- public:
- virtual bool Create()
- {
- cout<<"CFrameWnd::Create"<<endl;
- CreateEx();
- return true;
- }
- virtual bool PreCreateWindow()
- {
- cout<<"CFrameWnd::PreCreateWindow"<<endl;
- return true;
- }
- };
- IMPLEMENT_DYNCREATE(CFrameWnd,CWnd)
- class CWinThread:public CCmdTarget
- {
- public:
- CWinThread()
- {
- //cout<<"CWinThread constructor"<<endl;
- }
- ~CWinThread()
- {
- //cout<<"CWinThread destructor"<<endl;
- }
- public:
- virtual bool InitInstance()
- {
- cout<<"CWinThread::InitInstance"<<endl;
- return true;
- }
- virtual bool Run()
- {
- cout<<"CWinThread::Run"<<endl;
- return true;
- }
- };
- class CWinApp:public CWinThread
- {
- DECLARE_MESSAGE_MAP()
- public:
- CWinApp()
- {
- //cout<<"CWinApp Constructor "<<endl;
- m_currentApp=this;
- }
- ~CWinApp()
- {
- //cout<<"CWinApp destructor "<<endl;
- }
- virtual bool InitApplication()
- {
- cout<<"CWinApp::InitApplication"<<endl;
- return true;
- }
- virtual bool InitInstance()
- {
- cout<<"CWinApp:InitInstance"<<endl;
- return true;
- }
- virtual bool Run()
- {
- cout<<"CWinApp::Run"<<endl;
- return CWinThread::Run();
- }
- public:
- CWinApp*m_currentApp;
- CFrameWnd*m_currentFrameWnd;
- };
- class CDocument:public CCmdTarget
- {
- DECLARE_MESSAGE_MAP()
- public:
- CDocument()
- {
- //cout<<"CDocument constructor "<<endl;
- }
- ~CDocument()
- {
- //cout<<"CDocunment destructor "<<endl;
- }
- };
- class CMyFrameWnd:public CFrameWnd
- {
- DECLARE_DYNCREATE(CMyFrameWnd)
- DECLARE_MESSAGE_MAP()
- public:
- CMyFrameWnd()
- {
- //cout<<"CMyFrameWnd constructor "<<endl;
- Create();
- }
- ~CMyFrameWnd()
- {
- //cout<<"CMyFrameWnd destructor "<<endl;
- }
- };
- IMPLEMENT_DYNCREATE(CMyFrameWnd,CFrameWnd)
- class CMyWinApp:public CWinApp
- {
- DECLARE_MESSAGE_MAP()
- public:
- CMyWinApp()
- {
- //cout<<"CMyWinApp constructor "<<endl;
- }
- ~CMyWinApp()
- {
- //cout<<"CMyWinApp destructor "<<endl;
- }
- public:
- bool InitInstance()
- {
- cout<<"CMyWinApp::InitInstance"<<endl;
- m_currentFrameWnd=new CMyFrameWnd;
- return true;
- }
- };
- BEGIN_MESSAGE_MAP(CWnd,CCmdTarget)
- ON_COMMAND(1,0)
- END_MESSAGE_MAP()
- BEGIN_MESSAGE_MAP(CFrameWnd,CWnd)
- ON_COMMAND(2,0)
- END_MESSAGE_MAP()
- BEGIN_MESSAGE_MAP(CDocument,CCmdTarget)
- ON_COMMAND(3,0)
- END_MESSAGE_MAP()
- BEGIN_MESSAGE_MAP(CView,CWnd)
- ON_COMMAND(4,0)
- END_MESSAGE_MAP()
- BEGIN_MESSAGE_MAP(CWinApp,CCmdTarget)
- ON_COMMAND(5,0)
- END_MESSAGE_MAP()
- BEGIN_MESSAGE_MAP(CMyWinApp,CWinApp)
- ON_COMMAND(6,0)
- END_MESSAGE_MAP()
- BEGIN_MESSAGE_MAP(CMyFrameWnd,CFrameWnd)
- ON_COMMAND(7,0)
- END_MESSAGE_MAP()
- CMyWinApp myApp;
- CWinApp*AfxGetApp()
- {
- return myApp.m_currentApp;
- }
- void printAllMsgMapping(AFX_MSGMAP*p)
- {
- for(;p;p=p->pBaseMessageMap)
- {
- for(int i=0;p->lpEntries[i].nID;i++)
- {
- cout<<p->lpEntries[i].nID<<endl;
- }
- }
- }
- int main(int argc,char**argv)
- {
- CWinApp *pApp=AfxGetApp();
- pApp->InitApplication();
- pApp->InitInstance();
- pApp->Run();
- CRuntimeClass *pClass;
- CObject *pOb;
- cout<<"以下爲類型型錄鏈表中的所有類的名稱:"<<endl;
- for(pClass=CRuntimeClass::pFirstClass;pClass;pClass=pClass->m_pBaseClasss)
- {
- cout<<pClass->m_lpszClassName<<endl;
- }
- CMyFrameWnd *pMyFrame=(CMyFrameWnd*)pApp->m_currentFrameWnd;
- printAllMsgMapping(pMyFrame->GetMessageMap());
- cout<<endl;
- CDocument *pDoc=new CDocument;
- printAllMsgMapping(pDoc->GetMessageMap());
- while(1)
- {
- pClass=CRuntimeClass::Load();
- if(!pClass)
- {
- cout<<"找不到此類!!!"<<endl;
- }
- else
- {
- pOb=pClass->CreateObject();
- if(pOb)
- {
- cout<<"創建成功!"<<endl;
- }
- }
- }
- return 0;
- }