📄 chap9_3.htm
字号:
<p>Summary=(SUMMARY)GetProcAddress(ghMathsDLL,"Summary");</p>
<p>//获得DLL中Factorial函数的地址</p>
<p>Factorial=(FACTORIAL)GetProcAddress(ghMathsDLL,"Factorial");</p>
<p>}</p>
<p> </p>
<p> 在testdlg.cpp文件开头,加入:</p>
<p>//The instance of the Mymaths.DLL library</p>
<p>HINSTANCE ghMathsDLL=NULL;</p>
<p>//declare the Summary() function from the Mymaths.DLL libray.</p>
<p>typedef int (*SUMMARY)(int);</p>
<p>SUMMARY Summary;</p>
<p>//declare the Factorial() function from</p>
<p>//the Mymaths.DLL library.</p>
<p>typedef int (*FACTORIAL)(int);</p>
<p>FACTORIAL Factorial;</p>
<p>首先加入一个ghMathsDLL的全局变量,它是动态连接库载入后的句柄(同应用程序一样,每个动态连接库载入都会有一个句柄和它相对应)。应用程序通过句柄访问库中的函数。然后加入Summary和Factorial函数指针的类型定义。</p>
<p> 在LoadDLL()函数定义中,检查动态连接库句柄是否为空;若为空,则用LoadLibrary载入该动态连接库。然后用GetProcAddress取得Summary和Factorial函数地址。</p>
<p> 在OnFactorial和OnSummary函数开头,调用LoadDLL(),载入动态连接库。现在编译运行程序,按Factorial按钮测试一下程序。</p>
<p> <b></b>应用程序是如何查找DLL文件的</p>
<p> 应用程序test按以下顺序查找动态连接库文件:
<ul>
<li>当前目录下(因此要将动态连接库拷贝至DEBUG目录下,因为可执行文件在该目录下)</li>
<li>Windows目录</li>
<li>Windows系统目录</li>
<li>PATH环境变量中设置的目录</li>
<li>列入映射网络的目录表中的目录</li>
</ul>
<p><b> </b></p>
<p> <b></b>调用动态连接库中的函数的方法</p>
<p> 有两种方法可以调用动态连接库中的函数:</p>
<p> 1.通过引入库:</p>
<p> 利用Visual
C++提供的IMPLIB工具为动态连接库生成引入库,为引入库设计一个头文件:</p>
<p>#ifndef _MYMATH_H</p>
<p>#define _MYMATH_H</p>
<p>extern “C”</p>
<p>{</p>
<p>int Summary(int n);</p>
<p>int Factorial(int n);</p>
<p>}</p>
<p>#endif</p>
<p>将该头文件包含在使用动态连接库的源文件中,连接应用程序时会连接上该引入库。这样,应用程序就可以象使用静态连接库一样自由的使用动态连接库中的函数了。注意要把动态连接库拷贝到应用程序可执行文件所在的目录(\TEST\DEBUG)下。</p>
<p> 这是一种常用的方法。实际上,应用程序就是通过这种方式访问Windows的API函数的。Windows为其内核动态连接库生成引入库并提供了头文件。应用程序在编译时将引入库的信息带入可执行文件中,在运行时通过引入库信息访问API函数。</p>
<p> 2. 直接指定库和函数地址</p>
<p> 这种方式适合于一些提供文件格式转换等服务的动态连接库。比如,一个程序带有多个动态连接库,分别用于访问JPG、BMP、GIF等多种图像文件格式,这些动态连接库提供了相同的库函数接口。此时,无法使用引入库方式指定库函数。可以采用下面的方法来解决这个问题。</p>
<p>HANDLE hLibrary;</p>
<p>FARPROC lpFunc;</p>
<p>int nFormat;</p>
<p>if(nFormat==JPEG)//如果是JPEG格式,装入JPEG动态连接库</p>
<p>{</p>
<p>hLibrary=LoadLibrary(“JPEG.DLL”);</p>
<p>}</p>
<p>else//是GIF格式</p>
<p> hLibrary= LoadLibrary(“GIF.DLL”);</p>
<p>if(hLibrary>=32)</p>
<p>{</p>
<p>lpFunc=GetProcAddress(hLibrary,”ReadImage”);</p>
<p>if(lpFunc!=(FARPROC)NULL)</p>
<p>(*lpFunc)((LPCTSTR)strFileName);</p>
<p>FreeLibrary(hLibrary);</p>
<p>}</p>
<p>LoadLibrary函数装入所需的动态连接库,并返回库的句柄。如果句柄小于32,则载入库失败,错误含义参见有关手册。GetProcAddress函数使用函数名字取得函数的地址。利用该函数地址,就可以访问动态连接库的函数了。</p>
<p> FreeLibrary通过检查动态连接库的引用计数器,判断是否还有别的程序在使用这个动态连接库。如果没有,就从内存中移去该动态连接库;如果有,将动态连接库的使用计数器减1。LoadLibrary则将引用计数加1。</p>
<p> 在用户动态连接库中,也可以使用MFC类。这时,可以选择静态连接和动态连接两种方式使用MFC库。</p>
<p> <b></b>9.3.2 MFC扩展类库(_AFXDLL)</p>
<p> </p>
<p> 除了创建具有C语言接口的用户动态连接库外,MFC还允许用户在动态连接库中创建MFC类的派生类,这些类作为MFC类的自然延伸出现,可以为其他MFC应用程序所使用,就象使用普通的MFC类一样。</p>
<p> <b></b>创建扩展类库</p>
<p> 要创建扩展类库,可以选择File->New菜单,在Projects类型中选择MFC
AppWizard(dll)。弹出MFC
AppWizard 1of 1对话框,从中选择MFC
Extension DLL(using shared MFC DLL)。AppWizard就会生成Extension
DLL所需的框架。</p>
<p> 这里不再创建动态连接库,而是用Visual
C++的例子DLLHUSK程序(在SAMPLES\MFC\ADVANCED
\DLLHUSK目录下)说明扩展类库的创建和使用。</p>
<p> 在DLLHUSK项目工作区中,包含三个工程:DLLHUSK,TESTDLL1,TESTDLL2。</p>
<p> TESTDLL1和TESTDLL2分别定义了几个扩展类:CTextDoc、CHelloView和CListOutputFrame,DLLHUSK是使用这些类的示例程序。</p>
<p> 在CListOutputFrame声明中,要加入AFX_EXT_CLASS,表明它是一个MFC扩展类。</p>
<p>class AFX_EXT_CLASS CListOutputFrame:public CMDIChildWnd</p>
<p>{</p>
<p>...</p>
<p>}</p>
<p>在函数定义处,还要包含afxdllx.h头文件</p>
<p>// Initialization of MFC Extension DLL</p>
<p>#include "afxdllx.h" // standard MFC Extension DLL routines</p>
<p>类的成员函数使用与应用程序中类的使用大致相同。</p>
<p> 在CListOutputFrame类定义文件中,还提供了一个C函数。它的函数声明在类头文件testdll2.h中:</p>
<p>// Initialize the DLL, register the classes etc</p>
<p>extern "C" AFX_EXT_API void WINAPI InitTestDLL2();</p>
<p>这个函数用于初始化动态连接库和注册类:</p>
<p>// Exported DLL initialization is run in context of running application</p>
<p>extern "C" void WINAPI InitTestDLL2()</p>
<p>{</p>
<p>// create a new CDynLinkLibrary for this app</p>
<p>new CDynLinkLibrary(extensionDLL);</p>
<p>// nothing more to do</p>
<p>}</p>
<p>另外,源文件中还需要提供一个DllMain函数:</p>
<p align="JUSTIFY">DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID
lpReserved)</p>
<p align="JUSTIFY">这个函数作用与前面的DllEntryPoint类似。
</p>
<p align="JUSTIFY"> 扩展类库也需要一个DEF文件,这个文件包含了动态连接库中可用的函数信息。由于现在动态连接库包含的是类,因此在函数命名上与用户动态连接库有所不同。</p>
<p>EXPORTS</p>
<p>?AddString@CListOutputFrame@@QAAXPBD@Z</p>
<p>??_7CListOutputFrame@@6B@</p>
<p>??_GCListOutputFrame@@UAAPAXI@Z</p>
<p>?OnEditCut@CListOutputFrame@@IAAXXZ</p>
<p>?_messageEntries@CListOutputFrame@@0QBUAFX_MSGMAP_ENTRY@@B</p>
<p>??0CListOutputFrame@@QAA@XZ</p>
<p>??1CListOutputFrame@@UAA@XZ</p>
<p>?Clear@CListOutputFrame@@QAAXXZ</p>
<p>?OnEditClear@CListOutputFrame@@IAAXXZ</p>
<p>?OnEditCopy@CListOutputFrame@@IAAXXZ</p>
<p>InitTestDLL2</p>
<p>......</p>
<p>有关函数名扩展的技术参考Visual
C++帮助文档。</p>
<p> <b></b>使用扩展类动态连接库</p>
<p> 要使用扩展类库,要将类库的头文件包含在工程中。然后在适当位置初始化类库,DLLHusk是在InitInstance中完成这一工作的。</p>
<p>BOOL CHuskApp::InitInstance()</p>
<p>{</p>
<p>//...</p>
<p>InitTestDLL1(); </p>
<p>InitTestDLL2();</p>
<p>//...</p>
<p>} </p>
<p>然后就可以象使用普通MFC类一样使用扩展类库中定义的类了。</p>
<p> m_pListOut=new CListOutputFrame;</p>
<p> <b></b>访问DLL中的资源</p>
<p> 当应用程序使用资源时,它按以下顺序查找资源:首先查找应用程序本身,看有没有对应的资源;如果没有,查找MFC400.DLL(或MFC400D.DLL,它包含调试信息)。再查找应用程序所带的动态连接库中的资源。如果想在DLL中直接使用资源而不经过以上搜索顺序,可以使用AfxGetResouceHandle()和AfxSetResourceHandle()函数。</p>
<p> AfxGetResourceHandle()和AfxSetResouceHandle()函数分别用来保存旧的资源句柄和设置新的资源句柄。比如,要想直接从DLL中载入一个位图资源,可以这么调用:</p>
<p>CBitmap mybitmap;</p>
<p>HINSTANCE hInstOld=AfxGetResourceHandle()</p>
<p>AfxSetResouceHandler(extensionDLL.hModule);</p>
<p>if(!mybitmap.LoadBitmap(IDR_BITMAP));</p>
<p>{</p>
<p>//restore the old resouce chain and return error</p>
<p>AfxSetResouceHandle(hInstOld);</p>
<p>return FALSE;</p>
<p>}</p>
<p>AfxSetResouceHandle(hInstOld);</p>
<p>//use this bitmap...</p>
<p>return TRUE;</p>
<p>还可以使用FindResource()搜索资源表,寻找给定的资源。</p>
<blockquote> <b>
<p>HRSRC FindResource(</p>
</b></blockquote>
<p> <b>HMODULE</b> <i>hModule</i><b>,</b></p>
<p><b> </b></p>
<b></b>
<p> <b>LPCTSTR</b> <i>lpName</i><b>,</b> </p>
<p><b> </b></p>
<b></b>
<p> <b>LPCTSTR</b> <i>lpType</i> </p>
<p><b> </b></p>
<b>
<p> );</p>
</b>
<p> <b>FindResource</b>带三个参数,第一个参数是模块句柄,第二个是要查找的资源名字,如“MYDIALOG”,第三个是资源类型,可参见Visual
C++文档。如果查找成功,则返回该资源句柄。可以用LoadResouce以该句柄为参数装入资源。</p>
<div align="center">
<center>
<table border="0" cellpadding="0" cellspacing="0" width="615">
<tr>
<td><a href="chap9_2.htm">上一页</a></td>
<td>
<p align="right"><a href="chap9_4.htm">下一页</a>
</td>
</tr>
</table>
<p><a href="http://www.cpcw.com">电脑报首页</a> <a href="../../index.htm">网络学院首页</a></p>
</center>
</div>
<hr noshade color="#3973DE" size="1">
<p align="center">本教程由<a href="http://vcdynasty.yeah.net">Visual C++王朝(Where
programmers come together)</a>协助制作<br>
未经许可,请勿以任何形式复制
</td>
</tr>
</table>
</center>
</div>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -