深入淺出MFC學習筆記(第三章:MFC六大關鍵技術之仿真:消息映射)

消息映射機制

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;

}

    以下爲包含動態創建、類型識別、消息映射的完整代碼:

  1. #include<iostream>  
  2. #include<windows.h>  
  3. #include<string>  
  4. using namespace std;  
  5. class CCmdTarget;  
  6. typedef void (CCmdTarget::*AFX_PMSG)(void);  
  7.   
  8. //消息映射表元素類型。  
  9. enum AfxSig  
  10. {  
  11.     AfxSig_end=0,  
  12.     AfxSig_vv,  
  13. };  
  14. struct AFX_MSGMAP_ENTRY  
  15. {  
  16.     UINT nMessage;  
  17.     UINT nCode;  
  18.     UINT nID;  
  19.     UINT nLastID;  
  20.     UINT nSig;  
  21.     AFX_PMSG pfn;  
  22. };  
  23. struct AFX_MSGMAP  
  24. {  
  25.     AFX_MSGMAP *pBaseMessageMap;//指向基類的本結構。  
  26.     AFX_MSGMAP_ENTRY*lpEntries;//本類的消息映射表。  
  27. };  
  28.   
  29.   
  30. #define DECLARE_MESSAGE_MAP()\  
  31.   public:\  
  32.     static AFX_MSGMAP_ENTRY _messageEntries[];\  
  33.     static AFX_MSGMAP messageMap;\  
  34.     virtual AFX_MSGMAP*GetMessageMap()const;\  
  35.   
  36. #define BEGIN_MESSAGE_MAP(class_name,base_class)\  
  37.     AFX_MSGMAP*class_name::GetMessageMap()const\  
  38.        {return &class_name::messageMap;}\  
  39.     AFX_MSGMAP class_name::messageMap={&base_class::messageMap,class_name::_messageEntries};\  
  40.     AFX_MSGMAP_ENTRY class_name::_messageEntries[]=\  
  41.       {  
  42.   
  43. #define ON_COMMAND(id,memFunc)\  
  44.       {WM_COMMAND,0,id,id,AfxSig_vv,(AFX_PMSG)memFunc },\  
  45.   
  46. #define END_MESSAGE_MAP()\  
  47.        {0,0,0,0,AfxSig_end,(AFX_PMSG)0}\  
  48.         };  
  49.   
  50.          
  51.   
  52.   
  53. class CObject;  
  54. class CRuntimeClass  
  55. {  
  56. public:  
  57.     char* m_lpszClassName;//對象所屬類名  
  58.     int m_nObjectSize;//對象大小  
  59.     int m_wSchema;//模式號  
  60.     CObject*(PASCAL*m_pfnCreateObject)();//構建函數,抽象類爲NULL  
  61.     CRuntimeClass *m_pBaseClasss;//基類CRuntimeClass對象指針。  
  62.     static CRuntimeClass *pFirstClass;//鏈表頭指針。static  
  63.     CRuntimeClass  *m_pNextClass;//下一指針。  
  64. public:  
  65.     CObject*CreateObject()  
  66.     {  
  67.         if(m_pfnCreateObject==NULL)  
  68.         {  
  69.             cout<<"該類型不支持動態創建!!"<<endl;  
  70.             return NULL;  
  71.         }  
  72.         CObject*pClass=(*m_pfnCreateObject)();  
  73.         return pClass;  
  74.     }  
  75.     static CRuntimeClass*Load()  
  76.     {  
  77.         cout<<"請輸入要動態創建的類名:";  
  78.         string s;  
  79.         cin>>s;  
  80.         for(CRuntimeClass*pClass=pFirstClass;pClass;pClass=pClass->m_pBaseClasss)  
  81.         {  
  82.             if(pClass->m_lpszClassName==s)  
  83.             {  
  84.                 return pClass;  
  85.             }  
  86.         }  
  87.         return NULL;  
  88.     }  
  89. };  
  90.   
  91. class AFX_CLASSINIT  
  92. {  
  93. public:  
  94.     AFX_CLASSINIT(CRuntimeClass*pNewClass)//構造函數  
  95.       {   
  96.          pNewClass->m_pNextClass=CRuntimeClass::pFirstClass;  
  97.         CRuntimeClass::pFirstClass =pNewClass;  
  98.       }  
  99.  };  
  100.   
  101. /************************************************************************/  
  102. /* 動態類型識別宏定義                 
  103. //與CRuntimeClass類中的構建函數相區別。此處的CreateObject函數在每個類中都以static成員函數存在,用以 
  104. //初始化類型型錄表,而CRuntimeClass中的CreateObject用於調用每個類的構建函數。僅僅是函數名相同罷了。*/  
  105. /************************************************************************/  
  106.   
  107. #define DECLARE_DYNAMIC(class_name)\  
  108.      public:\  
  109.            static CRuntimeClass Class##class_name;\  
  110.            virtual CRuntimeClass*GetRuntimeClass()const;\  
  111.   
  112.   
  113. #define DECLARE_DYNCREATE(class_name)\  
  114.        DECLARE_DYNAMIC(class_name)\  
  115.        static CObject*PASCAL CreateObject();\  
  116.   
  117. #define RUNTIME_CLASS(class_name)\  
  118.     (&class_name::Class##class_name)\  
  119.   
  120. #define _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,wSchema,pfnNew)\  
  121.     class CRuntimeClass class_name::Class##class_name ={\  
  122.     #class_name,\  
  123.     sizeof(class_name),wSchema,pfnNew,RUNTIME_CLASS(base_class_name),NULL};\  
  124.     static AFX_CLASSINIT _init##class_name( RUNTIME_CLASS(class_name));\  
  125.     CRuntimeClass *class_name::GetRuntimeClass()const\  
  126.     {return &class_name::Class##class_name;}//此處將class_name寫成了classname花了一兩天才查出來。啊啊啊啊啊。20120605  
  127.   
  128.   
  129. #define IMPLEMENT_DYNAMIC(class_name,base_class_name)\  
  130.     _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL)\  
  131.   
  132. #define IMPLEMENT_DYNCREATE(class_name,base_class_name)\  
  133.     CObject*PASCAL class_name::CreateObject(){return new class_name;}\  
  134.     _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,class_name::CreateObject)\  
  135.   
  136.   
  137. /************************************************************************/  
  138. /*  對CObject特殊處理。                                                   */  
  139. /************************************************************************/  
  140. class CObject  
  141. {  
  142. public:  
  143.     CObject()  
  144.     {  
  145.         //cout<<"CObject constructor!"<<endl;  
  146.     }  
  147.     ~CObject()  
  148.     {  
  149.         //cout<<"CObject destructor!"<<endl;  
  150.     }  
  151. public:  
  152.     virtual CRuntimeClass*GetRuntimeClass();  
  153.     static CRuntimeClass  ClassCObject;  
  154. public:  
  155.     bool IsKindOf(CRuntimeClass*pClass)  
  156.     {  
  157.         CRuntimeClass *pThis=GetRuntimeClass();  
  158.         for(;pThis;pThis=pThis->m_pBaseClasss)  
  159.         {  
  160.             if(pThis==pClass)  
  161.             {  
  162.                 return true;  
  163.             }  
  164.         }  
  165.         return false;  
  166.     }  
  167. };  
  168. class CRuntimeClass CObject:: ClassCObject=  
  169. {  
  170.    "CObject",sizeof(CObject),0xFFFF,NULL,NULL,NULL  
  171. };  
  172. static AFX_CLASSINIT _init_CObject(&CObject:: ClassCObject);  
  173. CRuntimeClass *CObject::GetRuntimeClass()  
  174. {  
  175.     return &CObject::ClassCObject;  
  176. }  
  177. CRuntimeClass*CRuntimeClass::pFirstClass=NULL;  
  178.   
  179. /************************************************************************/  
  180. /* CCmdTarget是消息傳遞的終點,因此在實現時不能使用BEGIN_MESSAGE_MAP           */  
  181. /************************************************************************/  
  182. class CCmdTarget:public CObject  
  183. {  
  184.     DECLARE_DYNCREATE(CCmdTarget)  
  185.     DECLARE_MESSAGE_MAP()  
  186. public:  
  187.     CCmdTarget()  
  188.     {  
  189.         //cout<<"CCmdTarget constructor!"<<endl;  
  190.         //CreateObject();  
  191.     }  
  192.     ~CCmdTarget()  
  193.     {  
  194.         //cout<<"CCmdTarget destructor!"<<endl;  
  195.     }     
  196. public:  
  197.   
  198.   
  199. };  
  200. IMPLEMENT_DYNCREATE(CCmdTarget,CObject)  
  201.   
  202. AFX_MSGMAP CCmdTarget::messageMap=  
  203. {NULL,CCmdTarget::_messageEntries};  
  204. AFX_MSGMAP_ENTRY CCmdTarget::_messageEntries[]=  
  205. {  
  206.     {0,0,10,0,AfxSig_end,0},  
  207.     {0,0,0,0,AfxSig_end,0}  
  208. };  
  209. AFX_MSGMAP*CCmdTarget::GetMessageMap()const  
  210. {  
  211.     return &CCmdTarget::messageMap;  
  212. }  
  213.   
  214. class CWnd:public CCmdTarget  
  215. {  
  216.     DECLARE_DYNCREATE(CWnd)  
  217.     DECLARE_MESSAGE_MAP()  
  218. public:  
  219.     CWnd()  
  220.     {  
  221.         //cout<<"CWnd constructor"<<endl;  
  222.     }  
  223.     ~CWnd()  
  224.     {  
  225.         //cout<<"CWnd destructor"<<endl;  
  226.     }  
  227. public:  
  228.     virtual bool Create()  
  229.     {  
  230.         cout<<"CWnd::Create"<<endl;  
  231.         CreateEx();  
  232.         return true;  
  233.     }  
  234.     bool CreateEx()  
  235.     {  
  236.         cout<<"CWnd::CreateEx"<<endl;  
  237.         PreCreateWindow();  
  238.         return true;  
  239.     }  
  240.     virtual bool PreCreateWindow()  
  241.     {  
  242.         cout<<"CWnd::PreCreateWindow"<<endl;  
  243.         return true;  
  244.     }  
  245. };  
  246. IMPLEMENT_DYNCREATE(CWnd,CCmdTarget)  
  247.   
  248. class CView :public CWnd  
  249. {  
  250.     DECLARE_DYNCREATE(CView)  
  251.     DECLARE_MESSAGE_MAP()  
  252. public:  
  253.     CView()  
  254.     {  
  255.         //cout<<"CView constructor"<<endl;  
  256.   
  257.     }  
  258.     ~CView()  
  259.     {  
  260.         //cout<<"CView destructor"<<endl;  
  261.     }  
  262.   
  263. };  
  264. IMPLEMENT_DYNCREATE(CView,CWnd)  
  265.   
  266. class CFrameWnd:public CWnd  
  267. {  
  268.     DECLARE_DYNCREATE(CFrameWnd)  
  269.     DECLARE_MESSAGE_MAP()  
  270. public:  
  271.     CFrameWnd()  
  272.     {  
  273.         //cout<<"CFrameWnd constructor"<<endl;  
  274.   
  275.     }  
  276.     ~CFrameWnd()  
  277.     {  
  278.         //cout<<"CFrameWnd destructor"<<endl;  
  279.     }  
  280. public:  
  281.     virtual bool Create()  
  282.     {  
  283.         cout<<"CFrameWnd::Create"<<endl;  
  284.         CreateEx();  
  285.         return true;  
  286.     }  
  287.     virtual bool PreCreateWindow()  
  288.     {  
  289.         cout<<"CFrameWnd::PreCreateWindow"<<endl;  
  290.         return true;  
  291.     }  
  292. };  
  293. IMPLEMENT_DYNCREATE(CFrameWnd,CWnd)  
  294.   
  295. class CWinThread:public CCmdTarget  
  296. {  
  297. public:  
  298.     CWinThread()  
  299.     {  
  300.         //cout<<"CWinThread constructor"<<endl;  
  301.     }  
  302.     ~CWinThread()  
  303.     {  
  304.         //cout<<"CWinThread destructor"<<endl;  
  305.     }  
  306. public:  
  307.     virtual bool InitInstance()  
  308.     {  
  309.         cout<<"CWinThread::InitInstance"<<endl;  
  310.         return true;  
  311.     }  
  312.     virtual bool Run()  
  313.     {  
  314.         cout<<"CWinThread::Run"<<endl;  
  315.         return true;  
  316.     }  
  317. };  
  318. class CWinApp:public CWinThread  
  319. {  
  320.     DECLARE_MESSAGE_MAP()  
  321. public:  
  322.     CWinApp()  
  323.     {  
  324.         //cout<<"CWinApp Constructor "<<endl;  
  325.         m_currentApp=this;  
  326.     }  
  327.     ~CWinApp()  
  328.     {  
  329.         //cout<<"CWinApp destructor "<<endl;  
  330.     }  
  331.     virtual bool InitApplication()  
  332.     {  
  333.         cout<<"CWinApp::InitApplication"<<endl;  
  334.         return true;  
  335.       
  336.     }  
  337.     virtual bool InitInstance()  
  338.     {  
  339.         cout<<"CWinApp:InitInstance"<<endl;  
  340.         return true;  
  341.     }  
  342.     virtual bool Run()  
  343.     {  
  344.         cout<<"CWinApp::Run"<<endl;  
  345.         return CWinThread::Run();  
  346.     }  
  347. public:  
  348.     CWinApp*m_currentApp;  
  349.     CFrameWnd*m_currentFrameWnd;  
  350. };  
  351. class CDocument:public CCmdTarget  
  352. {  
  353.     DECLARE_MESSAGE_MAP()  
  354. public:  
  355.     CDocument()  
  356.     {  
  357.         //cout<<"CDocument constructor "<<endl;  
  358.     }  
  359.     ~CDocument()  
  360.     {  
  361.         //cout<<"CDocunment destructor "<<endl;  
  362.     }  
  363. };  
  364. class CMyFrameWnd:public CFrameWnd  
  365. {  
  366.     DECLARE_DYNCREATE(CMyFrameWnd)  
  367.     DECLARE_MESSAGE_MAP()  
  368. public:  
  369.     CMyFrameWnd()  
  370.     {  
  371.         //cout<<"CMyFrameWnd constructor "<<endl;  
  372.         Create();  
  373.     }  
  374.     ~CMyFrameWnd()  
  375.     {  
  376.         //cout<<"CMyFrameWnd destructor "<<endl;  
  377.     }  
  378. };  
  379. IMPLEMENT_DYNCREATE(CMyFrameWnd,CFrameWnd)  
  380.   
  381. class CMyWinApp:public CWinApp  
  382. {  
  383.     DECLARE_MESSAGE_MAP()  
  384. public:  
  385.     CMyWinApp()  
  386.     {  
  387.         //cout<<"CMyWinApp constructor "<<endl;  
  388.           
  389.     }  
  390.     ~CMyWinApp()  
  391.     {  
  392.         //cout<<"CMyWinApp destructor "<<endl;  
  393.     }  
  394. public:  
  395.     bool InitInstance()  
  396.     {  
  397.         cout<<"CMyWinApp::InitInstance"<<endl;  
  398.         m_currentFrameWnd=new CMyFrameWnd;  
  399.         return true;  
  400.     }  
  401. };  
  402. BEGIN_MESSAGE_MAP(CWnd,CCmdTarget)  
  403.     ON_COMMAND(1,0)  
  404. END_MESSAGE_MAP()  
  405.   
  406. BEGIN_MESSAGE_MAP(CFrameWnd,CWnd)  
  407.     ON_COMMAND(2,0)  
  408. END_MESSAGE_MAP()  
  409.   
  410. BEGIN_MESSAGE_MAP(CDocument,CCmdTarget)  
  411.     ON_COMMAND(3,0)  
  412. END_MESSAGE_MAP()   
  413.   
  414. BEGIN_MESSAGE_MAP(CView,CWnd)  
  415.     ON_COMMAND(4,0)  
  416. END_MESSAGE_MAP()  
  417.   
  418. BEGIN_MESSAGE_MAP(CWinApp,CCmdTarget)  
  419.     ON_COMMAND(5,0)  
  420. END_MESSAGE_MAP()  
  421.   
  422. BEGIN_MESSAGE_MAP(CMyWinApp,CWinApp)  
  423.     ON_COMMAND(6,0)  
  424. END_MESSAGE_MAP()  
  425.   
  426. BEGIN_MESSAGE_MAP(CMyFrameWnd,CFrameWnd)  
  427.     ON_COMMAND(7,0)  
  428. END_MESSAGE_MAP()  
  429.   
  430. CMyWinApp myApp;  
  431. CWinApp*AfxGetApp()  
  432. {  
  433.     return myApp.m_currentApp;  
  434. }  
  435. void printAllMsgMapping(AFX_MSGMAP*p)  
  436. {  
  437.     for(;p;p=p->pBaseMessageMap)  
  438.     {  
  439.         for(int i=0;p->lpEntries[i].nID;i++)  
  440.         {  
  441.             cout<<p->lpEntries[i].nID<<endl;  
  442.         }  
  443.     }  
  444. }  
  445.   
  446. int main(int argc,char**argv)  
  447. {  
  448.     CWinApp *pApp=AfxGetApp();  
  449.     pApp->InitApplication();  
  450.     pApp->InitInstance();  
  451.     pApp->Run();  
  452.   
  453.     CRuntimeClass *pClass;  
  454.     CObject *pOb;  
  455.     cout<<"以下爲類型型錄鏈表中的所有類的名稱:"<<endl;  
  456.     for(pClass=CRuntimeClass::pFirstClass;pClass;pClass=pClass->m_pBaseClasss)  
  457.     {  
  458.         cout<<pClass->m_lpszClassName<<endl;  
  459.     }  
  460.     CMyFrameWnd *pMyFrame=(CMyFrameWnd*)pApp->m_currentFrameWnd;  
  461.     printAllMsgMapping(pMyFrame->GetMessageMap());  
  462.     cout<<endl;  
  463.   
  464.     CDocument *pDoc=new CDocument;  
  465.     printAllMsgMapping(pDoc->GetMessageMap());  
  466.   
  467.     while(1)  
  468.     {  
  469.         pClass=CRuntimeClass::Load();  
  470.         if(!pClass)  
  471.         {  
  472.             cout<<"找不到此類!!!"<<endl;  
  473.         }  
  474.         else  
  475.         {  
  476.             pOb=pClass->CreateObject();  
  477.             if(pOb)  
  478.             {  
  479.                 cout<<"創建成功!"<<endl;  
  480.             }  
  481.   
  482.         }         
  483.     }  
  484.     return 0;  
  485. }  


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章