MFC框架程序剖析

1、MFC程序中的WinMain函数
在win32应用程序中WinMain是入口函数,然后设计窗口类、注册窗口类,产生窗口,注册窗口,显示窗口,更新窗口,最后进入消息循环,将消息录音到窗口过程函数中去处理。
在MFC程序中微软把WinMain函数封装起来,在MFC中是看不到的,实际上是在安装目录中我的是在“D:\Visual Studio Ultimate 2013\VC\atlmfc\src\mfc\appmodul.cpp”
MFC框架程序剖析_第1张图片

_tWinMain实际上是一个宏:#define _tWinMain WinMian。展开之后就是WinMin函数

2、theApp全局变量
全局变量、全局对象,程序在运行时,在加载main函数之前,就已经为全局变量、全局对象分配了内存空间,对一个全局对象来说,此时会调用该对象的构造函数,构造该对象,并进行初始化操作。
对MFC程序来说,通过产生一个应用程序类的对象来唯一标识应用程序的实例。每一个MFC程序有且仅有一个从应用程序派生的类。每一个MFC程序实例有且仅有一个该派生类的实例化对象,即theApp全局对象。
该全局变量定义在MFCHello\MFCHello\MFCHello.cpp(我的应用程序名为MFCHello)
在这里插入图片描述
如果在CMFCHelloApp的构造函数中设置断点会发现,在程序运行时时先运行到该构造函数,然后才运行到上面的_tWinMain

3、AfxWinMain函数
在D:\Visual Studio Ultimate 2013\VC\atlmfc\src\mfc\winmain.cpp中

 int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    	_In_ LPTSTR lpCmdLine, int nCmdShow)
    {
    	ASSERT(hPrevInstance == NULL);
    
    	int nReturnCode = -1;
    	CWinThread* pThread = AfxGetThread();
    	CWinApp* pApp = AfxGetApp();
    
    	// AFX internal initialization
    	if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
    		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();
    
    InitFailure:
    #ifdef _DEBUG
    	// Check for missing AfxLockTempMap calls
    	if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
    	{
    		TRACE(traceAppMsg, 0, "Warning: Temp map lock count non-zero (%ld).\n",
    			AfxGetModuleThreadState()->m_nTempMapLock);
    	}
    	AfxLockTempMaps();
    	AfxUnlockTempMaps(-1);
    #endif
    
    	AfxWinTerm();
    	return nReturnCode;
    }

其中
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
以上两个指针调用的函数即完成了win32程序所需的几个步骤:设计窗口类、注册窗口类、创建窗口类、显示窗口、更新窗口、消息循环、以及窗口过程函数。

注:AFX
MFC以全局函数的形式提供了自己各类API函数,名字以Afx打头。类成员仅能在所属的对象说明体中被滴用,而在任何时候任何地方都可使用Afx函数。常用AFX函数如下。
MFC框架程序剖析_第2张图片
3、MFC框架窗口
(1)设计和注册窗口
有了WinMain函数后,设计窗口类和注册窗口类。窗口类的注册为AfxEndDeferRegisterClass在D:\Visual Studio Ultimate 2013\VC\atlmfc\src\mfc\wincore.cpp中
AfxEndDeferRegisterClass 函数首先判断窗口类的类型,然后赋予其相应的类名( wndcls.lpszClassName变量),这些类名都是MFC预定义的。之后就调用AfxRegisterClass函数注册窗口类,后者的定义也位于WINCORE.CPP文件中
AfxDeferRegisterClass 实际上是一个宏,真正指向的是AfxEndDefer-RegisterClass函数。根据前面介绍的内容,我们知道这里完成的功能就是注册窗口类。

(2)创建窗口
设计窗口类和注册窗口类后,就是创建窗口。在MFC中,窗口创建功能是由CWnd类的CreateEx函数实现,该函数声明位于AFXWin.h文件中,实现位于wincore.cpp中。

(3)显示和更新窗口
在MFCHello.cpp的InitInstance()中
在这里插入图片描述

4、消息循环
消息循环在CWinThread::Run()。在D:\Visual Studio Ultimate 2013\VC\atlmfc\src\mfc\thrdcore.cpp中

  int CWinThread::Run()
    {
    	ASSERT_VALID(this);
    	_AFX_THREAD_STATE* pState = AfxGetThreadState();
    
    	// for tracking the idle time state
    	BOOL bIdle = TRUE;
    	LONG lIdleCount = 0;
    
    	// acquire and dispatch messages until a WM_QUIT message is received.
    	for (;;)
    	{
    		// phase1: check to see if we can do idle work
    		while (bIdle &&
    			!::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE))
    		{
    			// call OnIdle while in bIdle state
    			if (!OnIdle(lIdleCount++))
    				bIdle = FALSE; // assume "no idle" state
    		}
    
    		// phase2: pump messages while available
    		do
    		{
    			// pump message, but quit on WM_QUIT
    			if (!PumpMessage())
    				return ExitInstance();
    
    			// reset "no idle" state after pumping "normal" message
    			//if (IsIdleMessage(&m_msgCur))
    			if (IsIdleMessage(&(pState->m_msgCur)))
    			{
    				bIdle = TRUE;
    				lIdleCount = 0;
    			}
    
    		} while (::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE));
    	}
    }

5、窗口过程函数
在AfxEndDeferRegisterClass函数中,位于D:\Visual Studio Ultimate 2013\VC\atlmfc\src\mfc\wincore.cpp中。窗口过程函数为:

这行代码的作用就是设置窗口过程函数,这里指定的是一个默认的窗口过程:DefWindowProc.但实际上, MFC程序并不是把所有消息都交给DefWindowProc这-默认窗口过程来处理的,而是采用了一种称之为消息映射的机制来处理各种消息的。

6、过程整理
■首先利用全局应用程序对象theApp启动应用程序。正是产生了这个全局对象,基
类CWinApp中的this指针才能指向这个对象。如果没有这个全局对象,程序在编译时不会出错,但在运行时就会出错。
■调用全局应用程序对象的构造函数,从而就会先调用其基类CWinApp的构造函数。后者完成应用程序的- 些初始化工作,并将应用程序对象的指针保存起来。
■进入WinMain函数。在AfxWinMain的数中可以获取子类(对Test程序来说,就是CTestApp类)的指针,利用此指针调用虚函数: InitInstance, 根据多态性原理,实际上调用的是子类(CTestApp) 的InitInstance函数。后者完成应用程序的一-些初始化工作,包括窗口类的注册、创建,窗口的显示和更新。期间会多次调用CreateEx函数,因为一一个单文档MFC应用程序有多个窗口,包括框架窗口、工具条、状态条等。
■进入消息循环。虽然也设置了默认的窗口过程函数,但是, MFC应用程序实际上是采用消息映射机制来处理各种消息的。当收到WM QUT消息时,退出消息循环,程序结束。

你可能感兴趣的:(MFC)