/* 1. Windows 帮忙 */
/* 程序诞生! */
//
Windows 操作系统为应用程序创建进程核心对象,并为该应用程序分配4GB的进程地址空间,系统加载器
将应用程序可执行文件映像以及一些必要的代码(包括数据和一些应用程序使用的dlls)加载到应用程序的进程地址空间中。
/
/* 2.启动函数是什么? */
/
Windows 操作系统在初始化该应用程序进程的同时,将自动为该应用程序创建一个主线程,该主线程与
C/C++运行时库的启动函数一道开始运行。很多初学者并不知道C/C++运行时库的启动函数是何方神圣,这里我
简单介绍一下:当你的应用程序编译后开始链接时,系统的链接器会根据你的应用程序的设置为你的应用程序
选择一个C/C++运行时库的启动函数(注释:这些函数声明在../Visual Studio.NET/vc7/crt/src/crt0.c中)
一般的ANSI版本的GUI的应用程序的C/C++运行时库的启动函数为:
int WinMainCRTStartup(void);
注释:函数定义在../Visual Studio.NET/vc7/crt/src/crtexe.c中
其它版本的C/C++运行时库的启动函数如下:
ANSI版本的CUI的应用程序: int mainCRTStartup(void);
Unicode版本的CUI的应用程序: int wmainCRTStartup(void);
Unicode版本的GUI的应用程序: int wWinMainCRTStartup(void);
C/C++运行时库的启动函数的主要功能为初始化C/C++运行时库和为所有全局和静态的C++类对象调用构造函数
/
/* 3.侯捷老师所说的"引爆器" */
/
前面所说的C/C++运行时库的启动函数的主要功能之一是为所有全局和静态的C++类对象调用构造函数。侯捷老师所说的"引爆器"---CMyWinApp theApp这个Application Object就是由启动函数调用其构造函数构造出来的。
//
/* 4. WinMain函数登场了 */
//
C/C++运行时库的启动函数int WinMainCRTStartup(void);所调用的WinMain函数---同时也是主线程的入口函数为:
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
{
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
注释1:该函数定义在../Visual Studio.NET/vc7/atlmfc/src/mfc/appmodul.cpp中
注释2:_t 是为了照顾Unicode版本而定义的宏。
/
/* 5.MFC程序的入口点函数 */
//
MFC作了一个"乾坤大挪移",将WinMain函数的全部责任转移交给了MFC程序的入口点函数---AfxWinMain。
注释:该函数定义在../Visual Studio.NET/vc7/atlmfc/src/mfc/winmain.cpp中。
AfxWinMain函数主要由四大模块组成,他们分别是AfxWinInit,InitApplication,InitInstance,Run。
下面将分别介绍这四大模块的功能。
///
/* 5.1 AFX的内部初始化 */
///
还记得我在第三个标题---侯捷老师所说的"引爆器"处 的话么,"CWinApp类的一些主要的数据成员在后面将被重新赋值。",AfxWinInit函数就是这些数据成员被赋值的地方,它重新初始化这些在整个程中都扮演重要角色的成员,并且调用AfxInitThread()为主线程作了一些初始化工作,这些都为以后MFC框架的正常运作铺平了道路。
/
/* 5.2 应用程序的全局初始化 */
/
InitApplication函数(virtual)为程序进行全局初始化:
注释1:该函数定义在../Visual Studio.NET/vc7/atlmfc/src/mfc/appcore.cpp中。
InitApplication函数只是调用了CWinApp::LoadSysPolicies();而后者将加载一些注册表的信息用来初始化一些程序定义的结构并为程序注册一些基本信息。
注释2:在MFC文档中有这么一句话"The CWinApp::InitApplication member function is obsolete in MFC.",所以你大多情况下不用在意这个virtual函数。
/
/* 5.3 应用程序的标准实例化 */
//
CWinApp::InitInstance()是一个虚函数,大多数应用程序都要override这个函数。
CMyWinApp::InitInstance()先显式调用了基类的InitInstance();
CMyWinApp::InitInstance()在其基类的帮助后,开始执行它自己的一系列代码来完成诸如"初始化 OLE 库","设置注册表主键以使程序能保存信息到注册表中","分析标准外壳命令","生成程序主框架,文档和视图结构","显示程序主窗口"等工作。
/* 5.4 "消息泵"启动了 */
众所周知,Windows是一个以消息为基础,以事件驱动的操作系统,每一个Win32程序也都是如此。那么
MFC应用程序是如何实现消息机制的呢?MFC应用程序框架将这种消息机制包装到了一个"消息泵"中,而这个"消息泵"在CMyWinApp::Run()中被启动了。
- int CWinThread::Run()
- {
- ...
- // 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));
- }
- }
- //CWinThread implementation helpers
- BOOL CWinThread::PumpMessage()
- {
- return AfxInternalPumpMessage();
- }
- BOOL AFXAPI AfxInternalPumpMessage()//部分源码
- {
- _AFX_THREAD_STATE *pState = AfxGetThreadState();
- if (!::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))
- {
- ...//
- return FALSE;
- }
- ...//
- // process this message
- if (pState->m_msgCur.message != WM_KICKIDLE && !AfxPreTranslateMessage(&(pState->m_msgCur)))
- {
- ::TranslateMessage(&(pState->m_msgCur));
- ::DispatchMessage(&(pState->m_msgCur));
- }
- return TRUE;
- }
终于出现了::TranslateMessage和::DispatchMessage,熟悉Win32API编程的人一定会眼睛一亮,终于挖出源头了。
/
/* 6. 收尾工作 */
MFC应用程序的主要流程几乎都已被挖掘完了,下面看一下收尾工作是如何进行的。
当应用程序发现消息队列中出现了WM_QUIT消息时, nReturnCode = pThread->Run();CWinApp::Run()返回,并设置返回值。下面将执行AfxWinTerm函数。
该函数主要作一些清除工作,将该释放的东西释放,比如卸载钩子等。
等到AfxWinTerm函数结束,AfxWinMain函数返回nReturnCode值,且该值也将作为_WinMain函数的返回值返回。
摘自