MFC 程序入口和执行流程

本文详细解析了MFC程序的执行过程,包括从启动、初始化到消息循环及关闭的全过程。并以VC6中的SDI程序为例,通过调试演示了各关键函数的调用顺序。

一 MFC程序执行过程剖析

1)我们知道在WIN32API程序当中,程序的入口为WinMain函数,在这个函数当中我们完成注册窗口类,创建窗口,进入消息循环,最后由操作系统根据发送到程序窗口的消息调用程序的窗口函数。而在MFC程序当中我们不在能找到类似WinMain这样的程序入口,取而代之的是一系列派生类的声明和定义以及一个冲CWinApp类派生而来的类的全局对象。CWinApp类被称之为应用程序对象,在一个MFC程序当中只允许有一个应用程序对象。由于CWinApp的派生对象是全局的,因此这个对象的构造函数会在所有的其他代码运行之前被调用,而由于CWinApp类当中包含了HWND、HINSTANCE等句柄的存在,其构造函数就执行了对这些成员数据的初始化操作,这里的所谓初始化仅仅是把所有的句柄对象赋值为NULL。

2)在调用完CWinApp的构造函数以后由连接器向程序内自动链接的AfxWinMain函数将被调用,而这个函数可以被看作MFC程序的入口函数。在这个函数当中调用全局AfxGetApp()函数获得应用程序对象,这时将调用AfxInit全局函数,这个函数的功能是使用操作系统传递给AfxWinMain函数的参数初始化应用程序对象当中的相关句柄数据成员。

3)之后AfxWinMain函数调用CWinApp::InitApplication成员函数,这个成员函数用来初始化应用程序对象当中的关于文档部分的内容。

4)随后调用CWinApp::InitInstance成员函数,在这个成员函数当中,使用new操作在堆上声明一个框架窗口对象,由此导致框架窗口对象的构造函数被调用,在框架窗口构造函数当中调用Create函数来创建窗口,而调用的Create函数一般将WNDCLASS参数设置成NULL,这样就由MFC内部调用PreCreateWindow函数,在这个函数当中由MFC注册几个默认的WNDCLASS供框架窗口的Create使用。这时程序控制权交还给CWinApp::InitInstance成员函数内部,由这个函数调用CWnd::ShowWindow显示窗口并且调用CWnd::UpdateWindow向窗口发送WM_PAINT消息。调用完CWinApp::InitInstance成员函数后由AfxWinMain函数调用CWinApp::Run成员函数,并由这个函数来创建和处理消息循环,并且在没有消息的时候处理OnIdle空闲处理。至此整个程序的创建过程完成。
 5)在程序的运行过程当中,由操作系统源源不断的发送消息给应用程序,并且由CWinApp::Run当中的消息循环处理并且分发给相关的窗口对象的DefWindowProc成员函数,并由这个成员函数查询窗口对象的消息映射表,如果查到对应项,则由登记在消息映射表当中的类成员函数处理,否则则按照Message Route当中的顺序象父层类发送。
 6)在消息运行结束,用户按下关闭按钮后,操作系统向程序发送WM_CLOSE消息,默认状况下程序调用DestoryWindow并且发送WM_DESTORY消息,应用程序接受到这个消息以后的默认操作是调用PostQuitMessage函数,由这个函数发送WM_QUIT消息。当程序对象接受到WM_QUIT消息后消息循环结束,由AfxWinMain函数调用AfxTerm函数清理程序使用过的资源并且结束整个程序。
小结:以上的所有描述涵盖了一个程序从开始、运行到结束的所有过程。
相信大家有点晕点了吧,实际编程中没有必要深刻理解这么多,这些大都是由MFC内部自动帮我们完成的。实际MFC编程过程中,其实懂得MFC程序中各个函数的执行流程即可。有时候过于追究MFC细节会白白浪费我们的精力,应该将主要精力放在使用MFC解决实际问题上。

二 VC6中SDI程序的执行流程
下面以VC6中的sdi工程为例,通过给每个函数前设置断点后调式执行,可以看出MFC的SDI的执行流程。记录如下,希望对MFC执行有疑惑的人有帮助。
1)CSdiApp theApp;          //sdi.cpp
2)CSdiApp::CSdiApp()             //sdi.cpp
3)BOOL CSdiApp::InitInstance()         //sdi.cpp
4)CSdiDoc::CSdiDoc()                   //sdiDoc.cpp
5)CMainFrame::CMainFrame()          //MainFrm.cpp
6)BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)    //MainFrm.cpp
7)int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)    //MainFrm.cpp
8)CSdiView::CSdiView()                     //sdiView.cpp
9)BOOL CSdiView::PreCreateWindow(CREATESTRUCT& cs)         //sdiView.cpp
10)BOOL CSdiDoc::OnNewDocument()                //sdiDoc.cpp
11) void CSdiView::OnDraw(CDC* pDC)                //sdiView.cpp
// ---------------- 关闭窗口后-------------------------------------
12) CSdiView::~CSdiView()
13) CMainFrame::~CMainFrame()
14) CSdiDoc::~CSdiDoc() 
 
### MFC 程序入口函数及 CWinApp::InitInstance 调用时机 MFC(Microsoft Foundation Classes)是一种面向对象的框架,简化了 Windows 应用程序开发的过程。对于基于 MFC 的应用程序而言,其真正的入口点并非传统的 `main` 或者 `WinMain` 函数,而是由 MFC 提供的一个隐藏的入口点——`AfxWinMain`[^2]。 #### MFC 程序入口函数 在典型的 MFC 应用程序中,开发者无需显式编写 `WinMain` 函数。这是因为 MFC 已经提供了一个封装好的版本,即 `AfxWinMain`。它位于动态链接库(DLL)或静态库中,并作为程序的实际入口点。以下是 `AfxWinMain` 的大致功能分解: - **初始化模块状态**:创建并初始化 `_afxDllModuleManager` 对象以管理模块状态。 - **解析命令行参数**:通过调用 `ParseCommandLine` 解析传递给应用程序的命令行参数。 - **调用核心方法**:依次调用 `CWinApp::InitApplication` `CWinApp::InitInstance` 完成应用程序级别的初始化实例级初始化。 - **启动消息循环**:一旦初始化完成,便进入消息循环阶段,等待处理来自操作系统的各种事件直至退出。 具体来说,`AfxWinMain` 内部会执行以下关键步骤: 1. 创建一个全局变量 `_afxThreadState` 表示线程状态。 2. 加载资源句柄并通过 `AfxSetResourceHandle` 设置为当前进程使用的默认资源句柄。 3. 实例化用户定义的应用程序类(通常是派生于 `CWinApp`),从而触发构造函数运行。 4. 调用 `CWinApp::InitApplication` 处理通用设置如字体注册等。 5. 继续调用 `CWinApp::InitInstance` 让开发者有机会进行更详细的定制化初始化工作[^2]。 #### CWinApp::InitInstance 的调用时机 `CWinApp::InitInstance` 是一个虚函数,在每次新创建的应用程序实例开始时都会被调用一次。它的主要目的是让用户能够在此处添加自己的初始化逻辑,例如创建主窗口、加载配置数据或其他必要准备动作。以下是关于何时以及如何调用的一些要点说明: - 当前上下文中,“实例”指的是单独的一次程序运行而不是多个副本之间的共享部分;因此即使同一个 .exe 文件可能多次被执行,每个独立运行都只会经历属于自己那次运行周期内的唯一一次 `InitInstance` 调用。 - 此函数是在 `AfxWinMain` 控制流到达一定进度之后才会触达的位置 —— 即所有前期准备工作均已妥善安排妥当之时方才轮到它登场亮相。 - 开发人员可以在自己继承自 `CWinApp` 的子类里面覆盖掉原始版的 `InitInstance` 方法来注入个性化的业务规则。例如分配内存空间予新的框架窗体实例 (`new`) 并将其赋值给基类成员属性 `m_pMainWnd` ,进而使得后续操作有所依据[^3]。 下面是一个标准实现的例子演示了怎样正确地覆写该方法: ```cpp class CMyApp : public CWinApp { public: virtual BOOL InitInstance(); }; BOOL CMyApp::InitInstance() { // 创建主窗口 CMainFrame* pMainFrame = new CMainFrame; if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE; m_pMainWnd = pMainFrame; // 显示主窗口 pMainFrame->ShowWindow(SW_SHOW); pMainFrame->UpdateWindow(); return TRUE; } ``` 在这里可以看到,我们不仅完成了基本的任务像构建 GUI 结构那样简单的事情之外,还可以扩展至更多领域诸如网络连接建立或是数据库打开之类的复杂场景下去做文章[^3]。 --- ### 总结 综上所述,MFC 程序的真实入口是由框架本身提供的特殊形式的 `AfxWinMain` 函数代替传统意义上的 `WinMain` 。而在这一连串复杂的启动过程中间,`CWinApp::InitInstance` 则扮演着至关重要的角色,它是留给最终使用者用来实施特定需求层次上的最后一步重要环节所在之处[^2][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值