[转]MFC的模块状态:从AfxGetApp()和AFX_MANAGE_STATE()看MFC的模块状态_相互提携-------rootlife的博客

导读:


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


#define EXTERN_PROCESS_LOCAL(class_name, ident_name) /


         extern CProcessLocal ident_name;


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


class AFX_NOVTABLE CProcessLocalObject
{


public:


// Attributes


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


// Implementation


         CNoTrackObject* volatile m_pObject;


         ~CProcessLocalObject();
};


template


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 (_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()
{
         AFX_MODULE_STATE* pModuleState = AfxGetModuleState();


         return pModuleState;
}
#endif


3.       AfxGetAppModuleState


AfxGetAppModuleState是最简单的,直接返回_afxBaseModuleState:


AFX_MODULE_STATE* AFXAPI AfxGetAppModuleState()


{
         return _afxBaseModuleState.GetData();
}


从上面的讨论可以看出,当前处于那个MFC Module的状态之中,返回的就是那个MFC Module所相关联的CWinApp对象。如果你有多个Module都是动态链接到MFC DLL的话,那么AfxGetAppModuleState返回的总是同一个CWinApp。



5.        AFX_MANAGE_STATE
AFX_MANAGE_STATE的作用切换到指定的Module State,当出了作用域的时候将Module State恢复到原来的值。是在不同的Module State之中切换,原因有2:


1.       在不同的MFC DLL和MFC EXE的Module State之间切换,保持正确的AFX_MODULE_STATE,最常见的问题是在DLL输出的函数之中无法获得DLL本身相关的资源,这就是没有正确维护Module State的原因造成的,因为当前Resource DLL的句柄就保存在Module State之中。


2.       切换Activation Context,不同的Module必然有着不同的Activation Context,需要切换。这是属于Side By Side的内容,以后我会专门写一篇文章来讲述Side By Side和manifest的相关信息。


一般的用法如下:


void SomeMFCDllFunction()


{


AFX_MANAGE_STATE(AfxGetStaticModuleState())



注意这里使用的是AfxGetStaticModuleState,而非AfxGetModuleState。原因是在DLL项目中,AfxGetStaticModuleState返回的是DLL本身的Module State,而AfxGetModuleState则是返回当前线程相关的Module State,由于一般DLL输出的函数是被其他Module调用,那么大部分情况下当前线程的Module State都是错误的,所以必须得使用DLL本身的Module State。


AFX_MANAGE_STATE只是一个宏,如下:


struct AFX_MAINTAIN_STATE2
{
         explicit AFX_MAINTAIN_STATE2(AFX_MODULE_STATE* pModuleState) throw();


         ~AFX_MAINTAIN_STATE2();
protected:


#ifdef _AFXDLL
         AFX_MODULE_STATE* m_pPrevModuleState;


         _AFX_THREAD_STATE* m_pThreadState;
#endif
         ULONG_PTR m_ulActCtxCookie;


         BOOL m_bValidActCtxCookie;
};


#define AFX_MANAGE_STATE_NO_INIT_MANAGED(p) AFX_MAINTAIN_STATE2 _ctlState(p);


#define AFX_MANAGE_STATE(p) _AfxInitManaged(); AFX_MANAGE_STATE_NO_INIT_MANAGED(p)


可以看到AFX_MANAGE_STATE声明了一个栈上的局部变量_ctrlState,类型为AFX_MAINTAIN_STATE2。这是一个很常用的Pattern,AFX_MAINTAIN_STATE2在构造函数的时候会将当前的Module State切换为参数中指定的Module State:


AFX_MAINTAIN_STATE2::AFX_MAINTAIN_STATE2(AFX_MODULE_STATE* pNewState) throw()
{
#ifdef _AFXDLL


         m_pThreadState = _afxThreadState.GetData();


         ASSERT(m_pThreadState);


         if(m_pThreadState)
         {
                m_pPrevModuleState = m_pThreadState->m_pModuleState;


                m_pThreadState->m_pModuleState = pNewState;
         }
         else
         {
                // This is a very bad state; we have no good way to report the error at this moment


                // since exceptions from here are not expected


                m_pPrevModuleState=NULL;


                m_pThreadState=NULL;
         }
#endif
         if (AfxGetAmbientActCtx() &&
                pNewState->m_hActCtx != INVALID_HANDLE_VALUE)
         {
                m_bValidActCtxCookie = AfxActivateActCtx(pNewState->m_hActCtx, &m_ulActCtxCookie);
         }
         else
         {
                m_bValidActCtxCookie = FALSE;
         }
}


然后在析构函数的时候将其恢复回来:


// AFX_MAINTAIN_STATE2 functions


_AFXWIN_INLINE AFX_MAINTAIN_STATE2::~AFX_MAINTAIN_STATE2()
{
#ifdef _AFXDLL


         // Not a good place to report errors here, so just be safe


         if(m_pThreadState)
         {
                m_pThreadState->m_pModuleState = m_pPrevModuleState;
         }
#endif
         if (m_bValidActCtxCookie)
         {
                BOOL bRet;


                bRet = AfxDeactivateActCtx(0, m_ulActCtxCookie);


                ASSERT(bRet == TRUE);
         }
}


可以看到,AFX_MAINTAIN_STATE2将当前_afxThreadState在m_pThreadState中存起来,然后将所指向的Module State保存在m_pPrevModuleState中。在析构函数中,则使用保存起来的m_pPrevModuleState恢复到m_pThreadState的Module State。除了保存恢复Module state之外,AFX_MAINTAIN_STATE2也会在切换Activation Context。这个Activation Context被用来查找Side By Side Assemblies,我以后会专门写一篇文章讲述Side By Side和Manifest相关的一些信息。这次就写到这里。


本文转自
http://hi.baidu.com/rootlife/blog/item/2f37e354ad8cdc5bd10906be.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值