任何程序都有一个入口函数,我们在学习C语言的时候入口函数是main函数,学习Win32也是有main函数的,Win32的入口函数是_tWinMain(),因为MFC对Win32API进行了封装,所以在MFC的代码中我们是找不到_tWinMain()入口函数的,这增加了我们学习MFC的难度,很多同学都不知道程序是从哪里开始运行的,为了解决这个问题,我通过设置断点的方式,一步一步跟踪代码的执行,分析出了MFC整体的运行流程。
首先我使用VisualStudio2010提供的搜索功能搜索_tWinMain(),注意这里搜索的路径不能是当前工程路径,当前工程路径里的文件是找不到的,必须是在安装目录里的VC库里去搜索,如图11示: 不管MFC怎么进行封装,它的原理还是和Win32一样的,所以在库里里面搜索一定可以找到我们需要的_tWinMain函数,图13示 可以看到,搜索结果中第一个就是我们要找的函数。进入这个函数之后,设置一个断点,然后调试整个程序,可以看到程序果然运行到断点处,图14示 从_tWinMain函数内部我们发现,里面只有一句代码:returnAfxWinMain(hInstance,hPrevInstance, lpCmdLine, nCmdShow);也就是说MFC使用AfxWinMain替代了_tWinMain函数,原来的_tWinMain函数实际上是没有任何用处的,我们继续跟踪,图15示 在AfxWinMain内部我们终于看见我们熟悉的InitInstance()函数了,其中里面的类都是通过继承和多态的特性进行工作的,CWinApp继承CWinThread类,我们新建的类CDemoADOApp继承CWinApp,任何应用程序只有一个CWinApp类,在CWinThread的成员函数中有InitInstance、Run、ExitInstance三个主要的函数,且这三个函数都是虚函数,我们的类CDemoADOApp通过继承CWinApp类,重写InitInstance和ExitInstance函数,根据面向对象的多态性,当执行pThread->InitInstance()这一句代码时执行的函数不再是CWinThread或CWinApp里的InitInstance,而是CDemoADOApp类的InitInstance,我们通过调试工具进入InitInstance内部,图16示 可以发现,程序果然跳转到CDemoADOApp类的InitInstance()里面,在InitInstance()里面我们可以对我们的应用程序做初始化工作,当需要的配置都做好之后,退出InitInstance函数,再次回到AfxWinMain函数,接下来程序就会执行Run函数,等待消息响应。图17示 Win32采用的是消息循环的机制,通过捕捉应用程序上所有消息,识别之后送到相应的消息处理函数去处理操作,MFC也是基于这个机制,不过MFC使用的是消息映射与反射,就是将消息与处理函数通过制定宏建立联系,归根到底也是和Win32原理一样。 调试跟踪到这里,程序的整体脉络也大体清晰了,简单来讲AfxWinMain函数内部就执行三个函数InitInstance、Run、ExitInstance,InitInstance初始化,Run循环等待消息并执行相应处理程序,ExitInstance在程序结束之后做收尾工作,如释放资源等。 我认为学习VC++最重要的是弄清楚MFC的运行机制,弄清楚MFC的运行机制之前先要明白Win32又是怎么工作的,只要明白了Win32的工作流程,理解MFC就会变得简单很多了,至于其它的开发,都是基于这个运行机制,所以调试分析我没有对其他窗口的实现进行分析,而是着重分析了应用程序的执行流程。
|