MFC消息映射深入挖掘1

在MFC中,消息分为三大类:
1、命令消息

常见的就是由菜单或快捷键或工具栏产生的消息,MFC通过菜单项的识别码分辨来自各处的消息。

以下是两个例子:

//**.h DECLARE_MESSAGE_MAP() afx_msg void OnFileWrite(); afx_msg void OnFileRead(); //**.cpp BEGIN_MESSAGE_MAP(CtestView, CRichEditView) ON_COMMAND(IDM_FILE_WRITE, &CtestView::OnFileWrite) ON_COMMAND(IDM_FILE_READ, &CtestView::OnFileRead) END_MESSAGE_MAP() ... CtestView::OnFileRead()//响应函数 {..}

 

凡是派生于CCmdTarget的类,均有资格接收命令消息。

 

2、标准消息

除命令消息外,任何以WM_开头的消息都是标准消息。

以下示例了一个WM_CREATE消息:

//**.h DECLARE_MESSAGE_MAP() afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); //**.cpp BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_WM_CREATE() END_MESSAGE_MAP() ... int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)//消息响应 {...}

 

凡派生至CWnd的类,均可以接收此类消息。也就是说,CWnd及其子类,可以接收命令消息和标准消息

 

3、控件消息

称为Control Notification,这种消息由控件产生,是为了向其父窗口(通常为对话框)通知某种消息。

以下的例子说明了listbox中的项目被选择时,产生一个LBN_SELCHANGE消息。

//**.h DECLARE_MESSAGE_MAP() afx_msg void OnLbnSelchangeList1(); //**.cpp BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) ON_LBN_SELCHANGE(IDC_LIST1, &CAboutDlg::OnLbnSelchangeList1) END_MESSAGE_MAP() ... void CAboutDlg::OnLbnSelchangeList1()//消息响应 {...}   

 下面说说消息映射。消息映射其实一个巨大的网,一种数据结构。作用是决定消息的流动路线。

上面的消息映射,都出现了四个奇怪的宏。

DECLARE_MESSAGE_MAP()

BEGIN_MESSAGE_MAP

ON_COMMAND

END_MESSAGE_MAP

其中ON_COMMAND是命令消息的宏,当然也可以是标准消息或控件消息,以ON_开头定义。

如:ON_WM_CREATE,ON_LBN_SELCHANGE

 

下面我们来层层挖掘.

首先是DECLARE_MESSAGE_MAP宏,这个宏声明了一个MessageMap数据类型

#define DECLARE_MESSAGE_MAP() / protected: / static const AFX_MSGMAP* PASCAL GetThisMessageMap(); / virtual const AFX_MSGMAP* GetMessageMap() const; /

这里看到AFX_MSGMAP,定义如下:

 

struct AFX_MSGMAP { const AFX_MSGMAP* PBaseMap; const AFX_MSGMAP_ENTRY* lpEntries; }   

可以看出,pBaseMap指向基类的MessageMap,这个指针提供了一个走访整个继承链表的方法。而lpEntries指向了AFX_MSGMAP_ENTRY结构体.这个结构便是消息映射的网络的单个节点。

 

这个结构体的定义如下,这个结构体的作用是让消息nMessage对应于函数pfn。

struct AFX_MSGMAP_ENTRY { UINT nMessage; // windows message UINT nCode; // control code or WM_NOTIFY code UINT nID; // control ID (or 0 for windows messages) UINT nLastID; // used for entries specifying a range of control id's UINT_PTR nSig; // signature type (action) or pointer to message # AFX_PMSG pfn; // routine to call (or special value) };

其中pfn的定义为函数的指针

typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);

 

到此为止,只是声明了一种类型,并没有真正的实例化。

 

 

上面已经定义了一个MessageMap的结构,谨记这个结构

struct AFX_MSGMAP

{

    const AFX_MSGMAP* PBaseMap;

    const AFX_MSGMAP_ENTRY* lpEntries;

}

下面的BEGIN/ON/END就是来实例化这个结构,以组成一个庞大的消息映射网络。

下面是详细定义BEGIN/ON/END

 

#define BEGIN_MESSAGE_MAP(theClass, baseClass) / PTM_WARNING_DISABLE / const AFX_MSGMAP* theClass::GetMessageMap() const / { return GetThisMessageMap(); } / const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() / { / typedef theClass ThisClass; / typedef baseClass TheBaseClass; / static const AFX_MSGMAP_ENTRY _messageEntries[] = / { #define END_MESSAGE_MAP() / {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } / }; / static const AFX_MSGMAP messageMap = / { &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; / return &messageMap; /   

于是,对于这样的宏

BEGIN_MESSAGE_MAP(CtestView, CRichEditView)
ON_WM_CREATE()
ON_COMMAND(IDM_FILE_READ, &CtestView::OnFileRead)

END_MESSAGE_MAP()

 

其中ON_WM_CREATE被定义为:(afxmsg_.h中)

#define ON_WM_CREATE() / { WM_CREATE, 0, 0, 0, AfxSig_is, / (AFX_PMSG) (AFX_PMSGW) / (static_cast< int (AFX_MSG_CALL CWnd::*)(LPCREATESTRUCT) > ( &ThisClass :: OnCreate)) },

 

ON_COMMAND被定义为:(afxmsg_.h中)

#define ON_COMMAND(id, memberFxn) / { WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSigCmd_v, / static_cast<AFX_PMSG> (memberFxn) },

 

展开后就是

const AFX_MSGMAP* CtestView::GetMessageMap() const { return GetThisMessageMap(); } const AFX_MSGMAP* PASCAL CtestView::GetThisMessageMap() { typedef CtestView ThisClass; typedef CRichEditView TheBaseClass; static const AFX_MSGMAP_ENTRY _messageEntries[] = { {WM_CREATE, 0, 0, 0, AfxSig_is,(AFX_PMSG) (AFX_PMSGW)(static_cast< int (AFX_MSG_CALL CWnd::*)(LPCREATESTRUCT) > ( &ThisClass :: OnCreate)) } {WM_COMMAND,CN_COMMAND,(WORD)IDM_FILE_READ,(WORD)IDM_FILE_READ,AfxSigCmd_v,static_cast<AFX_PMSG> (&CtestView::OnFileRead) }, {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } }; static const AFX_MSGMAP messageMap = { &CRichEditView::GetThisMessageMap, &_messageEntries[0] }; return &messageMap;   

简单的文字替换,呵呵,这样就一目了然了。

经过以上的处理,现在为CtestView生成了一个messagemap

CtestView::messagemap

{

       pBaseMap->Cview::messagemap;

       lpEntries-> messageEntries[];

}

 

所有派生自CCmdTarget的类都可以接收消息,也就是说,这些类都有一个DECLARE/BEGIN/END宏组,但请注意,CWinThread没有,即CWinApp是直接跳到CCmdTarget的,定义如下:

BEGIN_MESSAGE_MAP(CWinAppCCmdTarget)

好了,通过这些宏,我们构造了一个庞大的消息映射网络.

 

 

 

下一章讨论,MFC如何利用这个网络进行消息映射,到底是谁把消息放入messagemap中,谁执行消息的比较操作等等等。这些都会在下一章揭晓。

 

 

 

你可能感兴趣的:(struct,网络,command,File,mfc,pascal)