解剖MFC自动生成的宏定义

您所在的位置:网站首页 getthisclass 解剖MFC自动生成的宏定义

解剖MFC自动生成的宏定义

2023-01-19 12:33| 来源: 网络整理| 查看: 265

一、关于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  (  & ThisClass :: OnPaint)) } , 说明:层次序号x.y.z表示x为根节点也就是上面代码中的行号,y、z为上一级的定义展开。2.1 #define WM_PAINT                        0x000F2.2 AfxSig_vv = AfxSig_v_v_v2.2.1 enum AfxSig::AfxSig_v_v_v = 193.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 pointer8        (AFX_MSG_CALL CCmdTarget::*)((AFX_MSG_CALL CWnd::*)(static_cast(&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 = 02.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.·最后将

1BEGIN_MESSAGE_MAP(CCapturePacketDlg, CDialog)2    ON_WM_PAINT()3END_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 pointer19                (AFX_MSG_CALL CCmdTarget::*)((AFX_MSG_CALL CWnd::*)(static_cast(&ThisClass :: OnPaint))20            },21            //add others22            {23                0,24                0,25                0,26                0,27                0,28                (AFX_PMSG)029            }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() \2protected: \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 constructable2    #define DECLARE_DYNCREATE(class_name) \3        DECLARE_DYNAMIC(class_name) \4        static CObject* PASCAL CreateObject();3.1如下定义:1#ifdef _AFXDLL2    #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:1protected: 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如下定义: 1struct 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    #else11        CRuntimeClass* m_pBaseClass;12    #endif1314    // Operations15        CObject* CreateObject();16        BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;1718        // dynamic name lookup and creation19        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);2324    // Implementation25        void Store(CArchive& ar) const;26        static CRuntimeClass* PASCAL Load(CArchive& ar, UINT* pwSchemaNum);2728        // CRuntimeClass objects linked together in simple list29        CRuntimeClass* m_pNextClass;       // linked list of registered classes30        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    }1112    __declspec(selectany) static const CRuntimeClass CDynamicDoc::classCDynamicDoc = 13    {14        "CDynamicDoc"15        , sizeof(class CDynamicDoc)16        , 0xFFFF17        , CDynamicDoc::CreateObject18        , &CDynamicDoc::_GetBaseClass19        , NULL20        , NULL21    };2223    static CRuntimeClass* PASCAL CDynamicDoc::GetThisClass()24    {25        return ((CRuntimeClass*)(&CDynamicDoc::classCDynamicDoc));26    }2728    CRuntimeClass* CDynamicDoc::GetRuntimeClass() const29    {30        return ((CRuntimeClass*)(&CDynamicDoc::classCDynamicDoc));31    }小结:注意了,上面的成员变量、很多函数都是static如果你想看这些宏的简化版,可以参考侯老的《深入浅出MFC》,如下:

 1//in header file 2class CView : public CWnd 3{ 4public: 5    static CRuntimeClass classCView; 6    virtual CRuntimeClass* GetRuntimeClass() const; 7    //…… 8}; 9//in implementation file10static char_lpszCView = "CView";11CRuntimeClass CView::classCView =12{13    _lpszCView14    , sizeof(CView)15    , 0xFFF16    , NULL17    , &CWnd::classCWnd18    , NULL19};20static AFX_CLASSINIT _init_CView(&CView::classCView)21{22    (&CView::classCView)->m_pNextClass = CRuntimeClass::pFirstClass;23    CRuntimeClass::pFirstClass = &CView::classCView;24}25CRuntimeClass* CView::GetRuntimeClass() const26{27    return &CView::classCView;28}其中他将CRuntimeClass简化定义为:struct CRuntimeClass{// Attributes        LPCSTR m_lpszClassName;        int m_nObjectSize;        UINT m_wSchema; // schema number of the loaded class        CObject* (PASCAL* m_pfnCreateObject)(); // NULL => abstract class        CRuntimeClass* m_pBaseClass;

        // CRuntimeClass objects linked together in simple list        static CRuntimeClass* pFirstClass; // start of class list        CRuntimeClass* m_pNextClass;       // linked list of registered classes};

三、宏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(); 910    #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 file18#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 registration30    void AFXAPI AfxClassInit(CRuntimeClass* pNewClass);31    struct AFX_CLASSINIT32        { AFX_CLASSINIT(CRuntimeClass* pNewClass) { AfxClassInit(pNewClass); } };3334    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    }4142    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))5556    #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 file11    //static12    static CObject* PASCAL CStroke::CreateObject()13    {14        return new CStroke;15    }16    //static17    static CRuntimeClass* PASCAL CStroke::GetThisClass();18    { 19        return ((CRuntimeClass*)(&CStroke::classCStroke))20    }21    //static22    static CRuntimeClass* PASCAL CStroke::_GetBaseClass() 23    { 24        return (CObject::GetThisClass());25    }26    //static27    static AFX_COMDAT CRuntimeClass CStroke::classCStroke = 28    {29        "CStroke"30        , sizeof(class CStroke)31        , 132        , CStroke::CreateObject33        , &class_name::_GetBaseClass34        , NULL35        , &_init_CStroke 36    }; 37    CRuntimeClass* CStroke::GetRuntimeClass() const38    { 39        return ((CRuntimeClass*)(&CStroke::classCStroke)); 40    }41    extern struct AFX_CLASSINIT _init_CStroke;42    struct AFX_CLASSINIT _init_CStroke43    {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的对象,此结构体有构造函数: 1void 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结构的一个对象。


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3