一、 初始化过程(入口函数)
1. 从CWinApp类派生一个应用程序类
2. 使用派生类定义全局变量theApp
3. 在CWinApp派生类中,重写InitInstance函数作为程序启动代码
二、 窗口创建(钩子函数)
1. 加载菜单
2. 调用CreateEx 设计/注册窗口类,并创建窗口
2.1 调用PreCreateWindow 设计/注册窗口类
WNDCLASS wndcls;
....
wndcls.lpfnWndProc = DefWindowProc;
....
2.2 调用AfxHookWindowCreate函数
1)利用WIN32 API 函数 SetWindowsHookEx在程序中埋下一个
类型为WH_CBT的钩子
2)将自己new的框架类对象(pFrame)保存到当前程序线程信息中
2.3 调用WIN32 API 函数::CreateWindowEx创建窗口,此函数一旦
执行成功,立即执行钩子处理函数。
3 钩子处理函数
3.1 将 窗口句柄 和 自己new的框架类对象 建立一对一的绑定关系
pFrame->m_hWnd = hWnd;
m_permanentMap[hWnd] = pFrame;
3.2 利用WIN32 API 函数::SetWindowLong将窗口处理函数由默认
处理函数更改为AfxWndProc(真正窗口处理函数)
三、 消息映射机制
1. 消息映射机制的使用
1.1 类必须派生自 CCmdTarget
1.2 类内必须添加声明宏 DECLARE_MESSAGE_MAP
1.3 类外必须添加实现宏 BEGIN_MESSAGE_MAP END_MESSAGE_MAP
2. 类内声明宏中包含三个成员
2.1 AFX_MSGMAP_ENTRY类型的结构体静态变量
struct AFX_MSGMAP_ENTRY {(宏展开的静态数组每个元素的类型)
UINT nMessage; // 消息ID
UINT nCode; // 通知码
UINT nID; // 命令ID/控件ID
UINT nLastID; // 最后一个控件ID
UINT nSig; // 消息处理函数的类型
AFX_PMSG pfn; // 消息处理函数的地址(指针)
};
2.2 AFX_MSGMAP类型的结构体静态变量
struct AFX_MSGMAP { (宏展开的静态变量的类型)
const AFX_MSGMAP* pBaseMap;//保存父类静态变量地址(负责连接链表)
const AFX_MSGMAP_ENTRY* lpEntries;//指向相应类的静态数组首地址
};
2.3 虚函数virtual const AfX_MSGMAP* GetMessageMap() const;
获取本类静态变量地址(获取链表头节点)
4. 消息映射机制执行过程
3.1 获取 和 窗口句柄 绑定在一起的 框架类对象地址(pFrame)
3.2 利用pFrame调用GetMessageMap虚函数获取 本类静态变量地址
(链表头节点)pMessageMap
3.3 利用pMessageMap获取相应类的静态数组,并到数组中匹配每个
元素,如果找到了执行5.5,如果没找到执行5.4
3.4 利用pMessageMap获取父类静态变量地址,如果为NULL遍历结束
如果不为NULL执行5.3
3.5 利用找到的数组元素的最后一个成员,并调用之,完成消息的处理
四、 运行时类信息(运行时类型识别)
1. 程序运行过程中可以获知对象的相关类的信息
2. 运行时类信息机制的使用
2.1 类必须派生自CObject
2.2 类内必须添加声明宏 DECLARE_DYNAMIC
2.3 类外必须添加实现宏 IMPLEMENT_DYNAMIC
CObject::IsKindOf(..) - 来判断对象是否属于某个类
3. 类内声明宏共包含两个成员
3.1 CRuntimeClass类型的静态结构体变量
静态变量保存了关于类的信息,连接一个链表
struct CRuntimeClass {
LPCSTR m_lpszClassName; //类的名称
int m_nObjectSize; //类的大小(sizeof)
UINT m_wSchema; //类的版本
CObject* (PASCAL* m_pfnCreateObject)();
//用于动态创建机制,运行时类信息机制为NULL
CRuntimeClass* m_pBaseClass;//父类静态变量地址(连接链表)
CRuntimeClass* m_pNextClass;//为NULL
};
3.2 虚函数GetRuntimeClass()
虚函数获取本类静态变量地址(获取链表头节点)
4 IsKindOf执行过程
4.1 利用派生类的对象调用虚函数GetRuntimeClass()
获取派生类的静态变量地址(链表头节点)
4.2 将派生类的静态变量和目标进行比对,如果相等,证明对象属于
这个类,如果不想等获取父类静态变量 循环和目标进行比对。
4.3 只要有一次相等也能证明对象属于这个类。
4.4 循环结束始终比对不成功,证明对象不属于这个类。
五、 动态创建
1. 在不知道类名的情况下,将类的对象创建出来
2. 动态创建机制的使用
2.1 类必须从CObject派生
2.2 类内必须添加声明宏 DECLARE_DYNCREATE
2.3 类外必须添加实现宏 IMPLEMENT_DYNCREATE
3. 类内声明宏共包含三个成员
3.1 CRuntimeClass类型的静态结构体变量
静态变量保存了关于类信息,负责连接链表,
保存了静态函数的地址(CDog::CreateObject)
struct CRuntimeClass {
LPCSTR m_lpszClassName; //类的名称
int m_nObjectSize; //类的大小(sizeof)
UINT m_wSchema; //类的版本
CObject* (PASCAL* m_pfnCreateObject)();
//用于动态创建机制,运行时类信息机制为NULL
CRuntimeClass* m_pBaseClass;//父类静态变量地址(连接链表)
CRuntimeClass* m_pNextClass;//为NULL
};
3.2虚函数GetRuntimeClass()
获取本类(CDog)的静态变量地址(链表头节点)
3.3静态成员函数 CreateObject()
用于在堆内申请对象空间
3.4 动态创建机制的实现
3.4.1 多了一个静态函数 CDog::CreateObject
3.4.2 静态变量的第四个成员不再为NULL, 保存新增加的那个静态函数的地址
4. 动态创建机制的执行过程
4.1 调用GetRuntimeClass()获取派生类的静态变量地址
4.2 通过4.1产生的静态变量地址调用其第四个成员CreateObject()
4.3 CreateObject()函数内部new了一个CDog类的对象并返回对象地址。
六、 永久保存(序列化)
1. 序列化的基本思想:一个类应该能够对自己的成员变量的数据进行读写操作,对象可以通过读操作而重新创建。即对象可以将其当前状态(由其成员变量的值表示)写入永久性存储体(通常指磁盘)中,以后可以从永久性存储体中读取(载入)对象的状态,从而重建对象。类的对象自己应该具备将状态值写入磁盘或从磁盘中读取的方法(即成员函数),这种对象的保存和恢复过程成为序列化
2. 实现条件:
A. 类必须直接或间接地从CObject类派生而来;
B. 类必须定义一个不带参数的构造函数,当从磁盘文件载入文档时调用该构造函数来创建一个可序列化的对象,使用从文件中读出来的数据填充对象的成员变量
C. 在类的头文件中使用DECLARE_SERIAL宏,在类的实现文件中使用IMPLEMENT_SERIAL宏;
D. 在自定义类中重载序列化成员函数Serialize();