现在的位置: 首页 > 综合 > 正文

MFC的模块状态:从AfxGetApp()和AFX_MANAGE_STATE()看MFC的模块状态

2013年10月12日 ⁄ 综合 ⁄ 共 8946字 ⁄ 字号 评论关闭

1.



Introduction



当我们在用
MFC
编程的时候,我们经常用到
AfxGetApp()
来获得当前的
CWinApp

Instance
。看看
MFC
的源代码中
AfxGetApp()
的实现,你会发现
AfxGetApp()
的实现并不像一般情况下面那样直接:

_AFXWIN_INLINE CWinApp*
AFXAPI AfxGetApp()

      
{ return afxCurrentWinApp; }

#define afxCurrentWinApp   
AfxGetModuleState()->m_pCurrentWinApp

AfxGetApp()
调用的是
AfxGetModuleState()
,该函数返回一个
AFX_MODULE_STATE
的指针,其中的一个成员保存着当前的
CWinApp
的指针。可
AfxGetModuleState()
的作用又是什么呢?

 

此外,当我们在开发
MFC
DLL

程序的时候,我们会在每个输出的
DLL
函数前面加上一句
AFX_MANAGE_STATE

void
SomeMFCDllFunction()

{

AFX_MANAGE_STATE(AfxGetStaticModuleState())

 

AFX_MANAGE_STATE
又是起什么作用呢?从字面上看来,它是
Manage
某种
State
,而
AfxGetStaticModuleState
又是获得
State
的,那么
State
究竟是什么呢?


MFC
中,
States
用来保存某种相关的状态信息,分为下面几类:

1.    


Process State
,和某个单独的进程绑定起来

2.    


Thread State

和某个单独的线程绑定

3.    


Module State


Module
相关

前两种
State
和一般的全局变量十分类似,只是根据需求的不同被绑定于不同的进程
/
线程,如多线程支持
等。而

Module State
本身比较特别,
Module State
根据情况的不同,可以是全局,线程,或者进程相关的
State
,并且可以根
据要求快速切换。

2.
     


Process State



常见的
Process
State

有:

1.    


_AFX_WIN_STATE

2.    


_AFX_DB_STATE

3.    


_AFX_DEBUG_STATE

4.    


_AFX_SOCK_STATE

5.    


……

从字面上面可以很容易猜出这些状态的用处。

MFC
通过下面的宏来定义
Process State:

#define
PROCESS_LOCAL(class_name, ident_name) /

      
AFX_COMDAT
CProcessLocal<class_name> ident_name;

#define
EXTERN_PROCESS_LOCAL(class_name, ident_name) /

      
extern
CProcessLocal<class_name> ident_name;

PROCESS_LOCAL

CProcessLocal
模板类定义了一个
CProcessLocal<class_name>
的一个实例作为状态变量,而
EXTERN_PROCESS_LOCAL
则使在头文件中声明此状态变量。
CProcessLocal
的定义如下:

class
AFX_NOVTABLE CProcessLocalObject

{

public:

// Attributes

      
CNoTrackObject*
GetData(CNoTrackObject* (AFXAPI* pfnCreateObject)());

 

// Implementation

      
CNoTrackObject*
volatile m_pObject;

      
~CProcessLocalObject();

};

 

template<class TYPE>

class CProcessLocal :
public CProcessLocalObject

{

// Attributes

public:

      
AFX_INLINE
TYPE* GetData()

      
{

             

TYPE* pData =
(TYPE*)CProcessLocalObject::GetData(&CreateObject);

             

ENSURE(pData != NULL);

             
return
pData;

      
}

      
AFX_INLINE
TYPE* GetDataNA()

             
{ return
(TYPE*)m_pObject; }

      
AFX_INLINE
operator TYPE*()

             
{ return GetData(); }

      
AFX_INLINE
TYPE* operator->()

             
{ return
GetData(); }

 

// Implementation

public:

      
static
CNoTrackObject* AFXAPI CreateObject()

             

{ return new TYPE; }

};

 

CProcessLocal
的作用只是一个
Wrapper

Hold
一个
TYPE*
的指针,一旦用户调用
GetData
来获得这个指针,
GetData
会首先判断该指针是否为空,如果为空,则创建一个新的实例保存起来,否
则返回已有的指针。前提条件是,

TYPE
必须从
CNoTrackObject
继承。任何从
CNoTrackObject
继承的类都拥有自己的
new/delete
,这样此对象便不会被
Debug
的内存分配系统所跟踪而误判为
Leak

CNoTrackObject*
CProcessLocalObject::GetData(

      
CNoTrackObject*
(AFXAPI* pfnCreateObject)())

{

      
if (m_pObject ==
NULL)

      
{

             

AfxLockGlobals(CRIT_PROCESSLOCAL);

             

TRY

             
{

                    

if (m_pObject == NULL)

                          
m_pObject
= (*pfnCreateObject)();

             
}

             

CATCH_ALL(e)

             
{

                    

AfxUnlockGlobals(CRIT_PROCESSLOCAL);

                    

THROW_LAST();

             
}

             

END_CATCH_ALL

             
AfxUnlockGlobals(CRIT_PROCESSLOCAL);

      
}

      
return
m_pObject;

}

 

3.
     


Thread State




Process
State

类似,
Thread State

某个线程绑定起来,

Thread State
有:

1.    


_AFX_THREAD_STATE

2.    


_AFXCTL_AMBIENT_CACHE

同样的,
Thread State


THREAD_LOCAL

EXTERN_THREAD_LOCAL
定义,也有
CThreadLocal

CThreadLocalObject

Hold

Thread
State

的指针。
CThreadLocal

CProcessLocal
的实现方式不太一样,
CThreadLocal
利用
TLS(Thread
Local Storage)

来保存指针,
而不是用成员变量。简单来说,

Thread Local Storage

Windows
支持的功能,可以在任意线程中保存多个
DWORD
数据,每个这样

DWORD
数据所占的位置称之为
Slot
,分配数据需要分配一个
Slot
,获得和修改数据
CThreadLocalObject::GetData
的实现如下:

CNoTrackObject*
CThreadLocalObject::GetData(

      
CNoTrackObject*
(AFXAPI* pfnCreateObject)())

{

   
ENSURE(pfnCreateObject);

 

      
if
(m_nSlot == 0)

      
{

             

if (_afxThreadData == NULL)

             
{

                    

_afxThreadData = new(__afxThreadData) CThreadSlotData;

                    

ENSURE(_afxThreadData != NULL);

             

}

             
m_nSlot =
_afxThreadData->AllocSlot();

             
ENSURE(m_nSlot
!= 0);

      
}

      
CNoTrackObject*
pValue =
static_cast<CNoTrackObject*>(_afxThreadData->GetThreadValue(m_nSlot));

      
if
(pValue == NULL)

      
{

             

// allocate zero-init object

             

pValue = (*pfnCreateObject)();

 

             

// set tls data to newly created object

             

_afxThreadData->SetValue(m_nSlot, pValue);

             

ASSERT(_afxThreadData->GetThreadValue(m_nSlot) == pValue);

      
}

      
return
pValue;

}

CThreadLocalObject::GetData
首先判断
m_nSlot
,如果
m_nSlot
== 0

,说明该
Thread State

曾分配,

GetData
函数将会使用
_afxThreadData->AllocSlot
函数分配一个新的
TLS

Slot
,保存在
m_nSlot
之中,然后调用
GetThreadValue
检查
pValue
是否为
NULL
,如果是,则创建一个新的对象然后调用
SetValue

pValue
设置到该
Slot
之中。
_afxThreadData
的类型为
CThreadSlotData
,是对
TLS API
的一个简单的封装。

_AFX_THREAD_STATE
是一个很常用的
Thread
State

,每个
Thread
,都会有自
己的一份

_AFX_THREAD_STATE

MFC
提供了一个函数
AfxGetThreadState
来获得当前进程的
Thread
State

,如果当前的线程还没有
Thread State

该函数会创建一个新的

Thread State

_AFX_THREAD_STATE*
AFXAPI AfxGetThreadState()

{

      
_AFX_THREAD_STATE
*pState =_afxThreadState.GetData();

      
ENSURE(pState
!= NULL);

      
return pState;

}

 

_AFX_THREAD_STATE
中保存着下列信息:

1.    


当前的
m_pModuleState
,每个线程都知道它当前的
Module
State

,这个信息被用来获得当前的
Module State

AfxGetModuleState
正是这么做的:

AFX_MODULE_STATE*
AFXAPI AfxGetModuleState()

{

      
_AFX_THREAD_STATE*
pState = _afxThreadState;

      
ENSURE(pState);

      
AFX_MODULE_STATE*
pResult;

      
if (pState->m_pModuleState
!= NULL)

      
{

             

// thread state's module state serves as override

             

pResult = pState->m_pModuleState;

      
}

      
else

      
{

             

// otherwise, use global app state

             

pResult = _afxBaseModuleState.GetData();

      
}

      
ENSURE(pResult
!= NULL);

      
return pResult;

}

 

2.    


之前的
m_pModuleState
,用来保存之前的
Module
State

,用于
Module State

换,可参考

AFX_MANAGE_STATE

3.    


其他信息,具体可以参考
_AFX_THREAD_STATE
的定义

4.
     


Module State



Module
State

保存着和
Module
相关的状态
信息。

Module

Windows
的术语,代表任何一个可执行的代码文件,
EXE

DLL
都是
Module
的一种。
Module State

下面几种:

1.    


AFX_MODULE_STATE
,保存
MODULE
的信息,是
_AFX_BASE_MODULE_STATE

_AFX_DLL_MODULE_STATE
的基类

2.    


_AFX_BASE_MODULE_STATE
,保存
MFC Module
的状态信息,没有定义其他的成员

3.    


_AFX_DLL_MODULE_STATE
,保存
DLL
的状态信息,没有定义其他的成员

4.    


AFX_MODULE_THREAD_STATE
,保存主线程的有关状态信息,虽然
AFX_MODULE_THREAD_STATE
是保存的线程的状态信息,但是它只保存
Module
的主线程的状
态信息,所以可以看作是

Module State
的一种。

这些
Module
State

保存了
MFC
中的大量重要信息:

1.    


CWinApp
指针

2.    


实例句柄

3.    


资源
Module
的句柄

4.    


句柄表

5.    


OLE
相关信息

6.    


窗口过程

7.    


Activation Context

8.    


……

 

4.1
     


AFX_MODULE_STATE


AFX_MODULE_STATE
的定义如下:

//
AFX_MODULE_STATE (global data for a module)

class AFX_MODULE_STATE :
public CNoTrackObject

{

public:

#ifdef _AFXDLL

      
AFX_MODULE_STATE(BOOL
bDLL, WNDPROC pfnAfxWndProc, DWORD dwVersion,

             

BOOL bSystem = FALSE);

#else

      
explicit
AFX_MODULE_STATE(BOOL bDLL);

#endif

      
~AFX_MODULE_STATE();

 

      
CWinApp*
m_pCurrentWinApp;

      
HINSTANCE
m_hCurrentInstanceHandle;

      
HINSTANCE
m_hCurrentResourceHandle;

      
LPCTSTR
m_lpszCurrentAppName;

      
// ……

其他成员,从略

};

可以看到:

1.    


AFX_MODULE_STATE

CNoTrackObject
继承。
CNoTrackObject
定义了自己的
new/delete
保证自己不会被各种调试版本的
new/delete

Track
,以免自己被
错误的当作

Leak

2.    


AFX_MODULE_STATE

DLL
和非
DLL
(也就是
EXE
)的情况下具有不同的构造函数(和成员)

3.    


AFX_MODULE_STATE
在成员中保存了一些和
Module
相关的重要信息

实际上,
AFX_MODULE_STATE
并没有被直接使用,而是作为
_AFX_BASE_MODULE_STATE

_AFX_DLL_MODULE_STATE
的基类:

_AFX_BASE_MODULE_STATE
被用于
Module
,其定义如下:

class
_AFX_BASE_MODULE_STATE : public AFX_MODULE_STATE

{

public:

#ifdef _AFXDLL

      
_AFX_BASE_MODULE_STATE()
: AFX_MODULE_STATE(TRUE, AfxWndProcBase, _MFC_VER)

#else

      
_AFX_BASE_MODULE_STATE()
: AFX_MODULE_STATE(TRUE)

#endif

             
{ }

};

 

PROCESS_LOCAL(_AFX_BASE_MODULE_STATE,
_afxBaseModuleState)

_AFX_DLL_MODULE_STATE

_AFX_BASE_MODULE_STATE
类似,只是仅用于
DLL

class
_AFX_DLL_MODULE_STATE : public AFX_MODULE_STATE

{

public:

      
_AFX_DLL_MODULE_STATE()
: AFX_MODULE_STATE(TRUE, AfxWndProcDllStatic, _MFC_VER)

             

{ }

};

 

static _AFX_DLL_MODULE_STATE afxModuleState;

这两个
class
都没有定义额外的成员,比较简单,只是传入到基类
AFX_MODULE_STATE
的参数不同。此外,他们定义的方式不太一样,前者使用的是
PROCESS_LOCAL
宏,定义了一个变量
_afxBaseModuleState
。后者只是简单的定义了一个
static
变量
afxModuleState

 

下面这些函数可以用来获得
Module

State

1.    


AfxGetModuleState

AfxGetModuleState
首先获得
_afxThreadState

m_pModuleState
,如果当前的
Thread
State


m_pModuleState
返回
NULL
,说明当前的
Thread
State

没有正确的初始化(通常的原因是
创建线程的时候调用的是

CreateThread
函数而非
AfxBeginThread
),则使用
_afxBaseModuleState

AFX_MODULE_STATE*
AFXAPI AfxGetModuleState()

{

      
_AFX_THREAD_STATE*
pState = _afxThreadState;

      
ENSURE(pState);

      
AFX_MODULE_STATE*
pResult;

      
if (pState->m_pModuleState
!= NULL)

      
{

             

// thread state's module state serves as override

             

pResult = pState->m_pModuleState;

      
}

      
else

      
{

             

// otherwise, use global app state

             

pResult = _afxBaseModuleState.GetData();

      
}

      
ENSURE(pResult
!= NULL);

      
return pResult;

}

 

_afxBaseModuleState
是用
PROCESS_LOCAL
定义的:

PROCESS_LOCAL(_AFX_BASE_MODULE_STATE,
_afxBaseModuleState)

它代表整个
MFC Module

State
。当你的程序
是动态链接到

MFC DLL
的时候,该
State
只有一份。如果你的程序是静态链接到
MFC
的话,有几个模块(
EXE/DLL
)静态链
接到

MFC

MFC
的代码就有几份,那么
_afxBaseModuleState
也就有几份。

 

2.    


AfxGetStaticModuleState

AfxGetStaticModuleState
在不同的
Project
下面有着不同的行为:在
DLL
项目中,
AfxGetSaticModuleState
返回
afxModuleState
,也就是定义好的
_AFX_DLL_MODULE_STATE
,而在非
DLL
项目中,
AfxGetStaticModuleState
直接调用
AfxGetModuleState
。可以看到,在
DLL
的情况下,必须使用
AfxGetStaticModuleState
才可以获得
DLL
本身的
Module
State


#ifdef _AFXDLL

 

static
_AFX_DLL_MODULE_STATE afxModuleState;

 

AFX_MODULE_STATE* AFXAPI
AfxGetStaticModuleState()

{

      
AFX_MODULE_STATE*
pModuleState = &afxModuleState;

      
return
pModuleState;

}

 

#else

 

AFX_MODULE_STATE* AFXAPI AfxGetStaticModuleState()

抱歉!评论已关闭.