9. MFC 的状态
MFC 定义了多种状态信息,这里要介绍的是模块状态、进程状态、线程状态。这些状态可以组合
在一起,例如 MFC 句柄映射就是模块和线程局部有效的,属于模块-线程状态的一部分。
1. 模块状态
这里模块的含义是:一个可执行的程序或者一个使用 MFC DLL 的 DLL,
比如一个 OLE 控件就是一个模块。dongchenghuozi
一个应用程序的每一个模块都有一个状态,模块状态包括这样一些信息:用来加载资源的
Windows 实例句柄、指向当前 CWinApp 或者 CWinThread 对象的指针、OLE 模块的引用计
数、Windows 对象与相应的 MFC 对象之间的映射。只有单一模块的应用程序的状态如图 9-1
所示。
m_pModuleState 指针是线程对象的成员变量,指向当前模块状态信息(一个
AFX_MODULE_STATE 结构变量)。当程序运行进入某个特定的模块时,必须保证当前使用的模
块状态是有效的模块状态──是这个特定模块的模块状态。所以,每个线程对象都有一个指针指
向有效的模块状态,每当进入某个模块时都要使它指向有效模块状态,这对维护应用程序全局状态
和每个模块状态的完整性来说是非常重要的。为了作到这一点,每个模块的所有入口点有责任
实现模块状态的切换。模块的入口点包括:DLL 的输出函数;OLE/COM 界面的成员函数;窗
口过程。
在讲述窗口过程和动态链接到 MFC DLL 的规则 DLL 时,曾提到了语句
AFX_MANAGE_STATE(AfxGetStaticModuleState( )),它就是用来在入口点切换模块状态
的。其实现机制将在后面 9.4.1 节讲解。
多个模块状态之间切换的示意图如图 9-2 所示。
图 9-2 中,m_pModuleState 总是指向当前模块的状态。
2. 模块、进程和线程状态的数据结构
MFC 定义了一系列类或者结构,通过它们来实现状态信息的管理。这一节将描述它们的关系,
并逐一解释它们的数据结构、成员函数等。
1. 层次关系
图 9-3 显示了线程状态、模块状态、线程-模块状态等几个类的层次关系:
线程状态用类_AFX_THREAD_STATE 描述,模块状态用类 AFX_MODULE_STATE 描述,
模块-线程状态用类 AFX_MODULE_THREAD_STATE 描述。这些类从类 CNoTrackObject
派生。进程状态类用 _AFX_BASE_MODULE_STATE 描述,从模块状态类
AFX_MODULE_STATE 派生。进程状态是了一个可以独立执行的 MFC 应用程序的模块状态。
还有其他状态如
DLL 的模块状态等
也从模块状态类
_AFX_MODULE_STATE 派生。
图 9-4 显示了这几个类的交互关
系。
从图 9-4 可以看出:首先,每个线
程有一个线程状态,线程状态的指
针 m_pModuleState 和
m_pPreModuleState 分别指向线
程当前运行模块的状态或前一运行
模块的状态;其次,每一个模块状
态都有一个线程局部的变量用来存储模块-线程状态。
下面各小节列出状态信息管理所涉及的各个类的定义。
2. CNoTrackObject 类
在图 9-3 中, CnoTrackObject 是根类,所有状态类都是从它这里派生的,其定义如下:
class CNoTrackObject
{
public:
void* PASCAL operator new(size_t nSize);
void PASCAL operator delete(void*);
#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)
void* PASCAL operator new(size_t nSize, LPCSTR, int);
#endif
virtual ~CNoTrackObject() { }
};