MFC中与消息相关的类是CCmdTarget,派生自它的类都是"消息标志类",每个"消息标志类"都需要一个消息映射表(AFX_MSGMAP),并将基类与派生类的消息映射表串连起来。
//消息映射表
struct AFX_MSGMAP {
AFX_MSGMAP *pBaseMessageMap; //父类的消息映射表
AFX_MSGMAP_ENTRY *lpEntrys; //消息数组
};
typedef void (CCmdTarget::*AFX_PMSG)(void); //消息处理函数
//消息及消息处理函数
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 nSig; // signature type (action) or pointer to message #
AFX_PMSG pfn; // routine to call (or special value)
};
下面的宏用来将消息映射表添加到消息标志类中:
//宏DECLARE_MESSAGE_MAP的作用就是为每个"消息标志类"添加消息映射表(AFX_MSGMAP)
#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 } \
};
其中用到了枚举:
enum AfxSig_end {
AfxSig_end = 0, //消息映射表的结束标志
AfxSig_vv,
};
注意:CObject与CWinThread并不参与消息传递,所以CWinApp在Message Map中的上级是CCmdTartget,而CCmdTartget作为消息传递的终点需要作特殊处理,完整代码如下:
MFC.h
#define BOOL int
#define TRUE 1
#define FALSE 0
#define LPCSTR LPSTR
typedef char* LPSTR;
#define UINT unsigned int
#define PASCAL __stdcall
#define NULL 0
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
/****************RTTI START**********************/
class CObject;
//该结构用于记录类的信息,以建立型录,达到RTTI的能力
//该结构的对象会以链表方式连接起来。
//CRunTimeClass对象的命名方式为:class+类名,比如CWnd的CRunTimeClass对象是classCWnd
struct CRunTimeClass
{
LPSTR m_lpszClassName; //类名
int m_nObjecSize; //类大小
UINT m_wSchema;
CObject* (PASCAL* m_pfnCreateObject) (); //动态创建类对象的方法
CRunTimeClass *m_pBaseClass; //该类的基类
static CRunTimeClass *pFirstClass; //全局对象,型录表的表头
CRunTimeClass *m_pNextClass; //在链表中的下一个类
CObject* CreateObject(); //动态创建对象
static CRunTimeClass* PASCAL Load();
};
//宏DECLARE_DYNAMIC的作用就是把CRuntimeClass对象塞到类之中。
#define DECLARE_DYNAMIC(class_name) \
public: \
static CRunTimeClass class##class_name; \
virtual CRunTimeClass* GetRunTimeClass() const;
//宏DECLARE_DYNAMIC的作用就是在DECLARE_DYNAMIC上实现动态创建
#define DECLARE_DYNCREATE(class_name) \
DECLARE_DYNAMIC(class_name) \
static CObject* PASCAL CreateObject();
//宏IMPLEMENT_DYNAMIC的作用就是做各CRuntimeClass对象的连接工作,使它们形成一个链表
#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)
//生成类的CRunTimeClass对象名
#define RUNTIME_CLASS(class_name) \
(&class_name::class##class_name)
struct AFX_CLASSINIT
{
//该结构的构造函数的作用就是将一个个CRuntimeClass的对象链接起来
AFX_CLASSINIT(CRunTimeClass *pNewClass);
};
#define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew) \
static char _lpsz##class_name[] = #class_name; \
CRunTimeClass class_name::class##class_name = { \
_lpsz##class_name, sizeof(class_name), wSchema, pfnNew, \
RUNTIME_CLASS(base_class_name), NULL }; \
static AFX_CLASSINIT _init##class_name(&class_name::class##class_name); \
CRunTimeClass* class_name::GetRunTimeClass() const \
{ return &class_name::class##class_name; } \
/****************RTTI END**********************/
/****************MESSAGE_MAP START**********************/
struct AFX_MSGMAP_ENTRY;
//消息映射表
struct AFX_MSGMAP {
AFX_MSGMAP *pBaseMessageMap;
AFX_MSGMAP_ENTRY *lpEntrys;
};
enum AfxSig_end {
AfxSig_end = 0, //消息映射表的结束标志
AfxSig_vv,
};
//宏DECLARE_MESSAGE_MAP的作用就是为每个"消息标志类"添加消息映射表(AFX_MSGMAP)
#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 } \
};
/****************MESSAGE_MAP END**********************/
class CObject
{
public:
CObject()
{
cout << "CObject Constructor!" << endl;
}
~CObject()
{
cout << "CObject Destructor!" << endl;
}
// 根据TRRI查看本类是否是pClass或pClass的子类
BOOL IsKindOf(const CRunTimeClass *pClass) const;
//作为RTTI的表头CObject要作特殊的处理,可以看作是DECLARE_DYNAMIC宏的展开方式
public:
static CRunTimeClass classCObject;
virtual CRunTimeClass* GetRunTimeClass() const;
};
//与消息有关的类
class CCmdTarget : public CObject
{
DECLARE_DYNAMIC(CCmdTarget);
public:
CCmdTarget() { cout << "CCmdTarget Constructor!" << endl; }
~CCmdTarget() { cout << "CCmdTarget Destructor!" << endl; }
DECLARE_MESSAGE_MAP() //在消息映射网中CCmdTarget是终点,没有上级领导
};
typedef void (CCmdTarget::*AFX_PMSG)(void); //消息处理函数
//消息及消息处理函数
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 nSig; // signature type (action) or pointer to message #
AFX_PMSG pfn; // routine to call (or special value)
};
class CWinThread : public CCmdTarget
{
DECLARE_DYNAMIC(CWinThread)
public:
CWinThread() { cout << "CWinThread Constructor!" << endl; }
~CWinThread() { cout << "CWinThread Destructor!" << endl; }
virtual BOOL InitInstance() {
cout << "CWinThread::InitInstance()" << endl;
return TRUE;
}
virtual int Run() {
cout << "CWinThread::Run()" << endl;
return 1;
}
};
class CWnd;
class CWinApp : public CWinThread
{
DECLARE_DYNAMIC(CWinApp)
public:
CWinApp *m_pCurrentApp; //应用程序实例
CWnd *m_pMainWnd; //程序主框架
public:
CWinApp() {
m_pCurrentApp = this;
cout << "CWinApp Constructor!" << endl;
}
~CWinApp() { cout << "CWinApp Destructor!" << endl; }
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()
};
class CWnd : public CCmdTarget
{
DECLARE_DYNCREATE(CWnd);
public:
CWnd() { cout << "CWnd Constructor!" << endl; }
~CWnd() { cout << "CWnd Destructor!" << endl; }
virtual BOOL Create();
BOOL CreateEX();
virtual BOOL PreCreateWindow();
DECLARE_MESSAGE_MAP()
};
class CFrameWnd : public CWnd
{
DECLARE_DYNCREATE(CFrameWnd)
public:
CFrameWnd() { cout << "CFrameWnd Constructor!" << endl; }
~CFrameWnd() { cout << "CFrameWnd Destructor!" << endl; }
virtual BOOL Create();
virtual BOOL PreCreateWindow();
DECLARE_MESSAGE_MAP()
};
class CView : public CWnd
{
DECLARE_DYNAMIC(CView)
public:
CView() { cout << "CView Constructor!" << endl; }
~CView() { cout << "CView Destructor!" << endl; }
DECLARE_MESSAGE_MAP()
};
class CDoucument : public CCmdTarget
{
DECLARE_DYNAMIC(CDoucument)
public:
CDoucument() { cout << "CDoucument Constructor!" << endl; }
~CDoucument() { cout << "CDoucument Destructor!" << endl; }
DECLARE_MESSAGE_MAP()
};
// global function
CWinApp * AfxGetApp();
MY.h
#include <iostream>
#include "MFC.h"
class CMyWinApp : public CWinApp
{
// DECLARE_DYNCREATE(CMyWinApp);
public:
CMyWinApp() { cout << "CMyWinApp Constructor!" << endl; }
~CMyWinApp() { cout << "CMyWinApp Destructor!" << endl; }
virtual BOOL InitInstance();
DECLARE_MESSAGE_MAP()
};
class CMyFrame : public CFrameWnd
{
DECLARE_DYNCREATE(CMyFrame)
public:
CMyFrame();
~CMyFrame() { cout << "CMyFrame Destructor!" << endl; }
DECLARE_MESSAGE_MAP()
};
class CMyView : public CView
{
DECLARE_DYNCREATE(CMyView)
public:
CMyView() { cout << "CMyView Constructor!" << endl; }
~CMyView() { cout << "CMyView Destructor!" << endl; }
DECLARE_MESSAGE_MAP()
};
class CMyDoc : public CDoucument
{
DECLARE_DYNCREATE(CMyDoc)
public:
CMyDoc() { cout << "CMyDoc Constructor!" << endl; }
~CMyDoc() { cout << "CMyDoc Destructor!" << endl; }
DECLARE_MESSAGE_MAP()
};
MFC.CPP
#include "MY.h"
CRunTimeClass * CRunTimeClass::pFirstClass = NULL;
AFX_CLASSINIT::AFX_CLASSINIT(CRunTimeClass* pNewClass)
{
pNewClass->m_pNextClass = CRunTimeClass::pFirstClass;
CRunTimeClass::pFirstClass = pNewClass;
}
CObject* CRunTimeClass::CreateObject()
{
if (m_pfnCreateObject == NULL)
{
cout << "Error:Trying to create object which is not DECLARE_DYNCREATE:"
<< m_lpszClassName << endl;
return NULL;
}
CObject *object = NULL;
object = (*m_pfnCreateObject)();
return object;
}
CRunTimeClass* PASCAL CRunTimeClass::Load()
{
char szClassName[64];
CRunTimeClass *pClass;
cout << "enter a class name: ";
cin >> szClassName;
for (pClass = pFirstClass; pClass != NULL; pClass = pClass->m_pNextClass)
{
if (strcmp(szClassName, pClass->m_lpszClassName) == 0)
return pClass;
}
cout << "Error:Class not found: " << szClassName;
return NULL;
}
//处理RTTI表的表头,可以看作是宏IMPLEMENT_DYNAMIC的展开方式
static char _lpszCOjbect[] = "CObject";
struct CRunTimeClass CObject::classCObject = {_lpszCOjbect, sizeof(CObject), 0xFFFF, NULL, NULL, NULL};
static AFX_CLASSINIT _initCObject(&CObject::classCObject);
CRunTimeClass* CObject::GetRunTimeClass() const
{
return &CObject::classCObject;
}
BOOL CObject::IsKindOf(const CRunTimeClass *pClass) const
{
CRunTimeClass *pClassThis = GetRunTimeClass();
while (pClassThis != NULL)
{
if (pClassThis == pClass)
return TRUE;
pClassThis = pClassThis->m_pBaseClass;
}
return FALSE;
}
// CCmdTarget作为消息映射的终点,需要做特殊处理,可以看作BEGIN_MESSAGE_MAP和END_MESSAGE_MAP展开
AFX_MSGMAP* CCmdTarget::GetMessageMap() const
{
return &CCmdTarget::messageMap;
}
AFX_MSGMAP CCmdTarget::messageMap = {NULL, &CCmdTarget::_messageEntries[0] };
AFX_MSGMAP_ENTRY CCmdTarget::_messageEntries[] = {0, 0, 1, 0, AfxSig_end, 0};
extern CMyWinApp theApp;
CWinApp* AfxGetApp()
{
return theApp.m_pCurrentApp;
}
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;
}
IMPLEMENT_DYNAMIC(CCmdTarget, CObject);
IMPLEMENT_DYNAMIC(CWinThread, CCmdTarget);
IMPLEMENT_DYNAMIC(CWinApp, CWinThread);
//IMPLEMENT_DYNAMIC(CMyWinApp, CWinApp);
IMPLEMENT_DYNCREATE(CWnd, CCmdTarget);
IMPLEMENT_DYNAMIC(CView, CWnd);
IMPLEMENT_DYNCREATE(CFrameWnd, CWnd);
IMPLEMENT_DYNAMIC(CDoucument, CCmdTarget);
BEGIN_MESSAGE_MAP(CWnd, CCmdTarget)
END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CWinApp, CCmdTarget)
END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CFrameWnd, CWnd)
END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CView, CWnd)
END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CDoucument, CCmdTarget)
END_MESSAGE_MAP()
MY.CPP
#include "MY.h"
// global objec
CMyWinApp theApp;
BOOL CMyWinApp::InitInstance()
{
m_pMainWnd = new CMyFrame;
return TRUE;
}
CMyFrame::CMyFrame()
{
cout << "CMyFrame Constructor!" << endl;
Create();
}
IMPLEMENT_DYNCREATE(CMyFrame, CFrameWnd);
IMPLEMENT_DYNCREATE(CMyDoc, CDoucument);
IMPLEMENT_DYNCREATE(CMyView, CView);
BEGIN_MESSAGE_MAP(CMyFrame, CFrameWnd)
END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)
END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CMyView, CView)
END_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CMyDoc, CDoucument)
END_MESSAGE_MAP()
//打印RTTI链表
void PrinAllClass()
{
CRunTimeClass *pClass;
for (pClass = CRunTimeClass::pFirstClass; pClass != NULL; pClass = pClass->m_pNextClass)
{
cout << pClass->m_lpszClassName << " " << pClass->m_nObjecSize << endl;
}
}
void main()
{
//仿真MFC的运行
CWinApp *pApp = AfxGetApp();
pApp->InitApplication();
pApp->InitInstance();
pApp->Run();
/**************************以下属于自定义**************************************/
//RTTI的使用
if (pApp->m_pMainWnd->IsKindOf(RUNTIME_CLASS(CWnd)))
cout << "true" << endl;
PrinAllClass();
//动态创建对象,输入类名,若存在则会动态创建对象
CRunTimeClass *pClass = NULL;
CObject *pObject = NULL;
while(1)
{
if ((pClass = CRunTimeClass::Load()) == NULL)
{
break;
}
pObject = pClass->CreateObject();
if (pObject)
cout << pClass->m_lpszClassName << " create succ!" << endl;
}
}