MFC初始化过程

原创 2004年07月17日 16:00:00

MFC应用程序不但具有一般的Win32程序的主要入口WinMain函数,还有一个CWinApp派生类的全局实例 theApp

Mfc程序(EXE)的程序运行过程如下:

首先是全局构造

CObject构造函数à CCmdTarget àCWinThreadàCWinAppà theApp构造函数

然后进入WinMain函数

WinMainàAfxWinMainàAfxWinInitàtheApp.InitApplicationàtheApp.InitInstance

接着执行线程过程。

theApp.Run()

最后清理

AfxWinTerm

在各种初始化函数中,反复调用了AfxGetAppAfxGetThread函数。在WinMain过程中,这两个函数实际上返回同一实例指针theApp。在其它线程中,AfxGetThread返回当前线程对象,这也就是为什么在MFC中新建线程不能使用CreateThreadbeginthread(ex),而要使用AfxBeginThread。后者会创建一个CWinThread的实例。

AfxGetAppAfxGetThread这两个全局函数是如何得知当前应用程序对象(theApp)和当前线程对象呢?在MFC中,有一个AFX_MODULE_STATE全局实例_afxBaseModuleState

(实际代码中_afxBaseModuleState_AFX_BASE_MODULE_STATE的实例,而_AFX_BASE_MODULE_STAT只是前者的一个包装,直接继承AFX_MODULE_STATE类,为了简化关系,这里把它们等同起来)。它以下划线开始,所以被认为是内部使用,不能直接操作。直接操作它的是函数AfxGetAppModuleState

AFX_MODULE_STATE的定义相当复杂,很多是为其它部件保留的与模块(EXE)相关状态参数(所以命名为MODULE_STATE)。下面只列出与初始化过程相关的部分:

   1|.  class AFX_MODULE_STATE : public CNoTrackObject

   2|.  {

   3|.  public:

   4|.  #ifdef _AFXDLL

   5|.       AFX_MODULE_STATE(BOOL bDLL, WNDPROC pfnAfxWndProc, DWORD dwVersion,

   6|.            BOOL bSystem = FALSE);

   7|.  #else<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

   8|.       explicit AFX_MODULE_STATE(BOOL bDLL);

   9|.  #endif

10|.       ~AFX_MODULE_STATE();

11|.   

12|.       CWinApp* m_pCurrentWinApp;

13|.       HINSTANCE m_hCurrentInstanceHandle;

14|.       HINSTANCE m_hCurrentResourceHandle;

15|.       LPCTSTR m_lpszCurrentAppName;

16|.       BYTE m_bDLL;    // TRUE if module is a DLL, FALSE if it is an EXE

17|.       BYTE m_bSystem; // TRUE if module is a "system" module, FALSE if not

18|.       BYTE m_bReserved[2]; // padding

19|.       // define thread local portions of module state

20|.       CThreadLocal<AFX_MODULE_THREAD_STATE> m_thread;

21|.  };

函数AfxGetApp返回的正是_afxBaseModuleStatm_pCurrentWinApp 成员。

_AFXDLL部分与MFC Regular Dll相关,暂不讨论。而AFX_MODULE_STATE秉承MFC的一贯原则,构造函数只保证了数据结构的有效性,而未对数据内容做出任何保证。因此,_ afxBaseModuleState构造后,其内容还是未知的。仅从成员可以知道,该类表示CWinApp所在模块(EXE)。而它的成员m_thread则表达了该模块中线程的状态(其实际类型为AFX_MODULE_THREAD_STATE)。该类的相关定义如下:

22|.  class AFX_MODULE_THREAD_STATE : public CNoTrackObject

23|.  {

24|.  public:

25|.       AFX_MODULE_THREAD_STATE();

26|.       virtual ~AFX_MODULE_THREAD_STATE();

27|.   

28|.       // current CWinThread pointer

29|.       CWinThread* m_pCurrentWinThread;

30|.   

31|.  };

AfxGetThread函数正是由_afxBaseModuleState取得取了AFX_MODULE_THREAD_STATE中的m_pCurrentThread成员。

下面是CCmdTarget,CWinThreadCWinApp构造函数中对以上成员变量初始化的过程。

CCmdTarget

CWinThread

32|.  CWinThread::CWinThread()

33|.  {

34|.      

35|.       CommonConstruct();

36|.  }

37|.   

38|.  void CWinThread::CommonConstruct()

39|.  {

40|.      

41|.       _AFX_THREAD_STATE* pState = AfxGetThreadState();

42|.       // initialize message pump

43|.  #ifdef _DEBUG

44|.       pState->m_nDisablePumpCount = 0;

45|.  #endif

46|.       pState->m_msgCur.message = WM_NULL;

47|.       pState->m_nMsgLast = WM_NULL;

48|.      

49|.  }

CWinApp

50|.  CWinApp::CWinApp(LPCTSTR lpszAppName)

51|.  {

52|.      

53|.       // initialize CWinThread state

54|.       AFX_MODULE_STATE* pModuleState = _AFX_CMDTARGET_GETSTATE();

55|.       AFX_MODULE_THREAD_STATE* pThreadState = pModuleState->m_thread;

56|.       ASSERT(AfxGetThread() == NULL);

57|.       pThreadState->m_pCurrentWinThread = this;

58|.       ASSERT(AfxGetThread() == this);

59|.       m_hThread = ::GetCurrentThread();

60|.       m_nThreadID = ::GetCurrentThreadId();

61|.   

62|.       // initialize CWinApp state

63|.       ASSERT(afxCurrentWinApp == NULL); // only one CWinApp object please

64|.       pModuleState->m_pCurrentWinApp = this;

65|.       ASSERT(AfxGetApp() == this);

66|.      

67|.  }

再看AfxWinInit函数

68|.  BOOL AFXAPI AfxWinInit(HINSTANCE hInstance, HINSTANCE hPrevInstance,

69|.       LPTSTR lpCmdLine, int nCmdShow)

70|.  {

71|.      

72|.       // set resource handles

73|.       AFX_MODULE_STATE* pModuleState = AfxGetModuleState();

74|.       pModuleState->m_hCurrentInstanceHandle = hInstance;

75|.       pModuleState->m_hCurrentResourceHandle = hInstance;

76|.   

77|.       // fill in the initial state for the application

78|.       CWinApp* pApp = AfxGetApp();

79|.       if (pApp != NULL)

80|.       {

81|.           // Windows specific initialization (not done if no CWinApp)

82|.            pApp->m_hInstance = hInstance;

83|.            hPrevInstance; // Obsolete.

84|.            pApp->m_lpCmdLine = lpCmdLine;

85|.            pApp->m_nCmdShow = nCmdShow;

86|.            pApp->SetCurrentHandles();

87|.       }

88|.   

89|.       // initialize thread specific data (for main thread)

90|.       if (!afxContextIsDLL)

91|.            AfxInitThread();

92|.   

93|.      

94|.   

95|.       return TRUE;

96|.  }

这里不得不说明一下AfxGetThreadState函数。它也是一个全局变量的包装函数,这个全局变量是_afxThreadState,它是_AFX_THREAD_STATE的实例,在单线程程序中这个实例的意义不大,但在多线程条件下,它可是连接AFX_MODULE_STATE和当前线程的一个桥梁。相关定义如下:

97|.  class _AFX_THREAD_STATE : public CNoTrackObject

98|.  {

99|.  public:

100|.       _AFX_THREAD_STATE();

101|.       virtual ~_AFX_THREAD_STATE();

102|.   

103|.       // override for m_pModuleState in _AFX_APP_STATE

104|.       AFX_MODULE_STATE* m_pModuleState;

105|.       AFX_MODULE_STATE* m_pPrevModuleState;

106|.  };

因为线程与模块的对应关系是多对一的,一个模块可以有多个线程,但一个线程只能有一个模块(不是其线程入口所在的模块,而是拥有它的模块)

其中m_pModuleState的初始化过程在CWinThread的线程入口过程中:

107|.  UINT APIENTRY _AfxThreadEntry(void* pParam)

108|.  {

109|.       _AFX_THREAD_STARTUP* pStartup = (_AFX_THREAD_STARTUP*)pParam;

110|.      

111|.       CWinThread* pThread = pStartup->pThread;

112|.       CWnd threadWnd;

113|.       TRY

114|.       {

115|.           // inherit parent's module state

116|.            _AFX_THREAD_STATE* pThreadState = AfxGetThreadState();

117|.            pThreadState->m_pModuleState = pStartup->pThreadState->m_pModuleState;

118|.       

119|.       }

120|.       

121|.  }

也就是说在不起动新线程的Mfc程序中,m_pModuleState不会被赋值。其默认值为0

AfxBeginThread引起的内存泄漏

AfxBeginThread引起的内存泄漏(ZZ) 下面的代码,当用AfxBeginThread开始一个线程时,实际上是有内存泄漏的 for  (ii  =   0 ; ii  { ...
  • cosmoslife
  • cosmoslife
  • 2013年03月23日 11:09
  • 765

深度解析MFC线程及机制

在VC中,启动一线程有3种方式:1.使用MFC中启动一个线程一般使用AfxBeginThread函数;2.使用API则使用CreateThread;3.就是使用_beginthread和_begint...
  • force_eagle
  • force_eagle
  • 2003年10月27日 02:06
  • 3530

AfxGetModuleState() 与 AfxGetModuleThreadState()

http://blog.pfan.cn/sword2008/29453.htmlhttp://blog.pfan.cn/sword2008/29453.html AfxGetModuleState()...
  • csw_100
  • csw_100
  • 2010年01月27日 11:24
  • 5224

AFX_MANAGE_STATE(AfxGetStaticModuleState())

         写MFC的DLL的时候,总会在自动生成的代码框架里看到提示,需要在每一个输出的函数开始添加上AFX_MANAGE_STATE (AfxGetStaticModuleState())。...
  • hejianhua
  • hejianhua
  • 2008年05月30日 11:32
  • 5970

appcore.cpp ASSERT(AfxGetThread() == NULL);错误

appcore.cpp文件在 ASSERT(AfxGetThread() == NULL);行出现错误 可能原因是工程中有超过一个eli...
  • liyun123gx
  • liyun123gx
  • 2014年04月16日 16:59
  • 1474

MFC动态库使用boost::thread运行时报错的问题

在MFC动态库中,如果包含有boost::thread的相关文件,可能会导致编译时没问题,运行时报错,报错位于ASSERT(AfxGetThread() == NULL)。百度得知,应该是静态链接bo...
  • comhaqs
  • comhaqs
  • 2016年12月26日 10:36
  • 787

要死的ASSERT(AfxGetThread() == NULL)问题--解决

大前天、前天、昨天、知道今天,要死的ASSERT(AfxGetThread() == NULL)问题终于得以解决,终于可以松口气了,赶快记录!!!         先说一下我的环境吧:V...
  • lixu0828
  • lixu0828
  • 2014年11月02日 11:37
  • 408

要死的ASSERT(AfxGetThread() == NULL)问题,终于得以解决

转自:http://china.ygw.blog.163.com/blog/static/687197462014776209635/       大前天、前天、昨天、知道今天,要死的ASSERT...
  • xuzzzhen123
  • xuzzzhen123
  • 2016年04月07日 08:39
  • 914

AfxGetThread和AfxGetApp的不同

 1 CWinThread* AFXAPI AfxGetThread() 2 { 3 // check for current thread in module thread state 4...
  • afxcontrolbars
  • afxcontrolbars
  • 2014年07月13日 16:10
  • 767

MFC 六大机制 (1) MFC程序的初始化

MFC六大机制之一(也成为MFC六大关键技术) MFC程序的初始化 本章将先介绍 MFC 的文档/视图结构,讲解实现该结构的数据结构,然后编写一个控制台应用程序来模拟 MFC 的初始化,理清 MFC ...
  • Raito__
  • Raito__
  • 2016年06月17日 15:14
  • 2908
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:MFC初始化过程
举报原因:
原因补充:

(最多只允许输入30个字)