MFC程序的来龙去脉

引言 :

  侯捷老师在他那本著名的"深入浅出MFC"(第二版)的第六章中对比着传统的Win32API编程,详细讲解了MFC应用程序“生死因果”,而且侯捷 老师还在"深入浅出MFC"(第二版)一书的“无责任书评”中称应用程序和MFC Framework的因果关系,是学习MFC程序设计的关键,并把它作为学习MFC程序设计的"第一个台阶".

正文 :

  初学MFC程序设计的人(甚至包括已经很精通Win32API编程的大虾们)都会感到很疑惑,对MFC应用程序的运行流程不能马上领悟,多数人都会提 出类似"WinMain函数跑到哪里去了?","窗口函数(WinProc),消息循环好像一下子都消失了?"等问题。下面就让我们看一个MFC SDI应用程序的运行流程并挖掘一下MFC库的源代码,来尽力争取弄清MFC应用程序“生死因果”的内幕。

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);

  其它版本的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就是由启动函数调用其构造函数构造出来的。CWinApp的构造函数到底作了什么?看看源代码吧,源代码最能说明问题了。

  注释:CWinApp的构造函数定义在../Visual Studio.NET/vc7/atlmfc/src/mfc/appcore.cpp

[cpp] view
plain
copy

  1. CWinApp::CWinApp(LPCTSTR lpszAppName)
  2. {
  3. if (lpszAppName != NULL)
  4. m_pszAppName = _tcsdup(lpszAppName);
  5. else
  6. m_pszAppName = NULL;
  7. // initialize CWinThread state
  8. AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();
  9. AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;
  10. ASSERT(AfxGetThread() == NULL);
  11. pThreadState->m_pCurrentWinThread = this;
  12. ASSERT(AfxGetThread() == this);
  13. m_hThread = ::GetCurrentThread();
  14. m_nThreadID = ::GetCurrentThreadId();
  15. // initialize CWinApp state
  16. ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please
  17. pModuleState->m_pCurrentWinApp = this;
  18. ASSERT(AfxGetApp() == this);
  19. // in non-running state until WinMain
  20. m_hInstance = NULL;
  21. m_hLangResourceDLL = NULL;
  22. m_pszHelpFilePath = NULL;
  23. m_pszProfileName = NULL;
  24. m_pszRegistryKey = NULL;
  25. m_pszExeName = NULL;
  26. m_pRecentFileList = NULL;
  27. m_pDocManager = NULL;
  28. m_atomApp = m_atomSystemTopic = NULL;
  29. m_lpCmdLine = NULL;
  30. m_pCmdInfo = NULL;
  31. // initialize wait cursor state
  32. ...//
  33. // initialize current printer state
  34. ...//
  35. // initialize DAO state
  36. m_lpfnDaoTerm = NULL;   // will be set if AfxDaoInit called
  37. // other initialization
  38. ...//
  39. }

  从源代码中可以看出CWinApp的构造函数主要收集了一些关于应用程序主线程的信息及初始化一些相关应用程序的信息。值得注意的是CWinApp类 的一些主要的数据成员如:m_hInstance,m_lpCmdLine,m_pCmdInfo及m_atomApp等都初始化为NULL,这些成员在 后面将被重新赋值。

4. WinMain函数登场了

  C/C++运行时库的启动函数int WinMainCRTStartup(void);所调用的WinMain函数---同时也是主线程的入口函数为:

  int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow);

  注释1:该函数定义在../Visual Studio.NET/vc7/atlmfc/src/mfc/appmodul.cpp中

  注释2:_t 是为了照顾Unicode版本而定义的宏。

  讲到这个时候你也许会稍稍展开你那紧皱的眉头,不过也许你还会问:"MFC中的WinMain函数到底作了什么?" 其实很简单,看看源代码就知道了

  C/C++运行时库的启动函数int WinMainCRTStartup(void);所调用的WinMain函数---同时也是主线程的入口函数为:

  int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow);

  注释1:该函数定义在../Visual Studio.NET/vc7/atlmfc/src/mfc/appmodul.cpp中

  注释2:_t 是为了照顾Unicode版本而定义的宏。

  讲到这个时候你也许会稍稍展开你那紧皱的眉头,不过也许你还会问:"MFC中的WinMain函数到底作了什么?" 其实很简单,看看源代码就知道了。

extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)

{

// call shared/exported WinMain

return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

}

  这一下清楚了,MFC中的WinMain函数其实什么也没做,只是调用了一个函数AfxWinMain。

5.MFC程序的入口点函数

  MFC作了一个"乾坤大挪移",将WinMain函数的全部责任转移交给了MFC程序的入口点函数---AfxWinMain。

  注释:该函数定义在../Visual Studio.NET/vc7/atlmfc/src/mfc/winmain.cpp中。

[cpp] view
plain
copy

  1. // Standard WinMain implementation
  2. // Can be replaced as long as ‘AfxWinInit‘ is called first
  3. int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  4. LPTSTR lpCmdLine, int nCmdShow)
  5. {
  6. ASSERT(hPrevInstance == NULL);
  7. int nReturnCode = -1;
  8. CWinThread* pThread = AfxGetThread();
  9. CWinApp* pApp = AfxGetApp();
  10. // AFX internal initialization
  11. if (!AfxWinInit(hInstance, hPrevInstance, lpCmdLine, nCmdShow))
  12. goto InitFailure;
  13. // App global initializations (rare)
  14. if (pApp != NULL && !pApp->InitApplication())
  15. goto InitFailure;
  16. // Perform specific initializations
  17. if (!pThread->InitInstance())
  18. {
  19. if (pThread->m_pMainWnd != NULL)
  20. {
  21. TRACE(traceAppMsg, 0, "Warning: Destroying non-NULL m_pMainWnd/n");
  22. pThread->m_pMainWnd->DestroyWindow();
  23. }
  24. nReturnCode = pThread->ExitInstance();
  25. goto InitFailure;
  26. }
  27. nReturnCode = pThread->Run();
  28. InitFailure:
  29. #ifdef _DEBUG
  30. // Check for missing AfxLockTempMap calls
  31. if (AfxGetModuleThreadState()->m_nTempMapLock != 0)
  32. {
  33. TRACE(traceAppMsg, 0, "Warning: Temp map lock count non-zero (%ld)./n",
  34. AfxGetModuleThreadState()->m_nTempMapLock);
  35. }
  36. AfxLockTempMaps();
  37. AfxUnlockTempMaps(-1);
  38. #endif
  39. AfxWinTerm();
  40. return nReturnCode;
  41. }

  从上面源代码可以看出AfxWinMain函数主要由四大模块组成,他们分别是AfxWinInit,InitApplication,InitInstance,Run。下面将分别介绍这四大模块的功能。

5.1 AFX的内部初始化

  AfxWinInit函数是既CWinApp类构造函数后的又一个重量级的函数。不妨看一下它的源代码:

  注释:该函数定义在../Visual Studio.NET/vc7/atlmfc/src/mfc/appinit.cpp中。

[c-sharp] view
plain
copy

  1. BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nCmdShow)
  2. {
  3. ASSERT(hPrevInstance == NULL);
  4. // handle critical errors and avoid Windows message boxes
  5. SetErrorMode(SetErrorMode(0) |
  6. SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
  7. // set resource handles
  8. AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
  9. pModuleState->m_hCurrentInstanceHandle = hInstance;
  10. pModuleState->m_hCurrentResourceHandle = hInstance;
  11. // fill in the initial state for the application
  12. CWinApp* pApp = AfxGetApp();
  13. if (pApp != NULL)
  14. {
  15. // Windows specific initialization (not done if no CWinApp)
  16. pApp->m_hInstance = hInstance;
  17. hPrevInstance; // Obsolete.
  18. pApp->m_lpCmdLine = lpCmdLine;
  19. pApp->m_nCmdShow = nCmdShow;
  20. pApp->SetCurrentHandles();
  21. }
  22. // initialize thread specific data (for main thread)
  23. if (!afxContextIsDLL)
  24. AfxInitThread();
  25. // Initialize CWnd::m_pfnNotifyWinEvent
  26. HMODULE hModule = ::GetModuleHandle(_T("user32.dll"));
  27. if (hModule != NULL)
  28. {
  29. CWnd::m_pfnNotifyWinEvent = (CWnd::PFNNOTIFYWINEVENT)::GetProcAddress(hModule, "NotifyWinEvent");
  30. }
  31. return TRUE;
  32. }

  还记得我在第三个标题---侯捷老师所说的"引爆器"处 的话么,"CWinApp类的一些主要的数据成员在后面将被重新赋值。",AfxWinInit函数就是这些数据成员被赋值的地方,它重新初始化这些在整 个程中都扮演重要角色的成员,并且调用AfxInitThread()为主线程作了一些初始化工作,这些都为以后MFC框架的正常运作铺平了道路。

5.2 应用程序的全局初始化

  InitApplication函数(virtual)为程序进行全局初始化:

  注释1:该函数定义在../Visual Studio.NET/vc7/atlmfc/src/mfc/appcore.cpp中。

  由于初次调用时 CDocManager::pStaticDocManager==0x00000000;m_pDocManager==0x00000000;所以 InitApplication函数只是调用了CWinApp::LoadSysPolicies();而后者将加载一些注册表的信息用来初始化一些程序 定义的结构并为程序注册一些基本信息。(由于该函数可能尚未文档化,所以关于LoadSysPolicies函数的说明只是看了源代码后的推测,下面列出 了它的部分源代码仅供参考)

  注释2:该函数定义在../Visual Studio.NET/vc7/atlmfc/src/mfc/appcore.cpp中。

[cpp] view
plain
copy

  1. BOOL CWinApp::LoadSysPolicies()
  2. {
  3. HKEY hkPolicy = NULL;
  4. DWORD dwValue = 0;
  5. DWORD dwDataLen = sizeof(dwValue);
  6. DWORD dwType = 0;
  7. // clear current policy settings.
  8. m_dwPolicies = _AFX_SYSPOLICY_NOTINITIALIZED;
  9. static _AfxSysPolicyData rgExplorerData[] =
  10. {
  11. {_T("NoRun"), _AFX_SYSPOLICY_NORUN},
  12. {_T("NoDrives"), _AFX_SYSPOLICY_NODRIVES},
  13. {_T("RestrictRun"), _AFX_SYSPOLICY_RESTRICTRUN},
  14. {_T("NoNetConnectDisconnect"), _AFX_SYSPOLICY_NONETCONNECTDISCONNECTD},
  15. {_T("NoRecentDocsHistory"), _AFX_SYSPOLICY_NORECENTDOCHISTORY},
  16. {_T("NoClose"), _AFX_SYSPOLICY_NOCLOSE},
  17. {NULL, NULL}
  18. };
  19. ...//
  20. static _AfxSysPolicyData rgComDlgData[] =
  21. {
  22. {_T("NoPlacesBar"), _AFX_SYSPOLICY_NOPLACESBAR},
  23. {_T("NoBackButton"), _AFX_SYSPOLICY_NOBACKBUTTON},
  24. {_T("NoFileMru"), _AFX_SYSPOLICY_NOFILEMRU},
  25. {NULL, NULL}
  26. };
  27. static _AfxSysPolicies rgPolicies[] =
  28. {
  29. {_T("Software//Microsoft//Windows//CurrentVersion//Policies//Explorer"),
  30. rgExplorerData},
  31. {_T("Software//Microsoft//Windows//CurrentVersion//Policies//Network"),
  32. rgNetworkData},
  33. {_T("Software//Microsoft//Windows//CurrentVersion//Policies//Comdlg32"),
  34. rgComDlgData},
  35. {NULL, NULL}
  36. };
  37. _AfxSysPolicies *pPolicies = rgPolicies;
  38. _AfxSysPolicyData *pData = NULL;
  39. ...//
  40. }

  注释3:在MFC文档中有这么一句话"The CWinApp::InitApplication member function is obsolete in MFC.",所以你大多情况下不用在意这个virtual函数。

5.3 应用程序的标准实例化

  CWinApp::InitInstance()是一个虚函数,大多数应用程序都要override这个函数。让我们看看应用程序向导MFC AppWizard(.exe)为SDI 程序作出的override后的代码吧!

BOOL CMyWinApp::InitInstance()

{

// 如果一个运行在 Windows XP 上的应用程序清单指定要

// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,

//则需要 InitCommonControls()。否则,将无法创建窗口。

InitCommonControls();

CWinApp::InitInstance();//显式调用基类的InitInstance()

// 初始化 OLE 库

if (!AfxOleInit())

{

AfxMessageBox(IDP_OLE_INIT_FAILED);

return FALSE;

}

AfxEnableControlContainer();

// 标准初始化

SetRegistryKey(_T("应用程序向导生成的本地应用程序"));

LoadStdProfileSettings(4); // 加载标准 INI 文件选项(包括 MRU)

// 注册应用程序的文档模板。

// 文档模板将用作文档、框架窗口和视图之间的连接

CSingleDocTemplate* pDocTemplate;

pDocTemplate = new CSingleDocTemplate(

IDR_MAINFRAME,

RUNTIME_CLASS(CTestDoc),

RUNTIME_CLASS(CMainFrame),       // 主 SDI 框架窗口

RUNTIME_CLASS(CTestView));

pDocTemplate->SetContainerInfo(IDR_CNTR_INPLACE);

AddDocTemplate(pDocTemplate);

// 分析标准外壳命令、DDE、打开文件操作的命令行

CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo);

if (!ProcessShellCommand(cmdInfo))

return FALSE;

// 唯一的一个窗口已初始化,因此显示它并对其进行更新

m_pMainWnd->ShowWindow(SW_HIDE);

m_pMainWnd->UpdateWindow();

return TRUE;

}

  CMyWinApp::InitInstance()先显式调用了基类的InitInstance();

  我们先看看这个基类的函数的定义吧!

  注释1:该函数定义在../Visual Studio.NET/vc7/atlmfc/src/mfc/appcore.cpp中。

[cpp] view
plain
copy

  1. BOOL CWinApp::InitInstance()
  2. {
  3. InitLibId();
  4. m_hLangResourceDLL = LoadAppLangResourceDLL();
  5. if(m_hLangResourceDLL != NULL)
  6. {
  7. AfxSetResourceHandle(m_hLangResourceDLL);
  8. _AtlBaseModule.SetResourceInstance(m_hLangResourceDLL);
  9. }
  10. return TRUE;
  11. }

  注释2:vc.net中的CWinApp::InitInstance()已与vc6.0中的CWinApp::InitInstance()有所区别。

  基类的InitInstance()先调用InitLibId()函数用于Initializes the data member containing the GUID of the current module;不过该函数现在为空,估计以后微软会填充该函数。

  之后调用LoadAppLangResourceDLL()函数加载应用程序所需资源;在vc6.0中的CWinApp::InitInstance()函数只有一条语句:即return TRUE;

  CMyWinApp::InitInstance()在其基类的帮助后,开始执行它自己的一系列代码来完成诸如"初始化 OLE 库","设置注册表主键以使程序能保存信息到注册表中","分析标准外壳命令","生成程序主框架,文档和视图结构","显示程序主窗口"等工作。

  注释3:有关应用程序是如何在CMyWinApp::InitInstance()完成上面一系列工作的,将在本系列文章之二的“MFC文档视图结构内幕”一文中详述。

  注释4:在MSDN中有关InitInstance的叙述如下:"Windows allows several copies of the same program to run at the same time."

5.4 "消息泵"启动了

  众所周知,Windows是一个以消息为基础,以事件驱动的操作系统,每一个Win32程序也都是如此。那么

MFC应用程序是如何实现消息机制的呢?MFC应用程序框架将这种消息机制包装到了一个"消息泵"中,而这个"消息泵"在CMyWinApp::InitInstance()中被启动了。其源代码如下:

  注释1:该函数定义在../Visual Studio.NET/vc7/atlmfc/src/mfc/appcore.cpp中。

[cpp] view
plain
copy

  1. // Main running routine until application exits
  2. int CWinApp::Run()
  3. {
  4. if (m_pMainWnd == NULL && AfxOleGetUserCtrl())
  5. {
  6. // Not launched /Embedding or /Automation, but has no main window!
  7. TRACE(traceAppMsg, 0, "Warning: m_pMainWnd is NULL in CWinApp::Run - quitting                        application./n");
  8. AfxPostQuitMessage(0);
  9. }
  10. return CWinThread::Run();
  11. }

  由上面的源代码看出:CWinApp::Run()调用了其基类的Run()函数,继续看源代码:

[cpp] view
plain
copy

  1. int CWinThread::Run()
  2. {
  3. ASSERT_VALID(this);
  4. _AFX_THREAD_STATE* pState = AfxGetThreadState();
  5. // for tracking the idle time state
  6. BOOL bIdle = TRUE;
  7. LONG lIdleCount = 0;
  8. // acquire and dispatch messages until a WM_QUIT message is received.
  9. for (;;)
  10. {
  11. // phase1: check to see if we can do idle work
  12. while (bIdle &&
  13. !::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE))
  14. {
  15. // call OnIdle while in bIdle state
  16. if (!OnIdle(lIdleCount++))
  17. bIdle = FALSE; // assume "no idle" state
  18. }
  19. // phase2: pump messages while available
  20. do
  21. {
  22. // pump message, but quit on WM_QUIT
  23. if (!PumpMessage())
  24. return ExitInstance();
  25. // reset "no idle" state after pumping "normal" message
  26. //if (IsIdleMessage(&m_msgCur))
  27. if (IsIdleMessage(&(pState->m_msgCur)))
  28. {
  29. bIdle = TRUE;
  30. lIdleCount = 0;
  31. }
  32. } while (::PeekMessage(&(pState->m_msgCur), NULL, NULL, NULL, PM_NOREMOVE));
  33. }
  34. }
  35. //CWinThread implementation helpers
  36. BOOL CWinThread::PumpMessage()
  37. {
  38. return AfxInternalPumpMessage();
  39. }
  40. BOOL AFXAPI AfxInternalPumpMessage()//部分源码
  41. {
  42. _AFX_THREAD_STATE *pState = AfxGetThreadState();
  43. if (!::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))
  44. {
  45. ...//
  46. return FALSE;
  47. }
  48. ...//
  49. // process this message
  50. if (pState->m_msgCur.message != WM_KICKIDLE &&                               !AfxPreTranslateMessage(&(pState->m_msgCur)))
  51. {
  52. ::TranslateMessage(&(pState->m_msgCur));
  53. ::DispatchMessage(&(pState->m_msgCur));
  54. }
  55. return TRUE;
  56. }

  终于出现了::TranslateMessage和::DispatchMessage,熟悉Win32API编程的人一定会眼睛一亮,终于挖出源头了。

6. 收尾工作

  MFC应用程序的主要流程几乎都已被挖掘完了,下面看一下收尾工作是如何进行的。

  当应用程序发现消息队列中出现了WM_QUIT消息时, nReturnCode = pThread->Run();CWinApp::Run()返回,并设置返回值。下面将执行AfxWinTerm函数。其源代码如下:

  注释1:该函数定义在../Visual Studio.NET/vc7/atlmfc/src/mfc/appterm.cpp中。

[cpp] view
plain
copy

  1. // Standard cleanup called by WinMain and AfxAbort
  2. void AFXAPI AfxWinTerm(void)
  3. {
  4. // unregister Window classes
  5. AFX_MODULE_STATE* pModuleState = AfxGetModuleState();
  6. AfxLockGlobals(CRIT_REGCLASSLIST);
  7. LPTSTR lpsz = pModuleState->m_szUnregisterList;
  8. while (*lpsz != 0)
  9. {
  10. LPTSTR lpszEnd = _tcschr(lpsz, ‘/n‘);
  11. ASSERT(lpszEnd != NULL);
  12. *lpszEnd = 0;
  13. UnregisterClass(lpsz, AfxGetInstanceHandle());
  14. lpsz = lpszEnd + 1;
  15. }
  16. pModuleState->m_szUnregisterList[0] = 0;
  17. AfxUnlockGlobals(CRIT_REGCLASSLIST);
  18. // cleanup OLE if required
  19. CWinThread* pThread = AfxGetApp();
  20. if (pThread != NULL && pThread->m_lpfnOleTermOrFreeLib != NULL)
  21. (*pThread->m_lpfnOleTermOrFreeLib)(TRUE, FALSE);
  22. // cleanup thread local tooltip window
  23. AFX_MODULE_THREAD_STATE* pModuleThreadState = AfxGetModuleThreadState();
  24. if (pModuleThreadState->m_pToolTip != NULL)
  25. {
  26. if (pModuleThreadState->m_pToolTip->DestroyToolTipCtrl())
  27. pModuleThreadState->m_pToolTip = NULL;
  28. }
  29. _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();
  30. if (!afxContextIsDLL)
  31. {
  32. // unhook windows hooks
  33. if (pThreadState->m_hHookOldMsgFilter != NULL)
  34. {
  35. ::UnhookWindowsHookEx(pThreadState->m_hHookOldMsgFilter);
  36. pThreadState->m_hHookOldMsgFilter = NULL;
  37. }
  38. if (pThreadState->m_hHookOldCbtFilter != NULL)
  39. {
  40. ::UnhookWindowsHookEx(pThreadState->m_hHookOldCbtFilter);
  41. pThreadState->m_hHookOldCbtFilter = NULL;
  42. }
  43. }
  44. }

  由源代码可以看出:该函数主要作一些清除工作,将该释放的东西释放,比如卸载钩子等。

  等到AfxWinTerm函数结束,AfxWinMain函数返回nReturnCode值,且该值也将作为_WinMain函数的返回值返回。

  让我们回过头来再看一看C/C++运行时库的启动函数的源代码:

  注释2:函数定义在../Visual Studio.NET/vc7/crt/src/crtexe.c中

[cpp] view
plain
copy

  1. int WinMainCRTStartup(void)//部分源代码
  2. {
  3. int argc;   /* three standard arguments to main */
  4. _TSCHAR **argv;
  5. _TSCHAR **envp;
  6. int argret;
  7. int mainret;
  8. int managedapp;
  9. #ifdef _WINMAIN_
  10. _TUCHAR *lpszCommandLine;
  11. STARTUPINFO StartupInfo;
  12. #endif /* _WINMAIN_ */
  13. _startupinfo    startinfo;
  14. /*
  15. * Determine if this is a managed application
  16. */
  17. managedapp = check_managed_app();
  18. ...//
  19. StartupInfo.dwFlags = 0;
  20. GetStartupInfo( &StartupInfo );
  21. #ifdef WPRFLAG
  22. mainret = wWinMain(
  23. #else /* WPRFLAG */
  24. mainret = WinMain(
  25. #endif /* WPRFLAG */
  26. GetModuleHandleA(NULL),
  27. NULL,
  28. lpszCommandLine,
  29. StartupInfo.dwFlags & STARTF_USESHOWWINDOW
  30. ? StartupInfo.wShowWindow
  31. : SW_SHOWDEFAULT);
  32. ...//
  33. if ( !managedapp )
  34. exit(mainret);
  35. ...//
  36. return mainret;
  37. }

  WinMain函数将返回值传给mainret,WinMainCRTStartup调用C运行时函数exit(int status);后者做什么了呢?看看微软自己的文档重视如何说的:

  "The exit functions terminate the calling process. exit calls, in last-in-first-out (LIFO) order, the functions registered by atexit and _onexit, then flushes all file buffers before terminating the process.The status value is typically set to 0 to indicate
a normal exit and set to some other value to indicate an error."

  事实上,exit函数除了做以上工作外,还为所有全局的和静态的C++类对象调用析构函数(如~CMyWinApp),将返回值传递给Windows操作系统的ExitProcess函数,使得操作系统可以撤销该进程并设置它的exit代码。

7. 结束了

  经过这么大篇幅的挖掘,一个MFC应用程序从生到死的流程我们都已目睹完了,相信你一定有所收获

时间: 2024-08-03 10:26:39

MFC程序的来龙去脉的相关文章

【笔记】《深入浅出MFC》第6章 MFC程序的生死因果

一.头文件说明 STDAFX.H 这个文件用来作为Precompile header file,其内只是载入其他的MFC头文件.应用程序通常会准备自己的头STDAFX.H. AFXWIN.H 每一个Windows MFC程序都必须载入它,因为它以及它所载入的文件声明了所有的MFC类. 在WINDEF.H中有CALLBACK的定义 #define CALLBACK _stdcall //是一种函数调用习惯 在AFXWIN.H中有afx_msg的定义 #define afx_msg   //故意安排

VS 2008 创建MFC程序对话框的步骤

用过不少编程语言,可是刚开始学的时候最容易忘记一些简单的流程或者生疏了.那么这里就说说VS 2008 创建MFC程序对话框的步骤.我主要是android开发方面的.平时使用jni调用不少c++代码.所以就用到了调试c++代码的MFC啦. 1.文件--新建项目 2.选择对话框,然后就可以拖控件进行监听 3.起始对话框的类名 4.项目新建后,依次双击箭头指向就可看到可视化界面. 5.可视化对话框 这里就可以增加button,输入框以及监听事件,还有你的逻辑代码进行测试.

MFC程序执行顺序

原文链接:http://www.cnblogs.com/lidabo/archive/2012/10/23/2735622.html 1.创建Application object对象theApp 程序一开始生产一个(且只有一个)Application object对象theApp,也即一个CWinApp对象,这个全局对象一产生,便执行其构造函数,因为并没有定义CMyWinApp构造函数,所以即执行CWinApp类的构造函数.该函数定义于APPCORE.CPP第75行,你可以自己搜出来啃一啃,因此

如何看MFC程序

一直以来  我都一个疑惑 如果看懂别人的MFC 程序. 今日忽然略有小悟. Q:MFC是啥? A:MFC是类库.. ************* Q :MFC 啥玩意类库? A;MFC 是封装API的类库 ×××××××× Q:MFC的导火索是啥? A:TheAPP ××××××××××××××××××××××× 以上是背景信息. 所以看懂程序第一步: 熟悉MFC类的架构  MFC家族的七大姑八大姨 要门清,谁是谁的儿子  ? 谁的谁的孙子? 谁是谁的远方表哥?这都要清楚. MFC就像一个大家庭,

MFC程序实现给对话框加入?背景图片

1.插入一个Bitmap的资源图片,如果资源名称为:IDC_BITMAP1 2.在CXXXDialog::OnPaint()中实现: void CMyDialogDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cx

将屏幕保存为图片 将当前MFC程序保存为图片 c++ vc

将屏幕保存为图片,使用vs2008编译通过. [cpp] view plaincopy #include "stdafx.h" #include <windows.h> #include <atlimage.h> int __stdcall WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { HWND hwnd = ::GetDesktop

VS2008运行MFC程序,提示microsoft incremental linker已停止工作解决方法

其实这边是因为设置有问题,具体的解决方案如下: 第一步:点击项目->"你的文件"属性->配置属性->链接器->启用增量链接   将  是(/INCREMENTAL)改为 否(/INCREMENTAL:NO) 第二步:点击项目->"你的文件"属性->配置属性->C/C++  将调试信息格式改为程序数据库(/Zi) 改完之后,重新调试一下程序,是不是问题已经解决了? 以下附上截图: VS2008运行MFC程序,提示microso

MFC程序的消息处理顺序

MFC应用程序中处理消息的顺序 1.AfxWndProc()      该函数负责接收消息,找到消息所属的CWnd对象,然后调用AfxCallWndProc 2.AfxCallWndProc()  该函数负责保存消息(保存的内容主要是消息标识符和消息参数)供应用程序以后使用,然后调用WindowProc()函数 3.WindowProc()      该函数负责发送消息到OnWndMsg()函数,如果未被处理,则调用DefWindowProc()函数 4.OnWndMsg()        该函

MFC程序逆向 – 消息篇(下)

上篇啰里啰嗦地说了一大堆,其实所说的消息都是PostMessage方式的.MFC中还有另外一种很常见的消息发送方式,就是SendMessage函数.这个消息起始路径和上篇所讲的完全不一样.这种方式下,前面的7个站点均不执行,而是直接进入第8站点:User32内核,从第8站点出来后,这两种消息方式走上了同一条道路,进入第9个站点或第10个站点了,真是殊道同归.对于MFC窗口程序,所有窗口都使用同一窗口过程 : AfxWndProcBase(第9个站点)或AfxWndProc(第10个站点).如果程