一、开篇引论
熟悉Win32开发的朋友,应该非常了解它的基本组成和流程
1. WinMain:书写窗口类(WNDCLASS) -> 注册窗口类 -> 创建窗口 -> 显示窗口和更新窗口 -> 消息循环
2. WndProc(回调函数):消息处理函数,由windows操作系统自行调用
而MFC呢,就是用c++面向对象的编程思想将这些主要成分封装到各个基本类中,由于封装得很隐蔽,所以学习它的难度就大大增加了。今儿,我就带着大家一起来剖析一下MFC的来龙去脉
在看后面两点之前,先上一份剖析MFC最简单的代码(MFC版的Hello):
1. Hello.h:
只有CMyApp和CMainWindow两个类,它们分别是CWinApp、CFrameWnd的子类,这两个基类有分别封装了WinMain和消息映射机制(相当于WndProc的消息处理)
//Hello.h //封装了Win32的WinMain函数的处理过程 class CMyApp : public CWinApp { public: virtual BOOL InitInstance (); }; //实现了MFC的消息机制 class CMainWindow : public CFrameWnd { public: CMainWindow (); protected: afx_msg void OnPaint (); DECLARE_MESSAGE_MAP ()//消息映射的声明 };
2. Hello.cpp//Hello.cpp #include <afxwin.h> #include "Hello.h" CMyApp myApp; ///////////////////////////////////////////////////////////////////////// // CMyApp member functions BOOL CMyApp::InitInstance () { m_pMainWnd = new CMainWindow; m_pMainWnd->ShowWindow (m_nCmdShow); m_pMainWnd->UpdateWindow (); return TRUE; } ///////////////////////////////////////////////////////////////////////// // CMainWindow message map and member functions //消息映射 BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd) ON_WM_PAINT () END_MESSAGE_MAP () CMainWindow::CMainWindow () { Create (NULL, _T ("The Hello Application")); } void CMainWindow::OnPaint () { CPaintDC dc (this); CRect rect; GetClientRect (&rect); dc.DrawText (_T ("Hello, MFC"), -1, &rect, DT_SINGLELINE |DT_CENTER | DT_VCENTER); }
今天主要利用这两份源代码来剖析MFC的"WinMain"和消息机制,下面进入主题(我就不说什么F话了,直接切入^_^)
二、MFC的"WinMain函数"跑哪儿去了呢?
要想找到它,我给大家介绍一种很有效的方式:
1. 如果你是VC++6.0,就用"Call Stack"(下图红色框圈住的按钮)
2. 如果是VS2008,就用"堆栈帧"(在调试模式下,会出现)
我这里使用的是vc++6.0:
1. 先在OnPaint函数(处理WM_PAINT消息)那儿设置一个端点
2. 键入F5进入调试模式,然后点击"Call Stack",得到的结果如下:
接下来需要做的工作就是一一跟踪这些函数,跟踪一会儿你就能很快了解到MFC中关于Win32的各个实现细节
在这里,由于篇幅的限制,我就直接明述跟踪结果(你可以自行按照上述方法跟踪,这样才有助于深入理解):
1. 全局变量CMyApp myApp;
2. _tWinMain
3. 全局变量myApp的InitInstance()函数
4. 窗口类的注册
5. 创建窗口
6. 显示、更新窗口(还是调用myApp的InitInstance()函数)
7. 进入WndProc,处理消息响应
这里我仅仅将大致的过程贴出来,给你一个大致思路,具体的需要你自己去调试、探究,这样的难度应该就小很多了
三、MFC的消息映射机制
这是MFC的精华所在,它将Win32的消息处理(以WM_开头的消息)过程 映射为 类函数成员函数的处理过程,这样才能符合面向对象的编程思想。其实,它就是使用一大堆宏来实现一种类似于c++的多态机制,因此,要想深入了解这个消息机制,我们必须剖析这些宏:
DECLARE_MESSAGE_MAP ()//消息映射的声明
//消息映射
BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd)
ON_WM_PAINT ()
END_MESSAGE_MAP ()下面我们一一展开这些宏:(方法很简单,就是在IDE(集成编译环境 就是编译器)中右键对应的宏,然后选择" Go To Definition Of *** " )
1. 首先展开DECLARE_MESSAGE_MAP
1)未展开的
2)展开后
2. 展开
{BEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd)
ON_WM_PAINT ()
END_MESSAGE_MAP ()}
1)未展开的
2)展开后
看到这里,你也许有一点儿蒙,为此,我自行绘制了一张图,它能很好的诠释消息机制的流程关系
好了,现在你应该能明白了吧,可能你还会有一个问题:
MFC本身使用c++封装的,又用一些宏来实现一个类似c++多态的消息映射机制,这不是有些多余吗?
表面上看似是这么回事儿,其实,据我了解到,当时微软的MFC的架构师们测试过,如果用c++的多态性实现,基本上每一个类的对象的储存空间要多那么几十到几百K,它们觉得这样很浪费内存,所以想出了这么一个类似于多态的消息消息映射机制