一、关于DECLARE_MESSAGE_MAP宏定义
使用MFC向导,在ApplicationType页面选择DialogBased,生成一个对话框项目,Dialog类命名为CCapturePacketDlg,在CCapturePacketDlg.cpp中自动产生下列代码:
1
BEGIN_MESSAGE_MAP(CCapturePacketDlg, CDialog)
2
ON_WM_PAINT()
3
END_MESSAGE_MAP()
- 先来分析ON_WM_PAINT(),在头文件“afxmsg.h”有它的宏定义,如下:
1
#define
ON_WM_PAINT() \
2
{ WM_PAINT,
0
,
0
,
0
, AfxSig_vv, \
3
(AFX_PMSG)(AFX_PMSGW) \
4
(static_cast
<
void
(AFX_MSG_CALL CWnd::
*
)(
void
)
>
(
&
ThisClass :: OnPaint)) }
,
说明:层次序号x.y.z表示x为根节点也就是上面代码中的行号,y、z为上一级的定义展开。
2.1 #define WM_PAINT 0x000F
2.2 AfxSig_vv = AfxSig_v_v_v
2.2.1 enum AfxSig::AfxSig_v_v_v = 19
3.1 AFX_PMSG:typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void); //为一个函数指针
3.2 AFX_PMSGW:typedef void (AFX_MSG_CALL CWnd::*AFX_PMSGW)(void); //为一个函数指针
将ON_WM_PAINT()完全展开:
1

{
2
0x000F,
3
0,
4
0,
5
0,
6
19,
7
//Converts OnPaint to the type of CCmdTarget finally. Derive Class 's pointer -> Base Class's pointer
8
(AFX_MSG_CALL CCmdTarget::*)((AFX_MSG_CALL CWnd::*)(static_cast< void (AFX_MSG_CALL CWnd::*)(void) >(&ThisClass :: OnPaint))
9
} 2. 再来分析BEGIN_MESSAGE_MAP(CCapturePacketDlg, CDialog),在“afxwin.h”中有定义:
1
#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
2
PTM_WARNING_DISABLE \
3
const AFX_MSGMAP* theClass::GetMessageMap() const \
4
{ return GetThisMessageMap(); } \
5
const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() \
6
{ \
7
typedef theClass ThisClass; \
8
typedef baseClass TheBaseClass; \
9
static const AFX_MSGMAP_ENTRY _messageEntries[] = \
10
{ 2.1 PTM_WARNING_DISABLE:
#define PTM_WARNING_DISABLE \
__pragma(warning( push )) \ //#pragma warning( push [ ,n ] ),Where n represents a warning level (1 through 4).
//The pragma warning( push ) stores the current warning state for all warnings.
__pragma(warning( disable : 4867 ))//Do not issue the specified warning message(s).
//http://msdn2.microsoft.com/en-us/2c8f766e.aspx
// Allows selective modification of the behavior of compiler warning messages.
3.1 struct AFX_MSGMAP
{
3.1.1 const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
3.1.2 const AFX_MSGMAP_ENTRY* lpEntries;
};
3.1.2 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 #
3.1.2.1 AFX_PMSG pfn; // routine to call (or special value)
};
3.1.2.1 typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);
5.1 #define PASCAL __stdcall
将BEGIN_MESSAGE_MAP(CCapturePacketDlg, CDialog)完全展开:
1
__pragma(warning( push )) __pragma(warning( disable : 4867 ))
2
const struct AFX_MSGMAP* CCapturePacketDlg::GetMessageMap() const
3
{
4
return GetThisMessageMap();
5
}
6
const struct AFX_MSGMAP* __stdcall CCapturePacketDlg::GetThisMessageMap()
7
{
8
typedef CCapturePacketDlg ThisClass;
9
typedef CDialog TheBaseClass;
10
static const struct AFX_MSGMAP_ENTRY _messageEntries[] =
11
{ 3 最后分析END_MESSAGE_MAP(),在“afxwin.h”中有定义:
1
#define END_MESSAGE_MAP() \
2
{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \
3
}; \
4
static const AFX_MSGMAP messageMap = \
5
{ &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; \
6
return &messageMap; \
7
} \
8
PTM_WARNING_RESTORE 2.1 AfxSig_end:enum AfxSig.AfxSig_end = 0
2.2 AFX_PMSG:typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);//函数指针
4.1 struct AFX_MSGMAP
{
const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
const AFX_MSGMAP_ENTRY* lpEntries;
};
8.1 #define PTM_WARNING_RESTORE \
__pragma(warning( pop ))
//pop restores the state of all warnings (including 4705, 4706, and 4707) to what it was at the beginning of the code.
·最后将
1
BEGIN_MESSAGE_MAP(CCapturePacketDlg, CDialog)
2
ON_WM_PAINT()
3
END_MESSAGE_MAP() 完全展开为:
1
__pragma(warning( push )) __pragma(warning( disable : 4867 ))
2
const struct AFX_MSGMAP* CCapturePacketDlg::GetMessageMap() const
3
{
4
return GetThisMessageMap();
5
}
6
const struct AFX_MSGMAP* __stdcall CCapturePacketDlg::GetThisMessageMap()
7
{
8
typedef CCapturePacketDlg ThisClass;
9
typedef CDialog TheBaseClass;
10
static const struct AFX_MSGMAP_ENTRY _messageEntries[] =
11
{
12
{
13
0x000F,
14
0,
15
0,
16
0,
17
19,
18
//Converts OnPaint to the type of CCmdTarget finally. Derive Class 's pointer -> Base Class's pointer
19
(AFX_MSG_CALL CCmdTarget::*)((AFX_MSG_CALL CWnd::*)(static_cast< void (AFX_MSG_CALL CWnd::*)(void) >(&ThisClass :: OnPaint))
20
},
21
//add others
22
{
23
0,
24
0,
25
0,
26
0,
27
0,
28
(AFX_PMSG)0
29
}
30
}
31
static const struct AFX_MSGMAP messageMap =
32
{
33
&TheBaseClass::GetThisMessageMap,
34
&_messageEntries[0]
35
};
36
return &messageMap;
37
}
38
__pragma(warning( pop ))
39
其中GetMessageMap()是在哪里声明的呢?在CCapturePacketDlg的定义中有一个这样的宏:DECLARE_MESSAGE_MAP()
老办法查看它的定义:
1
#define DECLARE_MESSAGE_MAP() \
2
protected: \
3
static const AFX_MSGMAP* PASCAL GetThisMessageMap(); \
4
virtual const AFX_MSGMAP* GetMessageMap() const; \ 注意函数为static,即它们是类的函数。函数中的static变量实际也在类对象未生成之前已经存在。(这种说法不知道是否正确?)
小结:
每次用MFC类向导生成一个类时,系统会在类的声明部分添加两个方法的声明:GetThisMessageMap(),GetMessageMap()。在类的实现部分.cpp文件中加上这两个方法的定义。
当然这所有的代码都是由系统生成的,如果我们要定义自己的消息处理函数呢,例如,我们要添加一个按钮(ID为:IDC_BUTTON1)的单击处理函数我们可以添加宏ON_NOTIFY(NM_CLICK, IDC_BUTTON1, OnMyClick),OnMyClick为自定义函数,但是他必须与ON_NOTIFY中的函数原型一致。
二、关于DECLARE_DYNCREATE宏
使用MFC向导,在ApplicationType页面选择SingleDocument,生成一个单文档项目,Document类命名为CDynamicDoc,在CDynamicDoc.h中自动产生DECLARE_DYNCREATE(CDynamicDoc),CDynamicDoc.cpp中产生IMPLEMENT_DYNCREATE(CDynamicDoc, CDocument)。
1、展开CDynamicDoc.h中的DECLARE_DYNCREATE(CDynamicDoc):
1
// not serializable, but dynamically constructable
2
#define DECLARE_DYNCREATE(class_name) \
3
DECLARE_DYNAMIC(class_name) \
4
static CObject* PASCAL CreateObject(); 3.1如下定义:
1
#ifdef _AFXDLL
2
#define DECLARE_DYNAMIC(class_name) \
3
protected: \
4
static CRuntimeClass* PASCAL _GetBaseClass(); \
5
public: \
6
static const CRuntimeClass class##class_name; \
7
static CRuntimeClass* PASCAL GetThisClass(); \
8
virtual CRuntimeClass* GetRuntimeClass() const; \ so the result(DECLARE_DYNCREATE(CDynamicDoc)) of combining the above two is following:
1
protected:
2
static CRuntimeClass* PASCAL _GetBaseClass();
3
public:
4
static const CRuntimeClass classCDynamicDoc;
5
static CRuntimeClass* PASCAL GetThisClass();
6
virtual CRuntimeClass* GetRuntimeClass() const;
7
static CObject* PASCAL CreateObject(); 2、展开CDynamicDoc.cpp中的IMPLEMENT_DYNCREATE(CDynamicDoc, CDocument):
1
#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \
2
CObject* PASCAL class_name::CreateObject() \
3
{ return new class_name; } \
4
IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \
5
class_name::CreateObject, NULL) 4.1如下定义:
1
#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \
2
CRuntimeClass* PASCAL class_name::_GetBaseClass() \
3
{ return RUNTIME_CLASS(base_class_name); } \
4
AFX_COMDAT const CRuntimeClass class_name::class##class_name =
{ \
5
#class_name, sizeof(class class_name), wSchema, pfnNew, \
6
&class_name::_GetBaseClass, NULL, class_init }; \
7
CRuntimeClass* PASCAL class_name::GetThisClass() \
8
{ return _RUNTIME_CLASS(class_name); } \
9
CRuntimeClass* class_name::GetRuntimeClass() const \
10
{ return _RUNTIME_CLASS(class_name); } \ 4.1.2 CRuntimeClass如下定义:
1
struct CRuntimeClass
2
{
3
// Attributes
4
LPCSTR m_lpszClassName;
5
int m_nObjectSize;
6
UINT m_wSchema; // schema number of the loaded class
7
CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class
8
#ifdef _AFXDLL
9
CRuntimeClass* (PASCAL* m_pfnGetBaseClass)();
10
#else
11
CRuntimeClass* m_pBaseClass;
12
#endif
13
14
// Operations
15
CObject* CreateObject();
16
BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;
17
18
// dynamic name lookup and creation
19
static CRuntimeClass* PASCAL FromName(LPCSTR lpszClassName);
20
static CRuntimeClass* PASCAL FromName(LPCWSTR lpszClassName);
21
static CObject* PASCAL CreateObject(LPCSTR lpszClassName);
22
static CObject* PASCAL CreateObject(LPCWSTR lpszClassName);
23
24
// Implementation
25
void Store(CArchive& ar) const;
26
static CRuntimeClass* PASCAL Load(CArchive& ar, UINT* pwSchemaNum);
27
28
// CRuntimeClass objects linked together in simple list
29
CRuntimeClass* m_pNextClass; // linked list of registered classes
30
const AFX_CLASSINIT* m_pClassInit;
31
}; 4.1.2.30 AFX_CLASSINIT如下定义:(这个变量非常重要,它完成了将新的类加在List头部的功能,List中的节点类型就是CRuntimeClass)
1
/**////////////////////////////////////////////////////////////////////////////// 2
// Basic object model
3
4
// generate static object constructor for class registration
5
void AFXAPI AfxClassInit(CRuntimeClass* pNewClass);
6
struct AFX_CLASSINIT
7
{ AFX_CLASSINIT(CRuntimeClass* pNewClass)
{ AfxClassInit(pNewClass); } };
8
//C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\src\mfc\objcore.cpp Line157
9
void AFXAPI AfxClassInit(CRuntimeClass* pNewClass)
10
{
11
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
12
AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
13
pModuleState->m_classList.AddHead(pNewClass);
14
AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
15
}
16
//可以将AfxClassInit()函数的功能简单的如下表示:
17
AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass* pNewClass)
18
{
19
pNewClass->m_pNextClass = CRuntimeClass::pFirstClass;
20
CRuntimeClass::pFirstClass = pNewClass;
21
} 4.1.3 RUNTIME_CLASS如下定义:
1
#define RUNTIME_CLASS(class_name) (class_name::GetThisClass()) 4.1.4 AFX_COMDAT如下定义:
1
#define AFX_COMDAT __declspec(selectany) 说明:“#”——operator (#) converts macro parameters to string literals without expanding the parameter definition.
“##”——operator (
##), which is sometimes called the "merging" operator, is used in both object-like and function-like macros.
4.1.8 _RUNTIME_CLASS如下定义:
1
#define _RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name)) so the result(IMPLEMENT_DYNCREATE(CDynamicDoc, CDocument)) of combining the aboves is following:
1//CDynamicDoc, CDocument->class_name, base_class_name
2 static CObject* PASCAL CDynamicDoc::CreateObject()

3
{
4 return new CDynamicDoc;
5 }
6
7 static CRuntimeClass* PASCAL CDynamicDoc::_GetBaseClass()

8
{
9 return CDocument::GetThisClass()
10 }
11
12 __declspec(selectany) static const CRuntimeClass CDynamicDoc::classCDynamicDoc =

13
{
14 "CDynamicDoc"
15 , sizeof(class CDynamicDoc)
16 , 0xFFFF
17 , CDynamicDoc::CreateObject
18 , &CDynamicDoc::_GetBaseClass
19 , NULL
20 , NULL
21 };
22
23 static CRuntimeClass* PASCAL CDynamicDoc::GetThisClass()

24
{
25 return ((CRuntimeClass*)(&CDynamicDoc::classCDynamicDoc));
26 }
27
28 CRuntimeClass* CDynamicDoc::GetRuntimeClass() const

29
{
30 return ((CRuntimeClass*)(&CDynamicDoc::classCDynamicDoc));
31 }小结:注意了,上面的成员变量、很多函数都是static
如果你想看这些宏的简化版,可以参考侯老的《深入浅出MFC》,如下:
三、宏DECLARE_SERIAL(CStroke)、IMPLEMENT_SERIAL(CStroke, CObject, 1),给出它们的宏定义及结果:
1
//declaration file
2
#define DECLARE_SERIAL(class_name) \
3
_DECLARE_DYNCREATE(class_name) \
4
AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb);
5
6
#define _DECLARE_DYNCREATE(class_name) \
7
_DECLARE_DYNAMIC(class_name) \
8
static CObject* PASCAL CreateObject();
9
10
#define _DECLARE_DYNAMIC(class_name) \
11
protected: \
12
static CRuntimeClass* PASCAL _GetBaseClass(); \
13
public: \
14
static CRuntimeClass class##class_name; \
15
static CRuntimeClass* PASCAL GetThisClass(); \
16
virtual CRuntimeClass* GetRuntimeClass() const; \
17
//implement file
18
#define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) \
19
CObject* PASCAL class_name::CreateObject() \
20
{ return new class_name; } \
21
extern AFX_CLASSINIT _init_##class_name; \
22
_IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, \
23
class_name::CreateObject, &_init_##class_name) \
24
AFX_CLASSINIT _init_##class_name(RUNTIME_CLASS(class_name)); \
25
CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb) \
26
{ pOb = (class_name*) ar.ReadObject(RUNTIME_CLASS(class_name)); \
27
return ar; } \
28
29
// generate static object constructor for class registration
30
void AFXAPI AfxClassInit(CRuntimeClass* pNewClass);
31
struct AFX_CLASSINIT
32
{ AFX_CLASSINIT(CRuntimeClass* pNewClass)
{ AfxClassInit(pNewClass); } };
33
34
void AFXAPI AfxClassInit(CRuntimeClass* pNewClass)
35
{
36
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
37
AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
38
pModuleState->m_classList.AddHead(pNewClass);
39
AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
40
}
41
42
43
#define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew, class_init) \
44
CRuntimeClass* PASCAL class_name::_GetBaseClass() \
45
{ return RUNTIME_CLASS(base_class_name); } \
46
AFX_COMDAT CRuntimeClass class_name::class##class_name =
{ \
47
#class_name, sizeof(class class_name), wSchema, pfnNew, \
48
&class_name::_GetBaseClass, NULL, class_init }; \
49
CRuntimeClass* PASCAL class_name::GetThisClass() \
50
{ return _RUNTIME_CLASS(class_name); } \
51
CRuntimeClass* class_name::GetRuntimeClass() const \
52
{ return _RUNTIME_CLASS(class_name); } \
53
54
#define _RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))
55
56
#define RUNTIME_CLASS(class_name) (class_name::GetThisClass()) 1
//header file
2
protected:
3
static CRuntimeClass* PASCAL _GetBaseClass();
4
public:
5
static CRuntimeClass classCStroke;
6
static CRuntimeClass* PASCAL GetThisClass();
7
virtual CRuntimeClass* GetRuntimeClass() const;
8
static CObject* PASCAL CreateObject();
9
AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, CStroke* &pOb);
10
//implement file
11
//static
12
static CObject* PASCAL CStroke::CreateObject()
13
{
14
return new CStroke;
15
}
16
//static
17
static CRuntimeClass* PASCAL CStroke::GetThisClass();
18
{
19
return ((CRuntimeClass*)(&CStroke::classCStroke))
20
}
21
//static
22
static CRuntimeClass* PASCAL CStroke::_GetBaseClass()
23
{
24
return (CObject::GetThisClass());
25
}
26
//static
27
static AFX_COMDAT CRuntimeClass CStroke::classCStroke =
28
{
29
"CStroke"
30
, sizeof(class CStroke)
31
, 1
32
, CStroke::CreateObject
33
, &class_name::_GetBaseClass
34
, NULL
35
, &_init_CStroke
36
};
37
CRuntimeClass* CStroke::GetRuntimeClass() const
38
{
39
return ((CRuntimeClass*)(&CStroke::classCStroke));
40
}
41
extern struct AFX_CLASSINIT _init_CStroke;
42
struct AFX_CLASSINIT _init_CStroke
43
{
44
void AFXAPI AfxClassInit(CRuntimeClass* CStroke)
45
{
46
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
47
AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
48
pModuleState->m_classList.AddHead(CStroke);
49
AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
50
}
51
};
52
CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb)
53
{
54
pOb = (CStroke*) ar.ReadObject(RUNTIME_CLASS(CStroke));
55
return ar;
56
} 总结,一旦RUNTIME_CLASS(CStroke)由#define RUNTIME_CLASS(class_name) (class_name::GetThisClass())也就是CStroke::GetThisClass() 即
CStroke::classCStroke =
{
"CStroke"
, sizeof(class CStroke)
, 1
, CStroke::CreateObject
, &class_name::_GetBaseClass
, NULL
, &_init_CStroke
}
其中,由extern AFX_CLASSINIT _initCStroke可知_init_CStroke是一个结构体AFX_CLASSINIT的对象,此结构体有构造函数:
1
void AFXAPI AfxClassInit(CRuntimeClass* pNewClass);
2
struct AFX_CLASSINIT
3
{ AFX_CLASSINIT(CRuntimeClass* pNewClass)
{ AfxClassInit(pNewClass); } };
4
5
void AFXAPI AfxClassInit(CRuntimeClass* pNewClass)
6
{
7
AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
8
AfxLockGlobals(CRIT_RUNTIMECLASSLIST);
9
pModuleState->m_classList.AddHead(pNewClass);
10
AfxUnlockGlobals(CRIT_RUNTIMECLASSLIST);
11
} 所以一旦返回classCStroke,也就调用了_init_CStroke的构造函数即将类CStroke添加到了全局变量m_classList类的List中了,同时在变量classCStroke中,也可以得到类CStroke的名称、大小、一个CStroke的对象、类CStroke的基类以及AFX_CLASSINIT结构的一个对象。