MFC程序的生存过程

一、MFC的结构

MFC(Microsoft Foundation Class Library)是微软公司开发的一组C++类库,用于开发Windows图形用户界面(GUI)应用程序。MFC的主要组成包括以下几个方面:

  1. 应用程序框架(Application Framework):包括CWinApp类、CFrameWnd类、CMDIFrameWnd类、CDialog类等,用于创建应用程序的主窗口、菜单、工具栏、状态栏等界面元素,以及处理消息、事件等应用程序逻辑。

  2. 控件库(Control Library):包括CButton类、CEdit类、CListCtrl类、CTreeCtrl类、CComboBox类等,用于创建各种常见的界面控件,例如按钮、文本框、列表框、树形控件、下拉框等。

  3. 文档视图模型(Document/View Architecture):包括CDocument类、CView类、CScrollView类、CFormView类等,用于实现文档视图模型架构,即将数据模型(Document)和用户界面(View)分离,使得数据和界面可以独立地进行操作和管理。

  4. 数据库支持(Database Support):包括CRecordset类、CDatabase类、CDataSource类等,用于实现对关系型数据库的访问和操作,例如打开数据库连接、执行SQL语句、读取和写入数据等。

  5. ActiveX控件支持(ActiveX Control Support):包括COleControl类、COleControlSite类、COleDispatchDriver类等,用于实现ActiveX控件的开发和使用,例如创建和嵌入ActiveX控件、调用控件的方法和属性等。

MFC的主要组成部分可以帮助开发者快速构建Windows图形用户界面应用程序,并且提供了丰富的功能和工具,使得开发过程更加高效和简便。

一个标准的MFC程序外貌

 

二、 MFC程序的启动与关闭顺序

普通win32程序的执行顺序

MFC程序的执行顺序

那么 ,现在来经历一个MFC程序的完整生命过程

1、创建Application theApp
第一件事情就是找出MFC程序的进入点。MFC程序也是Windows程序,所以它应该也有一个WinMain,,但是我们在程序看不到它的踪影。是的,但先别急,在程序进入点之前,还有一个(而且仅有一个)全局对象(本例名为hApp),这是所谓的application object,当操作系统将程序加载并激活时,这个全局对象获得配置,其构造函数会先执行,比WinMain更早。所以以时间顺序来说,我们先看看这个application object。

 下图所示,创建一个MFC工程,在MFCApplication1.cpp中有个全局变量CMFCApplication1App theApp;这个全局对象一产生,便执行其构造函数。CWinApp之中的成员变量将因为theApp这个全局对象的诞生而获得配置与初值。

2、WinMain登场

用SDK编程序时,程序的入口点是WinMain函数,而在MFC程序里我们并没有看到WinMain函数,原来它是被隐藏在MFC代码里面了。当theApp配置完成后,WinMain登场。细看程序,并没看到WinMain函数的代码啊!在MFC程序中,微软把WinMain函数封装起来,在MFC中是看不到的,代码实际上是在安装目录中,我的是在“C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\atlmfc\src\mfc\appmodul.cpp”,原来它在appmodul.cpp里面,好,我们就认为当theApp配置完成后,程序就转到appmodul.cpp来了。那执行什么呢?看看下面从appmodul.cpp摘出来的代码:

 extern "C" int WINapi

 _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
 {
     // call shared/exported WinMain
     return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
 }

_tWinMain函数的“_t”是为了支持Unicode而准备的一个宏。

 _tWinMain函数返回值是AfxWinMain函数的返回值,AfxWinMain函数定义于winmain.cpp第21行,稍加整理,去芜存菁,就可以看到这个“程序进入点”主要做些什么事:

int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
 {
     int nReturnCode = -1;
     CWinApp* pApp = AfxGetApp();

     AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

     pApp->InitApplication();
     pApp->InitInstance()
     nReturnCode = pApp->Run();

     AfxWinTerm();
     return nReturnCode;
 }

3、AfxWinInit——AFX内部初始化操作

 AfxWinInit是继CWinApp构造函数之后的第一个操作,主要做的是AFX内部初始化操作,该函数定义于APPINIT.CPP第24行,

BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPTSTR lpCmdLine, int nCmdShow)
{
	ASSERT(hPrevInstance == NULL);

	// handle critical errors and avoid Windows message boxes
	SetErrorMode(SetErrorMode(0) |
		SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);

	// set resource handles
	AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
	pModuleState->m_hCurrentInstanceHandle = hInstance;
	pModuleState->m_hCurrentResourceHandle = hInstance;

	// fill in the initial state for the application
	CWinApp* pApp = AfxGetApp();
	if (pApp != NULL)
	{
		// Windows specific initialization (not done if no CWinApp)
		pApp->m_hInstance = hInstance;
		pApp->m_hPrevInstance = hPrevInstance;
		pApp->m_lpCmdLine = lpCmdLine;
		pApp->m_nCmdShow = nCmdShow;
		pApp->SetCurrentHandles();
	}

	// initialize thread specific data (for main thread)
	if (!afxContextIsDLL)
		AfxInitThread();

	return TRUE;
}


4、执行CWinApp::InitApplication

 AfxWinInit之后的操作是pApp->InitApplication,我们已知道pApp指向CMyWinApp对象,当调用:
 pApp->InitApplication();

 相当于调用:

 CMyWinApp::InitApplication();

 但是你要知道,CMyWinApp继承自CWinApp,而InitApplication又是CWinApp的一个虚拟函数,我们并没有改写它(大部分情况下不需改写它),所以上述操作相当于调用:

 CWinApp::InitApplication();

 此函数定义于APPCORE.CPP第125行,你自己搜出来看吧!我就不搬出来了,里面的操作都是MFC为了内部管理而做的(其实我也看不懂,知道有这回事就好了)。

5、执行CWinApp::InitInstance

 继InitApplication函数之后,AfxWinMain调用pApp->InitInstance。当程序调用:

 pApp->InitInstance(); 相当于调用: CMyWinApp::InitInstance();

 但是你要知道,CMyWinApp继承自CWinApp,而InitInstance又是CWinApp的一个虚拟函数。由于我们改写了它,所以上述操作就是调用我们自己(CMyWinApp)的这个InitInstance函数。

6、CFrameWnd::Create产生主窗口(并先注册窗口类)

在已经来到CWinApp::InitInstance了,该函数先new一个CMyFrameWnd对象,从而产生主窗口。在创建CMyFrameWnd对之前,要先执行构造函数CMyFrameWnd::CMyFrameWnd(),该函数用Create函数产生窗口:
 

 CMyFrameWnd::CMyFrameWnd()
 {
     Create(NULL, "Hello MFC", WS_OVERLAPPEDWINDOW, rectDefault, NULL, "MainMenu");
 }

7、窗口显示与更新

 CMyFrameWnd::CMyFrameWnd结束后,窗口已经诞生出来;程序流程又回到CMyWinApp::InitInstance,于是调用ShowWindow函数令窗口显示出来,并调用UpdateWindow函数令程序送出WM_PAINT消息。在SDK程序中,消息是通过窗口函数来处理,而现在窗口函数在哪里、又如何送到窗口函数手中呢?那要从CWinApp::Run说起了。

8、执行CWinApp::Run

 在执行完CMyWinApp::InitInstance函数后,程序的脚步到了AfxWinMain函数的pApp->Run了,现在我们已知道这将执行CWinApp::Run函数,该函数定义于APPCORE.CPP第391行,下面是程序代码:

int CWinApp::Run()
 {
     if (m_pMainWnd == NULL && AfxOleGetUserCtrl())
     {
         // Not launched /Embedding or /Automation, but has no main window!
         TRACE0("Warning: m_pMainWnd is NULL in CWinApp::Run - quitting application.n");
         AfxPostQuitMessage(0);
     }
     return CWinThread::Run();
 }

9、把消息与处理函数连接在一起——Message Map机制

到此,主窗口已经产生,等待的就是各种消息了,然后调用相应的处理函数,然而消息和处理函数怎样连接在一起呢?MFC采用了Message Map机制(消息映射机制),提供给应用程序使用的“很方便的接口”的两组宏,这里就不细讲了。

所以,总的调用结构就是

三、 总结

参考:

mfc的生与死 (转)_csd3176的博客-CSDN博客

MFC程序的出生和结束-ruanbanyong1-ChinaUnix博客

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值