📄 mfc
字号:
<P align=justify>
<LI>一个进程(使用MFC的应用程序)的主线程创建线程模块状态和进程模块状态,前者是_AFX_THREAD_STATE类的实例,后者是_AFX_BASE_MODULE_STATE类的实例。
<P></P>
<P align=justify></P>
<LI>当进程的新的线程被创建时,它创建自己的线程状态,继承父线程的模块状态。在线程的入口函数_AfxThreadEntry完成这样的处理,该函数的描述见8.5.3节。
<P></P></LI></UL>
<OL>
<OL>
<OL>
<P align=justify>
<LI><A name=_Toc445889112></A><A name=_Toc445782515></A><A
name=_Toc452640975></A><A name=_Toc457299078></A><B>扩展DLL的模块状态</B>
<P></P>
<P
align=justify>7.3.1节指出扩展DLL的实现必须遵循五条规则,为此,首先在扩展DLL实现文件里头,定义AFX_EXTENSION_MODULE类型的静态扩展模块变量,然后在DllMain入口函数里头使用AfxInitExtension初始化扩展模块变量,并且实现和输出一个初始化函数供扩展DLL的使用者调用。</P>
<P
align=justify>使用者必须具备一个CWinApp对象,通常在它的InitInstance函数中调用扩展DLL提供的初始化函数。</P>
<P align=justify>一般用以下的几段代码完成上述任务。首先是扩展模块变量的定义和初始化:</P>
<P align=justify>static AFX_EXTENSION_MODULE extensionDLL;</P>
<P align=justify>DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID)</P>
<P align=justify>{</P>
<P align=justify>if (dwReason == DLL_PROCESS_ATTACH)</P>
<P align=justify>{</P>
<P align=justify>// Extension DLL one-time initialization</P>
<P align=justify>if (!AfxInitExtensionModule(extensionDLL,hInstance))</P>
<P align=justify>return 0;</P>
<P align=justify>……</P>
<P align=justify>}</P>
<P align=justify>}</P>
<P
align=justify>然后是扩展DLL的初始化函数,假定初始化函数命名为InitMyDll,InitMyDll被定义为“C”链接的全局函数,并且被输出。</P>
<P align=justify>// wire up this DLL into the resource chain</P>
<P align=justify>extern “C” void WINAPI InitMyDll()</P>
<P align=justify>{</P>
<P align=justify>CDynLinkLibrary* pDLL = new</P>
<P align=justify>CDynLinkLibrary(extensionDLL, TRUE);</P>
<P align=justify>ASSERT(pDLL != NULL);</P>
<P align=justify>...</P>
<P align=justify>}</P>
<P align=justify>最后是调用者的处理,假定在应用程序对象的InitInstance函数中调用初始化函数:</P>
<P align=justify>BOOL CMyApp::InitInstance()</P>
<P align=justify>{</P>
<P align=justify>InitMyMyDll();</P>
<P align=justify>…</P>
<P align=justify>}</P>
<P align=justify>上述这些代码只有在动态链接到MFC DLL时才有用。下面,对这些代码进行分析和解释</P>
<OL>
<P align=justify>
<LI><A name=_Toc445889113></A><A name=_Toc445782516></A><A
name=_Toc457299079></A><B>_AFX_EXTENSION_MODULE</B>
<P></P>
<P
align=justify>在分析代码之前,先讨论描述扩展模块状态的_AFX_EXTENSION_MODULE类。_AFX_EXTENSION_MODULE没有基类,其定义如下:</P>
<P align=justify>struct AFX_EXTENSION_MODULE</P>
<P align=justify>{</P>
<P align=justify>BOOL bInitialized;</P>
<P align=justify>HMODULE hModule;</P>
<P align=justify>HMODULE hResource;</P>
<P align=justify>CRuntimeClass* pFirstSharedClass;</P>
<P align=justify>COleObjectFactory* pFirstSharedFactory;</P>
<P align=justify>};</P>
<P align=justify>其中:</P>
<P align=justify>第一个域表示该结构变量是否已经被初始化了;</P>
<P align=justify>第二个域用来保存扩展DLL的模块句柄;</P>
<P align=justify>第三个域用来保存扩展DLL的资源句柄;</P>
<P align=justify>第四个域用来保存扩展DLL要输出的CRuntimeClass类;</P>
<P align=justify>第五个域用来保存扩展DLL的OLE Factory。</P>
<P
align=justify>该结构用来描述一个扩展DLL的模块状态信息,每一个扩展DLL都要定义一个该类型的静态变量,例如extensionDLL。</P>
<P align=justify></P>
<P
align=justify>在DllMain中,调用AfxInitExtensionModule函数来初始化本DLL的静态变量该变量(扩展模块状态),如extensionDLL。函数AfxInitExtensionModule原型如下:</P>
<P align=justify>BOOL AFXAPI AfxInitExtensionModule(</P>
<P align=justify>AFX_EXTENSION_MODULE& state, HMODULE hModule)</P>
<P align=justify>其中:</P>
<P align=justify>参数1是DllMain传递给它的扩展DLL的模块状态,如extensionDLL;</P>
<P align=justify>参数2是DllMain传递给它的模块句柄。</P>
<P align=justify>AfxInitExtensionModule函数主要作以下事情:</P>
<P
align=justify>(1)把扩展DLL模块的模块句柄hModule、资源句柄hModule分别保存到参数state的成员变量hModule、hResource中;</P>
<P
align=justify>(2)把当前模块状态的m_classList列表的头保存到state的成员变量pFirstSharedClass中,m_classInit的头设置为模块状态的m_pClassInit。在扩展DLL模块进入DllMain之前,如果该扩展模块构造了静态AFX_CLASSINIT对象,则在初始化时把有关CRuntimeClass信息保存在当前模块状态(注意不是扩展DLL模块,而是应用程序模块)的m_classList列表中。因此,扩展DLL模块初始化的CRuntimeClass信息从模块状态的m_classList中转存到扩展模块状态state的pFirstSharedClass中,模块状态的m_classInit恢复被该DLL改变前的状态。</P>
<P
align=justify>关于CRuntimeclass信息和AFX_CLASSINIT对象的构造,在3.3.1节曾经讨论过。一个扩展DLL在初始化时,如果需要输出它的CRuntimeClass对象,就可以使用相应的CRuntimeClass对象定义一个静态的AFX_CLASSINIT对象,而不一定要使用IMPLEMENT_SERIAL宏。当然,可以序列化的类必定导致可以输出的CRuntimeClass对象。</P>
<P
align=justify>(3)若支持OLE的话,把当前模块状态的m_factoryList的头保存到state的成员变量pFirstSharedFactory中。m_factoryList的头设置为模块状态的m_m_pFactoryInit。</P>
<P
align=justify>(4)这样,经过初始化之后,扩展DLL模块包含了扩展DLL的模块句柄、资源句柄、本模块初始化的CRuntimeClass类等等。</P>
<P align=justify>扩展DLL的初始化函数将使用扩展模块状态信息。下面,讨论初始化函数的作用。</P>
<P align=justify></P>
<LI><A name=_Toc445889114></A><A name=_Toc445782517></A><A
name=_Toc457299080></A><B>扩展DLL的初始化函数</B>
<P></P></LI></OL>
<P
align=justify>在初始化函数InitMyDll中,创建了一个动态的CDynLinkLibrary对象,并把对象指针保存在pDLL中。CDynLinkLibrary类从CCmdTarget派生,定义如下:</P>
<P align=justify>class CDynLinkLibrary : public CCmdTarget</P>
<P align=justify>{</P>
<P align=justify>DECLARE_DYNAMIC(CDynLinkLibrary)</P>
<P align=justify>public:</P>
<P align=justify>// Constructor</P>
<P align=justify>CDynLinkLibrary(AFX_EXTENSION_MODULE& state,</P>
<P align=justify>BOOL bSystem = FALSE);</P>
<P align=justify></P>
<P align=justify>// Attributes</P>
<P align=justify>HMODULE m_hModule;</P>
<P align=justify>HMODULE m_hResource; // for shared resources</P>
<P align=justify>CTypedSimpleList<CRuntimeClass*> m_classList;</P>
<P align=justify>#ifndef _AFX_NO_OLE_SUPPORT</P>
<P align=justify>CTypedSimpleList<COleObjectFactory*>
m_factoryList;</P>
<P align=justify>#endif</P>
<P align=justify>BOOL m_bSystem; // TRUE only for MFC DLLs</P>
<P align=justify></P>
<P align=justify>// Implementation</P>
<P align=justify>public:</P>
<P align=justify>CDynLinkLibrary* m_pNextDLL; // simple singly linked
list</P>
<P align=justify>virtual ~CDynLinkLibrary();</P>
<P align=justify></P>
<P align=justify>#ifdef _DEBUG</P>
<P align=justify>virtual void AssertValid() const;</P>
<P align=justify>virtual void Dump(CDumpContext& dc) const;</P>
<P align=justify>#endif //_DEBUG</P>
<P align=justify>};</P>
<P
align=justify>CDynLinkLibrary的结构和AFX_EXTENSION_MODULE有一定的相似性,存在对应关系。</P>
<P
align=justify>CDynLinkLibrary构造函数的第一个参数就是经过AfxInitExtensionModule初始化后的扩展DLL的模块状态,如extensionDLL,第二个参数表示该DLL模块是否是系统模块。</P>
<P
align=justify>创建CDynLinkLibrary对象导致CCmdTarget和CDynLinkLibrary类的构造函数被调用。CCmdTarget的构造函数将获取模块状态并且保存在成员变量m_pModuleState中。CDynLinkLibrary的构造函数完成以下动作:</P>
<P align=justify>构造列表m_classList和m_factoryList;</P>
<P
align=justify>把参数state的域hModule、hResource复制到对应的成员变量m_hModule、m_hResource中;</P>
<P
align=justify>把state的pFirstSharedClass、pFirstSharedFactory分别插入到m_classList列表、m_factoryList列表的表头;</P>
<P align=justify>把参数2的值赋值给成员变量m_bSystem中;</P>
<P
align=justify>至此,CDynLinkLibrary对象已经构造完毕。之后,CDynLinkLibrary构造函数把CDynLinkLibrary对象自身添加到当前模块状态(调用扩展DLL的应用程序模块或者规则DLL模块)的CDynLinkLibrary列表m_libraryList的表头。为了防止多个线程修改模块状态的m_libraryList,访问m_libraryList时使用了同步机制。</P>
<P align=justify>这样,调用模块执行完扩展模块的初始化函数之后,就把该扩展DLL的资源、CRuntimeClass类、OLE
Factory等链接到调用者的模块状态中,形成一个链表。图9-8表明了这种关系链。</P>
<P align=justify></P>
<P align=justify>综合以上分析,可以知道:</P>
<P
align=justify>扩展DLL的模块仅仅在该DLL调用DllMain期间和调用初始化函数期间被使用,在这些初始化完毕之后,扩展DLL模块被链接到当前调用模块的模块状态中,因此它所包含的资源信息等也就被链接到调用扩展DLL的应用程序或者规则DLL的模块状态中了。扩展DLL扩展了调用者的资源等,这是“扩展DLL”得名的原因之一。</P>
<P
align=justify>也正因为扩展DLL没有自己的模块状态(指AFX_MODULE_STATE对象,扩展DLL模块状态不是),而且必须由有模块状态的模块来使用,所以只有动态链接到MFC的应用程序或者规则DLL才可以使用扩展DLL模块的输出函数或者输出类。</P>
<P align=justify></P>
<LI><A name=_Toc445889111></A><A name=_Toc445782514></A><A
name=_Toc452640976></A><A name=_Toc457299081></A><B>核心MFC DLL</B>
<P></P>
<P align=justify>所谓核心MFC DLL,就是MFC核心类库形成的DLL,通常说动态链接到MFC,就是指核心MFC DLL。</P>
<P align=justify>核心MFC
DLL实际上也是一种扩展DLL,因为它定义了自己的扩展模块状态coreDLL,实现了自己的DllMain函数,使用AfxInitExtensionModule初始化核心DLL的扩展模块状态coreDLL,并且DllMain还创建了CDynLinkLibrary,把核心DLL的扩展模块状态coreDLL链接到当前应用程序的模块状态中。所有这些,都符合扩展DLL的处理标准。</P>
<P align=justify>但是,核心MFC
DLL是一种特殊的扩展DLL,因为它定义和实现了MFC类库,模块状态、线程状态、进程状态、状态管理和使用的机制就是核心MFC
DLL定义和实现的。例如核心MFC
DLL定义和输出的模块状态变量,即_afxBaseModuleState,就是动态链接到MFC的DLL的应用程序的模块状态。</P>
<P align=justify>但是MFC DLL不作为独立的模块表现出来,而是把自己作为一个扩展模块来处理。当应用程序动态链接到MFC
DLL时,MFC
DLL把自己的扩展模块状态coreDLL链接到模块状态afxBaseModuleState,模块状态的成员变量m_hCurrentInstanceHandle指定为应用程序的句柄。当规则DLL动态链接到MFC
DLL时,由规则DLL的DllMain把核心MFC
DLL的扩展模块状态coreDLL链接到规则DLL的模块状态afxModuleState中,模块状态afxModuleState的m_hCurrentInstanceHandle指定为规则DLL的句柄。</P>
<P align=justify>关于afxModuleState和规则DLL的模块状态,见下一节的讨论。</P>
<P align=justify></P>
<LI><A name=_Toc452640977></A><A
name=_Toc457299082></A><B>动态链接的规则DLL的模块状态的实现</B>
<P></P></LI></OL></OL></OL>
<P align=justify>在本节中,动态链接到MFC DLL(定义了_AFXDLL)的规则DLL在下文简称为规则DLL。</P>
<P align=justify>(1)规则DLL的模块状态的定义</P>
<P align=justify>规则DLL有自己的模块状态_afxModuleState,它是一个静态变量,定义如下:</P>
<P align=justify>static _AFX_DLL_MODULE_STATE afxModuleState;</P>
<P align=justify>_AFX_DLL_MODULE_STATE的基类是AFX_MODULE_STATE。</P>
<P align=justify>在前面的模块状态切换中提到的AfxGetStaticModuleState函数,其定义和实现如下:</P>
<P align=justify>_AFX_MODULE_STATE* AFXAPI AfxGetStaticModuleState()</P>
<P align=justify>{</P>
<P align=justify>AFX_MODULE_STATE* pModuleState = &afxModuleState;</P>
<P align=justify>return pModuleState;</P>
<P align=justify>}</P>
<P align=justify>它返回规则DLL的模块状态afxModuleState。</P>
<P
align=justify>规则DLL的内部函数使用afxModuleState作为模块状态;输出函数在被调用的时候首先切换到该模块状态,然后进一步处理。</P>
<P align=justify>(2)规则DLL的模块状态的初始化</P>
<P align=justify>从用户角度来看,动态链接到MFC
DLL的规则DLL不需要DllMain函数,只要提供CWinApp对象即可。其实,MFC内部是在实现扩展DLL的方法基础上来实现规则DLL的,它不仅为规则DLL提供了DllMain函数,而且规则DLL也有扩展DLL模块状态controlDLL。</P>
<P
align=justify>顺便指出,和扩展DLL相比,规则DLL有一个CWinApp(或其派生类)应用程序对象和一个模块状态afxModuleState。应用程序对象是全局对象,所以在进入规则DLL的DllMain之前已经被创建,DllMain可以调用它的初始化函数InitInstance。模块状态afxModuleState是静态全局变量,也在进入DllMain之前被创建,DllMain访问模块状态时得到的就是该变量。扩展DLL是没有CWinApp对象和模块状态的,它只能使用应用程序或者规则DLL的CWinApp对象和模块状态。</P>
<P align=justify>由于核心MFC
DLL的DllMain被调用的时候,访问的必定是应用程序的模块状态,要把核心DLL的扩展模块状态链接到规则DLL的模块状态中,必须通过规则DLL的DllMain来实现。</P>
<P
align=justify>规则DLL的DllMain(MFC内部实现)把参数1表示的模块和资源句柄通过AfxWinInit函数保存到规则DLL的模
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -