深入跟踪MFC程序的执行流程

来源: http://blog.csdn.net/ljianhui/article/details/8781991

在MFC程序设计的学习过程中最令人感到难受,甚至于有时会动摇学习者信心的就是一种对于程序的一切细节都没有控制权的感觉。这种感觉来源于学习者不知道一个MFC程序是如何运行起来的(即一个MFC程序的执行流程)和MFC程序的设计思想和机制,即使是写过Windows程序的学习者,也会感到非常迷惘并且无从下手。而这种感觉的出现会使大家认为自己离开了书本上的例子就无法设计编制程序。下面我就来说一说一个MFC具体是如何被执行的。在阅读本文之前,你要有一定的Windows程序设计基础,知道Windows程序的运行流程,如不清楚,可先看看我写的这篇文章——解说一个简单的Win32程序

一、单文档项目特点简述

以一个在VS2010中建立的一个单文档MFC程序来例子,深入跟踪MFC执行流程。工程名为MFCSDI,工程建立步骤不在这样详述。

当一个SDI(单文档)程序建立之后,我们会看到程序为我们生成了四个类:CAboutDlg、CChildView、CMainFrame、CMFCSDIApp。在它们的头文件中可以看到CCAboutDlg是从CDialogEx类派生出来的,用来显示一个对话框窗口,该对话框用来显示与此程序相关的版本信息。CMainFrame由类CFrameWndEx派生而来,用为表示一个程序的框架。CHildView类由类CWnd派生而来,用于单文档程序的显示。CMFCSDIApp类由类CWinAppEx派生而来,用于表示一个MFC程序,在每一个MFC程序中都有一个C+工程名+App的类(本例子中为CMFCSDIApp),它定义了一个全局对象theApp,它是一个应用程序对象,它就代表着这个程序。一个MFC程序有且只有一个这样的从CWinAppEx派生出来的类,也有且仅有一个从从CWinAppEx派生出来的类(如这里的CMFCSDIApp)所实例化的对象。

由此可见,这个MFC单文档程序并不像之前所说的Win32程序那样有一条清晰的主线。一个Windows程序从WinMain函数开始,经过注册窗口类、创建窗口、显示和刷新窗口才使得该程序的窗口界面为用户可见,然后建立进行消息循环,用户对此界面所作的任何操作都会被Windows作为消息传递给程序的窗口函数,并由窗口函数对消息进行分类处理,这些工作都是被 WinMain函数独自包办的。但在MFC程序中WinMain函数的地位被CWinApp类取代了,它所负责的全部初始化工作和对消息解释及分派都有 CWinApp类的内部函数来完成,但是WinMain仍然存在,并且扮演着驾驭CWinApp的角色。但我们在生成的所有文件的代码中,也找不到WinMain函数。而且这几个类之间是通过什么联系起来,组成一个Windows程序的呢?

二、在WinMain执行前初始化的全局变量theApp

前面说过,theApp是一个应用程序对象,它就代表着这个程序。一个MFC程序有且只有一个这样的从CWinAppEx派生出来的类,也有且仅有一个从从CWinAppEx派生出来的类(如这里的CMFCSDIApp)所实例化的对象。因为它是一个全局变量,根据C++的特点,它可以在WinMain函数执行前进行自己的初始化。

所以,要构造theApp对象就要调用其构造函数,由于CMFCSDIApp的基类为CWinAppEx,CWinAppEx的基类为CWinApp,由于要构造子类,就要先构造父类,即要构造theApp对象就要先调用CWinApp的构造函数来构造父类,CWinApp的构造函数对theApp的一些参数作初始化。

三、调用WinMain函数

构造完theApp这个全局对象后,就进入WinMian函数,它的代码在mfc代码所在目录下的appmodul.cpp文件中,这个函数名为_tWinMain,咋一看与我们在Win32所用的WinMain函数的名字不一样,其实_tWinMain是一个宏,到它的定义处一看,就知道它代表的正是WinMain,它的写法与我们在Win32程序中的WinMain函数是一样的。这个_tWinMain会调用一个函数AfxWinMain,这个函数在文件winmain.cpp中定义,而这个函数会有一条语句pThread->InitInstance(),pThread是一个窗口线程的指针,它的值由函数AfxGetThread()所得,根据多态性的原理,pThread会获得一个指向子类的指针,所以它会调用CMFCSDIApp类的成员函数CMFCSDIApp::InitInstance(),这个函数会初始化一些程序运行所需要的资源。

四、注册窗口

初始化一些所需的资源之后,就要对窗口类进行注册。MFC会调用函数AfxEndDeferRegisterClass注册窗口类,该函数的定义在文件wincore.cpp中。在Win32中时,我们需要设计一个窗口类,但是MFC已为我们设计好一个默认的窗口类,这里我们进行注册就行。

五、产生窗口

注册完窗口类之后,就会调用CMainFrm类的成员函数CMainFrm::PreCreateWindow来创建窗口,而这个函数会去调用它的父类的成员函数CFrameWnd::PreCreateWindow来创建窗口,在这个函数中可以对一些MFC设计好的默认的窗口类作一些修改,然后会调用AfxEndDeferRegisterClass函数进行窗口类的注册。之后,就会调用CFrameWnd::Create函数进行窗口的创建,该函数的定义在文件winfrm.cpp中,而该在窗口创建过程中该函数又会调用CWnd::CreateEx函数来对窗口进行创建,CWnd::CreateEx定义在文件wincore.cpp中。窗口创建完成后,会调用ShowWindow函数和UpdateWindow函数显示窗口,这两个函数在函数CMFCSDIApp::InitInstance()中被调用(在文件MFCSDI.cpp中)。

在一个程序中可以见到PreCreateWindow会被调用很多次,这是因为我们产生一个程序时会注册很多个窗口,如工具栏,按钮等,每创建一个窗口都要调用AfxEndDeferRegisterClass函数来进行窗口类注册,所以这两个函数就被多次地调用了。

六、建立消息循环

回到一开始所说的AfxWinMain函数中,里面有一条语句nReturnCode = pThread->Run();其实这就是建立消息循环。在文件thrdcore.cpp中可以找到它的定义(CWinThread::Run),它会循环调用函数PumpMessage(同样定义在文件thrdcore.cpp中),PumpMessage函数又会调用函数AfxInternalPumpMessage(在文件thrdcore.cpp中),它会调用函数GetMessage,它就等同于我们Win32程序中的函数GetMessage,然后调用函数::TranslateMessage,::DispatchMessage这与我们所写的Win32程序是一致的。

七、窗口过程

MFC在窗口类注册时就给它指定了一个默认的窗口过程,在函数AfxEndDeferRegisterClass(wincore.cpp)中有如下语句,wndcls.lpfnWndProc = DefWindowProc;把窗口过程指定为默认的窗口过程,而MFC则会通过消息映射转换处理过程,使我们的程序能响应不同的消息。

八、窗口的销毁

MFC程序的死亡相对于初生来说要简单的多,主要是以下几步:

  1.使用者通过点击File/Close或程序窗口由上角的叉号发出WM_CLOSE消息。

  2.程序没有设置WM_CLOSE处理程序,交给默认处理程序。

  3.默认处理函数对于WM_CLOSE的处理方式为调用::DestoryWindow,并因而发出WM_DESTORY消息。

  4.默认的WM_DESTORY处理方式为调用::PostQuitMessage,发出WM_QUIT。

  5.CWinApp::Run收到WM_QUIT后结束内部消息循环,并调用ExinInstance函数,它是CWinApp的一个虚拟函数,可以由用户重载。

  6.最后回到AfxWinMain,执行AfxWinTerm,结束程序。

本文中,我用到的文件的路径如下,写出来给大家参考一下,大家可以找到这些函数,设置断点,调试运行看一看程序的具体执行流程。

D:\ProgramFiles\Microsoft Visual Studio 10.0\VC\atlmfc\src\mfc\appmodul.cpp

D:\ProgramFiles\Microsoft Visual Studio 10.0\VC\atlmfc\src\mfc\winmain.cpp

D:\ProgramFiles\Microsoft Visual Studio 10.0\VC\atlmfc\src\mfc\winfrm.cpp

D:\ProgramFiles\Microsoft Visual Studio 10.0\VC\atlmfc\src\mfc\appcore.cpp

D:\ProgramFiles\Microsoft Visual Studio 10.0\VC\atlmfc\src\mfc\wincore.cpp

D:\ProgramFiles\Microsoft Visual Studio 10.0\VC\atlmfc\src\mfc\thrdcore.cpp

时间: 2024-10-11 05:44:08

深入跟踪MFC程序的执行流程的相关文章

PHP程序的执行流程

Web环境我们假设为Apache.在编译PHP的时候,为了能够让Apache支持PHP,我们会生成一个mod_php5.so的模块. Apache加载这个模块,在url访问.php文件的时候,就会转给mod_php5.so模块来处理.这个就是我们常说的SAPI.英文名字 是:Server Application Programming Interface.SAPI其实是一个统称,其下有 ISAPI,CLI SAPI,CGI等.有了它,就可以很容易的跟其他东西交互,比如APACHE,IIS,CGI

TXT编写程序-编译-执行流程

DOS下  1切换到程序路径Test.java这 2.javac  Test.java    >>>>>得到  .class 文件 3.java  Test             >>>>>得到 Test.java文件的输出结果 原文地址:https://www.cnblogs.com/2016-cxp/p/8654775.html

MFC 程序入口和执行流程

一 MFC程序执行过程剖析 1)我们知道在WIN32API程序当中,程序的入口为WinMain函数,在这个函数当中我们完成注册窗口类,创建窗口,进入消息循环,最后由操作系统根据发送到程序窗口的消息调用程序的窗口函数.而在MFC程序当中我们不在能找到类似WinMain这样的程序入口,取而代之的是一系列派生类的声明和定义以及一个冲CWinApp类派生而来的类的全局对象.CWinApp类被称之为应用程序对象,在一个MFC程序当中只允许有一个应用程序对象.由于CWinApp的派生对象是全局的,因此这个对

【转载】MFC 程序入口和执行流程

原文链接: http://www.cnblogs.com/liuweilinlin/archive/2012/08/16/2643272.html 一 MFC程序执行过程剖析 1)我们知道在WIN32API程序当中,程序的入口为WinMain函数,在这个函数当中我们完成注册窗口类,创建窗口,进入消息循环,最后由操作系统根据发送到程序窗口的消息调用程序的窗口函数.而在MFC程序当中我们不在能找到类似WinMain这样的程序入口,取而代之的是一系列派生类的声明和定义以及一个冲CWinApp类派生而来

【转】MFC 程序入口和执行流程

一 MFC程序执行过程剖析 1)我们知道在WIN32API程序当中,程序的入口为WinMain函数,在这个函数当中我们完成注册窗口类,创建窗口,进入消息循环,最后由操作系统根据发送到程序窗口的消息调用程序的窗口函数.而在MFC程序当中我们不在能找到类似WinMain这样的程序入口,取而代之的是一系列派生类的声明和定义以及一个冲CWinApp类派生而来的类的全局对象.CWinApp类被称之为应用程序对象,在一个MFC程序当中只允许有一个应用程序对象.由于CWinApp的派生对象是全局的,因此这个对

MFC程序执行过程剖析

一 MFC程序执行过程剖析 1)我们知道在WIN32API程序当中,程序的入口为WinMain函数,在这个函数当中我们完成注册窗口类,创建窗口,进入消息循环,最后由操作系统根据发送到程序窗口的消息调用程序的窗口函数.而在MFC程序当中我们不在能找到类似WinMain这样的程序入口,取而代之的是一系列派生类的声明和定义以及一个冲CWinApp类派生而来的类的全局对象.CWinApp类被称之为应用程序对象,在一个MFC程序当中只允许有一个应用程序对象.由于CWinApp的派生对象是全局的,因此这个对

mfc程序执行入口

一 MFC程序执行过程剖析 1)我们知道在WIN32API程序当中,程序的入口为WinMain函数,在这个函数当中我们完成注册窗口类,创建窗口,进入消息循环,最后由操作系统根据发送到程序窗口的消息调用程序的窗口函数.而在MFC程序当中我们不在能找到类似WinMain这样的程序入口,取而代之的是一系列派生类的声明和定义以及一个冲CWinApp类派生而来的类的全局对象.CWinApp类被称之为应用程序对象,在一个MFC程序当中只允许有一个应用程序对象.由于CWinApp的派生对象是全局的,因此这个对

MFC程序逆向 – 消息篇(下)

上篇啰里啰嗦地说了一大堆,其实所说的消息都是PostMessage方式的.MFC中还有另外一种很常见的消息发送方式,就是SendMessage函数.这个消息起始路径和上篇所讲的完全不一样.这种方式下,前面的7个站点均不执行,而是直接进入第8站点:User32内核,从第8站点出来后,这两种消息方式走上了同一条道路,进入第9个站点或第10个站点了,真是殊道同归.对于MFC窗口程序,所有窗口都使用同一窗口过程 : AfxWndProcBase(第9个站点)或AfxWndProc(第10个站点).如果程

MFC程序逆向 – 消息篇(上)

标 题: [原创]MFC程序逆向 – 消息篇(上)+(下) 11楼作 者: szdbg时 间: 2007-10-31,06:26:02链 接: http://bbs.pediy.com/showthread.php?t=54150 前言:记得前一段时间,我刚接触软件破解和逆向这一行时,对于一些软件不知从何处跟踪按钮消息,试了好多方法,就是断不下来,在系统模块中经常转得晕头转向,而一无所获. MFC程序是一种常见类型的程序,我静下心来,潜心研究了一下MFC消息流程.弄清原委之后,一切豁然开朗,发现