摘要:本文章主要以MFC程序的执行流程、执行顺序等执行过程的剖析做出的结论,下面一起来看看原文的具体介绍。
一、MFC介绍
微软基础类库(英语:Microsoft Foundation Classes,简称MFC)是微软公司提供的一个类库(class libraries),以C++类的形式封装了Windows API,并且包含一个应用程序框架,以减少应用程序开发人员的工作量。其中包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装类。
二、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只是对WIN32的API进行了封装,所以MFC的本质还是WIN32程序。有了这层封装,我们看不到WIN32的WinMain函数,也就不清楚MFC程序的启动过程。虽然我们没有看到WinMain函数,但不代表没有WinMain函数,这个函数位于*\VC\atlmfc\src\mfc目录的appmodul .cpp文件中有一个_tWinMain函数, _tWinMain函数调用了WinMain.CPP文件中的AfxWinMain函数。
tWinMain函数实现:
extern “C” int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
__in LPTSTR lpCmdLine, int nCmdShow)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}1234567
AfxWinMain函数实现:
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))
// 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;
}123456789101112131415161718192021222324252627282930313233343536373839404142434445
_tWinMain和WinMain的声明是一致的,但是_tWinMain不是最先执行的,因为整个程序一开始是初始化全局变量,这里的全局变量有WinApp类型的theApp,初始化theApp就是执行CWinApp的构造函数。在这个AfxWinMain函数里面调用了pThread-》InitInstance()函数,InitInstance函数是CWinApp类(CWinApp继承于CWinThread)的虚函数,所以这里就调用派生类的InitInstance函数,用户一般在这个函数里面创建对话框,单文档,多文档界面。执行完InitInstance函数后,就会执行CWinApp类的run函数(*\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));
}
}123456789101112131415161718192021222324252627282930313233343536373839
小结
MFC程序的执行顺序和Win32的执行顺序完全一样:初始化全局变量(theApp),执行WinMain函数(AfxWinMain),创建及注册窗口(在InitInstance函数中创建对话框,单文档,多文档窗口),消息循环(Run函数)
评论
查看更多