1.
Introduction
当我们在用
MFC
编程的时候,我们经常用到
AfxGetApp()
来获得当前的
CWinApp
的
Instance
。看看
MFC
的源代码中
AfxGetApp()
的实现,你会发现
AfxGetApp()
的实现并不像一般情况下面那样直接:
_AFXWIN_INLINE CWinApp* #define afxCurrentWinApp |
AfxGetApp()
调用的是
AfxGetModuleState()
,该函数返回一个
AFX_MODULE_STATE
的指针,其中的一个成员保存着当前的
CWinApp
的指针。可
AfxGetModuleState()
的作用又是什么呢?
此外,当我们在开发
MFC
DLL
程序的时候,我们会在每个输出的
DLL
函数前面加上一句
AFX_MANAGE_STATE
:
void { 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 #define |
PROCESS_LOCAL
用
CProcessLocal
模板类定义了一个
CProcessLocal<class_name>
的一个实例作为状态变量,而
EXTERN_PROCESS_LOCAL
则使在头文件中声明此状态变量。
CProcessLocal
的定义如下:
class { public: // Attributes
// Implementation };
template<class TYPE> class CProcessLocal : { // Attributes public:
// Implementation public: };
|
CProcessLocal
的作用只是一个
Wrapper
,
Hold
一个
TYPE*
的指针,一旦用户调用
GetData
来获得这个指针,
GetData
会首先判断该指针是否为空,如果为空,则创建一个新的实例保存起来,否
则返回已有的指针。前提条件是,
TYPE
必须从
CNoTrackObject
继承。任何从
CNoTrackObject
继承的类都拥有自己的
new/delete
,这样此对象便不会被
Debug
的内存分配系统所跟踪而误判为
Leak
。
CNoTrackObject* { } |
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
首先判断
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* { } |
_AFX_THREAD_STATE
中保存着下列信息:
1.
当前的
m_pModuleState
,每个线程都知道它当前的
Module
State
,这个信息被用来获得当前的
Module State
,
AfxGetModuleState
正是这么做的:
AFX_MODULE_STATE* { } |
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
的定义如下:
// class AFX_MODULE_STATE : { public: #ifdef _AFXDLL #else #endif
}; |
可以看到:
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 { public: #ifdef _AFXDLL #else #endif };
PROCESS_LOCAL(_AFX_BASE_MODULE_STATE, |
_AFX_DLL_MODULE_STATE
和
_AFX_BASE_MODULE_STATE
类似,只是仅用于
DLL
:
class { public: };
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* { } |
_afxBaseModuleState
是用
PROCESS_LOCAL
定义的:
PROCESS_LOCAL(_AFX_BASE_MODULE_STATE, |
它代表整个
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_MODULE_STATE* AFXAPI { }
#else
AFX_MODULE_STATE* AFXAPI AfxGetStaticModuleState()
|