一、消息映射机制的使用
1、必须由CCmdTarget类直接派生或者间接派生
2、在类内写声明宏DECLARE_MESSAGE_MAP()
3、在类外写实现宏BEGIN_MESSAGE_MPA(CMainFrameWnd, CFrameWnd)
二、写一个简单的窗口应用程序
1 //窗口框架类
2 class CMainFrameWnd : public CFrameWnd
3 {
4 //DECLARE_MESSAGE_MAP()
5 private:
6 static const AFX_MSGMAP_ENTRY _messageEntries[];
7 /*struct AFX_MSGMAP_ENTRY
8 {
9 UINT nMessage; // 消息ID
10 UINT nCode; // 通知码
11 UINT nID; // 命令ID/控件ID
12 UINT nLastID; // 最后一个控件ID
13 UINT nSig; // 处理消息的函数的类型
14 AFX_PMSG pfn; // 处理消息的函数的地址
15 };*/
16 protected:
17 static AFX_DATA const AFX_MSGMAP messageMap;
18 /*struct AFX_MSGMAP
19 {
20
21 const AFX_MSGMAP* pBaseMap; //获取父类静态变量地址
22 const AFX_MSGMAP_ENTRY* lpEntries; //获取相应类的静态数组首地址
23 };*/
24 virtual const AFX_MSGMAP* GetMessageMap() const;
25 protected:
26 afx_msg int OnCreate( LPCREATESTRUCT lpCreateStruct );
27 };
28 //BEGIN_MESSAGE_MAP(CMainFrameWnd, CFrameWnd)
29
30 //获取本类的静态变量地址(获取链表的头结点)
31 const AFX_MSGMAP* CMainFrameWnd::GetMessageMap() const
32 {
33 return &CMainFrameWnd::messageMap;
34 }
35
36 AFX_COMDAT AFX_DATADEF const AFX_MSGMAP CMainFrameWnd::messageMap =
37 {
38 &CFrameWnd::messageMap,
39 &CMainFrameWnd::_messageEntries[0]
40 };
41
42 AFX_COMDAT const AFX_MSGMAP_ENTRY CMainFrameWnd::_messageEntries[] =
43 {
44 //ON_WM_CREATE()
45 { WM_CREATE, 0, 0, 0, AfxSig_is,
46 (AFX_PMSG)(AFX_PMSGW)(int (AFX_MSG_CALL CWnd::*)(LPCREATESTRUCT))&OnCreate },
47 //END_MESSAGE_MAP()
48 {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }
49 };
50
51 int CMainFrameWnd::OnCreate( LPCREATESTRUCT lpCreateStruct )
52 {
53 AfxMessageBox("创建窗口消息");
54 return CFrameWnd::OnCreate(lpCreateStruct);
55 }
56
57 //应用程序类
58 class CMyWinApp : public CWinApp
59 {
60 public:
61 CMyWinApp(void);
62 virtual BOOL InitInstance(void);
63 };
64
65 CMyWinApp::CMyWinApp(void)
66 {
67
68 }
69
70 CMyWinApp theApp;//唯一的全局应用程序对象
71
72 BOOL CMyWinApp::InitInstance(void)
73 {
74 CMainFrameWnd *pFrame = new CMainFrameWnd;
75 pFrame->Create(NULL, "MFCSummaryProcess");
76 m_pMainWnd = pFrame;
77 m_pMainWnd->ShowWindow(SW_SHOW);
78 m_pMainWnd->UpdateWindow();
79 return TRUE;
80 }
从上面的两个宏展开可以看出,在类中添加了一个静态数组,一个静态变量,和一个虚函数。
1) 静态数组:其元素类型为一个结构体,结构体里面主要是保存了消息和消息所对应的处理函数。
2)静态变量:类型为结构体,有两个成员,第一个成员是用来保存父类的静态变量地址,这样,就会形成一个链表,
第二个成员就是用来保存静态数组的首地址。
3)虚函数:获取当前类的静态变量的地址。
三、通过看源代码写伪代码来体会消息映射机制的过程
1 AfxWndProc(...)
2 {
3 return AfxCallWndProc(...);
4 {
5 lResult = pWnd->WindowProc(nMsg, wParam, lParam);
6 {
7 OnWndMsg(message, wParam, lParam, &lResult)
8 {
9 //获取自己创建的框架窗口类的静态变量地址(头结点)
10 const AFX_MSGMAP* pMessageMap = GetMessageMap();
11 {
12 return &CMainFrameWnd::messageMap;
13 }
14 //循环遍历
15 for (; pMessageMap != NULL; pMessageMap = pMessageMap->pBaseMap)
16 {
17 //查找数组中是否有与message相等的消息ID,如果有返回数组元素地址,否则继续遍历
18 if ((lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, message, 0, 0)) != NULL)
19 {
20 pMsgCache->lpEntry = lpEntry;
21 AfxUnlockGlobals(CRIT_WINMSGCACHE);
22 goto LDispatch;
23 }
24 }
25 LDispatch:
26 union MessageMapFunctions mmf;
27 //找到之后,把消息ID对应的消息处理函数地址存放到一个联合变量里
28 mmf.pfn = lpEntry->pfn;
29 nSig = lpEntry->nSig;
30 switch (nSig)
31 {...
32 case AfxSig_is:
33 lResult = (this->*mmf.pfn_is)((LPTSTR)lParam);
34 {
35 AfxMessageBox("创建窗口消息");
36 return CFrameWnd::OnCreate(lpCreateStruct);
37 }
38 break;...
39 }
40 }
41 }
42 }
43 }
通过伪代码我们可以总结出消息映射的过程:首先,通过自己创建的框架窗口类对象调用GetMessageMap()获取本类的静态变量的首地址,
也就是链表的头结点,然后进行遍历这个链表,先从头结点开始,通过头结点的第二个成员,访问静态数组,查找这个数组中是否有跟当前
消息一致的数组元素,如果有,就把这个元素的首地址保存起来,结束循环,然后把这个元素里的一个成员处理函数指针存放到一个联合里,
最后就调用这个指针所指向的函数;如果没有的话,继续遍历这个链表,重复之前的过程,如果找到,调用基类中消息所对应的处理函数,
如果pMessageMap为NULL,表示确实没有,那么再调用缺省的窗口处理函数。