mfc学习之分析mfc程序执行过程

本文通过跟踪MFC程序的执行流程,详细解析了MFC程序的启动过程,包括全局对象的作用、构造函数的执行顺序、宏定义的作用以及如何找到程序的真正入口点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

     在前几天学习自己动手创建了一个mfc程序之后,生出了一个疑问,作为一个新手,在学习c++标准语法的时候,基本都是控制台程序,而且众所周知程序都会有一个入口点也就是main函数,而在mfc程序中,只是定义了一个全局对象theApp,和重写了一个初始化函数,没有看到任何的主函数,然后资料上说mfc将入口函数也给封装起来了,因此今天准备跟踪一下mfc程序的执行流程,以FirstMFC为例

因为全局变量先于入口函数执行,因此程序会先执行CMyWinApp myApp; 因为该过程会创建对象,进入构造函数,因此在他之前加断点调试

按F11进入构造函数内部,会先进入本类的构造函数,再按F11进入父类的构造函数


在父类的构造函数中发现有两个宏定义AFX_MODULE_STATE和AFX_MODULE_THREAD_STATE,一头雾水,在网上查阅了很多资料也没得出个所以然,在这里分享一篇分析较好的文章

http://blog.163.com/maple_zh@126/blog/static/10712959820132219189932/

继续跟代码发现这两个宏其实是两个类,都派生自一个叫CNoTrackObject的类,进入这个类,发现它冲在了new跟delete操作符

至于这个类出现的意义,在网上查询得到的解释是用来记录内存块和给每一个对象分配一个单独的内存块(有待考证),最终得到信息是

 

AFX_MODULE_STATE     定义的变量记录当前程序模块状态信息

AFX_MODULE_THREAD_STATE 定义的变量记录当前程序线程状态信息


而用pModuleState指针和pThreadState指针分别获取了_afxThreadState和m_thread这两个全局变量的地址



执行到断点处可以发现,mfc将当前myApp对象的地址保存到了AFX_MODULE_THREAD_STATE类的成员变量CWinThread* m_pCurrentWinApp中,即CWinApp(CMyWinApp的父类)拿到了CMyWinApp的地址,而下面的AfxGetThread又重新拿到了myApp的地址(不理解)

CWinThread* AFXAPI AfxGetThread()
{
	// check for current thread in module thread state
	AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
	CWinThread* pThread = pState->m_pCurrentWinThread;
	return pThread;
}

继续执行mfc又将将当前myApp对象的地址保存到了AFX_MODULE_STATE类的成员变量CWinApp* m_pCurrentWinApp中

从这里可以看出CwinApp的构造函数主要完成了以下几个功能

1) 将myApp对象地址保存到当前程序模块状态信息中。

2) 将myApp对象地址保存到当前程序线程状态信息中。

3) AfxGetThread/AfxGetApp – 返回myApp对象地址。

因此可以猜测,当前myApp对象地址会在之后的窗口创建过程中会用到

至此父类的构造函数执行完毕,退出父类构造函数开始执行子类构造,子类构造执行完毕应该开始执行main函数,也就是需要寻找的程序入口点,由于不知道函数入口点在哪,但是可以肯定的是入口函数会调用CMyWinApp::InitInstance函数来实现窗口的创建过程,因此可以借助vs的调用堆栈工具来查找函数之间的调用关系,如

进入入口函数

点击单步调试进入AfxWinMain

CWinThread* pThread = AfxGetThread();//获取myApp对象地址
	CWinApp* pApp = AfxGetApp();//获取myApp对象地址

	// AFX internal initialization
	if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))//初始化mfc库
		goto InitFailure;

	// App global initializations (rare)
	if (pApp != NULL && !pApp->InitApplication())//初始化应用程序
		goto InitFailure;

	// Perform specific initializations
	if (!pThread->InitInstance())
	{
		if (pThread->m_pMainWnd != NULL)
		{
			TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd\n");
			pThread->m_pMainWnd->DestroyWindow();
		}
		nReturnCode = pThread->ExitInstance();
		goto InitFailure;
	}
	nReturnCode = pThread->Run();
由代码可以看出在经过一系列初始化之后,执行到pThread->InitInstance,而pThread为基类指针存的是子类myApp的地址,由多态可以得到程序会调用我们重写的 CMyWinApp::InitInstance函数



此时程序回到我们写的初始化函数开始创建窗口





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值