~~~~终于快到MFC的6大关键技术的尽头了~~
Windows程序的活动依靠消息的流动,在前面我们已经很简单的看过了消息的处理方式,即一个一般化的switch/case比较操作,判断是否有对应的消息再执行处理对应的程序,为了让switch/case的操作简化,为了简化这一过程且为了后来更方便的添加消息,MFC中提供了一种消息映射表的做法。
消息映射表的建立其实就是统一的在需要处理消息的类之中加入了一些用来记录消息的定义,然后为了保证类的编写的方便化,统一地使用宏定义来降低代码的冗余~~.
这过程中还考虑到一些消息的传递,所以还要建立一些独特的联系保证消息的传递的执行,其实具体做法就和之前的自动类型识别很是相似
接下来让我们一个一个的来看一看:
首先声明一个这样的数据结构,其中包含下一个消息条目的指针和本身消息条目的指针,具体如下:
struct AFX_MSGMAP
{
AFX_MSGMAP* pBaseMessageMap;
AFX_MSGMAP_ENTRY* lpEntries;
};
其中AFX_MSGMAP_ENTRY是这样一个数据结构:
struct AFX_MSGMAP_ENTRY
{
UINT nMessage;
UINT nCode;
UINT nID;
UINT nLastID;
UINT nSig;
AFX_PMSG pfn;
};
该数据结构主要用来储存消息条目,在这个数据结构中AFX_PMSG是一个函数指针,可以指向CCmdTarget的一个无参数无返回值的成员函数,具体定义如下:
typedef void (CCmdTarget::*AFX_PMSG)(void);
有了这些基础材料之后,我们就可以开始着手实现我们消息映射表了,首先我们需要在需要处理消息的类中加入如下的宏:
#define DECLARE_MESSAGE_MAP() \
static AFX_MSGMAP_ENTRY _messageEntries[]; \
static AFX_MSGMAP messageMap; \
virtual AFX_MSGMAP* GetMessageMap() const;
宏的第一部分是一个数组,用来保存对应类的所有的消息条目,第2个则是特定的数据结构用来储存父类的该结构索引和本身条目的索引,第3个方法则是为了获取第2个成员,该组宏的具体实现宏如下:
#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 } \
};
在这组宏之中,我们还可以添加一些消息条目,例如:
BEGIN_MESSAGE_MAP(CWinApp, CCmdTarget)
ON_COMMAND(CWinAppid, 0)
END_MESSAGE_MAP()
在我们需要处理消息的对象之中加入了消息之后,我们的对象便拥有了对应的消息映射表
且我们可以通过我们创建的结构AFX_MSGMAP来实现消息的流动,将一消息从子类对象传递到父类对象
对了,在实际编码中我们设定了消息的最终节点为CCmdTarget,所以对于该节点的消息映射表我们需要特殊处理一下,同时还有一点要注意的是WinApp的消息传递的下一级就是CCmdTarget,而不是CWinThread,,
整个消息传递网形成之后如下所示:
以上内容均为作者读《深入浅出MFC》有感
作者在后面为了保证搭建出来的正确性,还做了一些特殊标记以输出消息传递的过程
在这我贴出代码:
运行平台:VS2013
代码:
//MFC.h
#pragma once
#define TRUE 1
#define FALSE 0
typedef char* LPSTR;
typedef const char* LPCSTR;
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 CMyWinAppid 1111
#define CWndid 12
#define CFrameWndid 121
#define CMyFrameWndid 1211
#define CViewid 122
#define CMyViewid 1221
#define CDocumentid 13
#define CMyDocid 131
#include<iostream>
using namespace std;
struct AFX_MSGMAP_ENTRY;
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;
#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 } \
};
#include<afxmsg_.h>
class CObject
{
public:
CObject::CObject() {}
CObject::~CObject() {}
};
class CCmdTarget : public CObject
{
public:
CCmdTarget::CCmdTarget() {}
CCmdTarget::~CCmdTarget(){}
DECLARE_MESSAGE_MAP()
};
typedef void (CCmdTarget::*AFX_PMSG)(void);
struct AFX_MSGMAP_ENTRY
{
UINT nMessage;
UINT nCode;
UINT nID;
UINT nLastID;
UINT nSig;
AFX_PMSG pfn;
};
class CWinThread :public CCmdTarget
{
public:
CWinThread::CWinThread() {}
CWinThread::~CWinThread(){}
virtual BOOL InitInstance()
{
cout << "CWinThread::InitInstance" << endl;
return TRUE;
}
virtual int Run() {
cout << "CWinThread::Run" << endl;
return 1;
}
};
class CWnd;
class CWinApp : public CWinThread
{
public:
CWinApp* m_pCurrentWinApp;
CWnd* m_pMainWnd;
public:
CWinApp::CWinApp()
{
m_pCurrentWinApp = this;
}
CWinApp::~CWinApp(){}
virtual BOOL InitApplication() {
cout << "CWinApp::InitApplication" << endl;
return TRUE;
}
virtual BOOL InitInstance() {
cout << "CWinApp::InitInstance" << endl;
return TRUE;
}
virtual int Run()
{
cout << "CWinApp::Run" << endl;
return CWinThread::Run();
}
DECLARE_MESSAGE_MAP()
};
typedef void (CWnd::*AFX_PMSGW)(void);
//时间队列指针
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
{
public:
CFrameWnd::CFrameWnd(){}
CFrameWnd::~CFrameWnd(){}
BOOL Create();
virtual BOOL PreCreateWindow();
DECLARE_MESSAGE_MAP()
};
class CView :public CWnd
{
public:
CView::CView() {}
CView::~CView() {}
DECLARE_MESSAGE_MAP()
};
//全局函数用以获取全局对象
CWinApp* AfxGetApp();
//MFC.cpp
#include"MY.h"
extern CMyWinApp theApp;
BOOL CWnd::Create()
{
cout << "CWnd::Create" << endl;
return TRUE;
}
BOOL CWnd::CreateEx()
{
cout << "CWnd::CreateEx" << endl;
PreCreateWindow();
return TRUE;
}
BOOL CWnd::PreCreateWindow()
{
cout << "CWnd::PreCreateWindow" << endl;
return TRUE;
}
BOOL CFrameWnd::Create()
{
cout << "CFrameWnd::Create" << endl;
CreateEx();
return TRUE;
}
BOOL CFrameWnd::PreCreateWindow()
{
cout << "CFrameWnd::PreCreateWindow" << endl;
return TRUE;
}
CWinApp* AfxGetApp()
{
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,0,0,AfxSig_end ,0} ,
{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
#pragma once
#include<iostream>
#include"MFC.h"
using namespace std;
class CMyWinApp : public CWinApp
{
public:
CMyWinApp::CMyWinApp() {}
CMyWinApp::~CMyWinApp() {}
virtual BOOL InitInstance();
DECLARE_MESSAGE_MAP()
};
class CMyFrameWnd :public CFrameWnd
{
public:
CMyFrameWnd::CMyFrameWnd();
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()
};
//MF.cpp
#include"MY.h"
CMyWinApp theApp;
BOOL CMyWinApp::InitInstance()
{
cout << "CMyWinApp::InitInstance" << endl;
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,"CWndid",
CFrameWndid,"CFrameWnd",
CMyFrameWndid,"CMyFrameWnd",
CViewid,"CView",
CMyViewid,"CMyView",
CDocumentid,"CDocument",
CMyDocid,"CMyDoc",
0," "
};
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 (; pMessageMap != NULL; pMessageMap = pMessageMap->pBaseMessageMap)
{
AFX_MSGMAP_ENTRY* lpEntry = pMessageMap->lpEntries;
printlpEntries(lpEntry);
}
}
void main()
{
CWinApp* pApp = AfxGetApp();
pApp->InitApplication();
pApp->InitInstance();
pApp->Run();
CMyDoc* pMyDoc = new CMyDoc;
CMyView* pMyView = new CMyView;
CFrameWnd* pMyFrame = (CFrameWnd*)pApp->m_pMainWnd;
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 << "CMyFrameWnd Message Map:" << endl;
MsgMapPrinting(pMessageMap);
pMessageMap = pApp->GetMessageMap();
cout << endl << "CMyWinApp Message Map:" << endl;
MsgMapPrinting(pMessageMap);
system("pause");
}
效果图如下: