【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 2555|回复: 3

创建动态连接库-vc++编程指南

[复制链接]
发表于 2006-1-13 11:27:01 | 显示全部楼层 |阅读模式
<><a href="http://dev.poptool.net/vc++/2005-09-01/0509010199.html" target="_blank" >http://dev.poptool.net/vc++/2005-09-01/0509010199.html</A></P>
<>9.3创建动态连接库<BR><BR>在一些情况下,必须使用动态连接库:<BR><BR>1.多个应用程序共享代码和数据:比如Office软件的各个组成部分有相似的外观和功能,这就是通过共享动态连接库实现的。<BR><BR>2.在钩子程序过滤系统消息时必须使用动态连接库<BR><BR>3.设备驱动程序必须是动态连接库<BR><BR>4.如果要在对话框编辑器中使用自己定义的控件,也必须使用动态连接库<BR><BR>5.动态连接库以一种自然的方式将一个大的应用程序划分为几个小的模块,有利于小组内部成员的分工与合作。而且,各个模块可以独立升级。如果小组中的一个成员开发了一组实用例程,他就可以把这些例程放在一个动态连接库中,让小组的其他成员使用。<BR><BR>6.为了实现应用程序的国际化,往往需要使用动态连接库。使用动态连接库可以将针对某一国家、语言的信息存放在其中。对于不同的版本,使用不同的动态连接库。在使用AppWizard生成应用程序时,我们可以指定资源文件使用的语言,这就是通过提供不同的动态连接库实现的。<BR><BR>MFC支持两类动态连接库的创建:<BR><BR>用户动态连接库<BR><BR>MFC扩展类库。<BR><BR>9.3.1用户动态连接库(_USRDLL)<BR><BR>用户动态连接库一般使用C语言接口。要创建一个动态连接库,选择File-&gt;New菜单,弹出New对话框。在Projects标签页下,选择“Win32 Dynamic-Link Library”。Visual C++就会创建动态连接库所需的工程文件和MAK文件。<BR><BR>然后把下面两个文件加入到工程中(Project-Add to Project-Files菜单)。<BR><BR>文件1:mymaths.cpp<BR></P>
<>////////////////////////////<BR><BR>//mymaths.cpp<BR><BR>//<BR><BR>//a maths API DLL.<BR><BR>//<BR><BR>///////////////////////////<BR><BR>#include&lt;windows.h&gt;<BR><BR>//Declare the DLL functions prototypes<BR><BR>int Summary(int);<BR><BR>int Factorial(int);<BR><BR>//////////////////////////<BR><BR>//DllEntryPoint():The entry point of the DLL<BR><BR>//<BR><BR>/////////////////////////<BR><BR>BOOL WINAPI DLLEntryPoint(HINSTANCE hDLL,DWORD dwReason,<BR><BR>LPVOID Reserved)<BR><BR>{<BR><BR>switch(dwReason)<BR><BR>{<BR><BR>case DLL_PROCESS_ATTACH:<BR><BR>{<BR><BR>//一些初始化代码<BR><BR>break;<BR><BR>}<BR><BR>case DLL_PROCESS_DETACH:<BR><BR>{<BR><BR>//一些用于清理的代码<BR><BR>break;<BR><BR>}<BR><BR>}<BR><BR>return TRUE;<BR><BR>}<BR><BR>int Summary(int n)<BR><BR>{<BR><BR>int sum=0;<BR><BR>int i;<BR><BR>for(i=1;i&lt;=n;i++)<BR><BR>{<BR><BR>sum+=i;<BR><BR>}<BR><BR>return sum;<BR><BR>}<BR><BR>int Factorial(int n)<BR><BR>{<BR><BR>int Fact=1;<BR><BR>int i;<BR><BR>for(i=1;i&lt;=n;i++)<BR><BR>{<BR><BR>Fact=Fact*i;<BR><BR>}<BR><BR>return Fact;<BR><BR>}</P>
<><BR>//文件2:mymaths.def<BR><BR>//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;<BR><BR>;Mymaths.DEF<BR><BR>;<BR><BR>;The DEF file for the Mymaths.DLL DLL.<BR><BR>;<BR><BR>LIBRARY mymaths<BR><BR>CODE PRELOAD MOVEABLE DISCARDABLE<BR><BR>DATA PRELOAD SINGLE<BR><BR>EXPORTS<BR><BR>;The names of the DLL functions<BR><BR>Summary<BR><BR>Factorial<BR><BR></P>
 楼主| 发表于 2006-1-13 11:27:16 | 显示全部楼层
在文件mymaths.cpp开头,声明了动态连接库所包含的两个函数:Summary和Factorial。接着是DllEntryPoint()函数的定义。DllEntryPoint()顾名思义是动态连接库的入口,应用程序通过该入口访问动态连接库提供的服务。DllEntryPoint()主体是一个switch/case语句:<BR><BR>switch(dwReason)<BR><BR>{<BR><BR>case DLL_PROCESS_ATTACH:<BR><BR>{<BR><BR>//一些初始化代码<BR><BR>break;<BR><BR>}<BR><BR>case DLL_PROCESS_DETACH:<BR><BR>{<BR><BR>//一些用于清理的代码<BR><BR>break;<BR><BR>}<BR><BR>}<BR><BR>其中,在case DLL_PROCESS_ATTACH分支可加入动态连接库执行时的一些初始化代码。在case DLL_PROCESS_DETACH加入动态连接库被卸载时的一些清理代码,比如释放动态连接库运行时申请的内存等。<BR><BR>在DllEntryPoint()函数后,是两个函数Summary和Factorial函数的定义。它们的定义与前面的静态库完全相同。在这里用户可以放入任何函数。<BR><BR>另外,我们还需要一个mymaths.def文件。这个文件记录了可被外部应用程序使用的DLL库函数名字。这些名字信息和对应的函数位置的信息将被编译进动态连接库文件中,然后应用程序根据函数名字和函数位置对照表来找到对应的函数。<BR><BR>按F7编译工程,Visual C++就在mymaths\debug目录下生成一个mymaths.dll动态连接库文件。<BR><BR>现在,我们来使用刚才生成的动态连接库。我们并不重新生成一个程序,而是修改前面测试静态库时的test程序。首先,把mymaths\debug目录下的mymaths.dll拷贝到test\debug目录下。test程序运行时,会在该目录下搜索动态连接库文件。然后修改testdlg.h,在其中加入一个函数LoadDLL()的声明,见清单9.4。LoadDLL用于载入动态连接库。<BR><BR>清单9.4 修改后的对话框头文件<BR>
<>class CTestDlg : public CDialog<BR><BR>{<BR><BR>// Construction<BR><BR>public:<BR><BR>CTestDlg(CWnd* pParent = NULL); // standard constructor<BR><BR>protected:<BR><BR>void LoadDLL();<BR><BR>//......<BR><BR>}<BR><BR>然后修改testdlg.cpp,修改后如清单9.5。<BR><BR>清单95. TestDlg.cpp文件<BR><BR>// TestDlg.cpp : implementation file<BR><BR>//<BR><BR>#include "stdafx.h"<BR><BR>#include "Test.h"<BR><BR>#include "TestDlg.h"<BR><BR>//#include "mymath.h" //注释掉mymath.h头文件<BR><BR>#ifdef _DEBUG<BR><BR>#define new DEBUG_NEW<BR><BR>#undef THIS_FILE<BR><BR>static char THIS_FILE[] = __FILE__;<BR><BR>#endif<BR><BR>//The instance of the Mymaths.DLL library<BR><BR>HINSTANCE ghMathsDLL=NULL;<BR><BR>//declare the Summary() function from the Mymaths.DLL libray.<BR><BR>typedef int (*SUMMARY)(int);<BR><BR>SUMMARY Summary;<BR><BR>//declare the Factorial() function from<BR><BR>//the Mymaths.DLL library.<BR><BR>typedef int (*FACTORIAL)(int);<BR><BR>FACTORIAL Factorial;<BR><BR>/////////////////////////////////////////////////////////////////////////////<BR><BR>// CAboutDlg dialog used for App About<BR><BR>class CAboutDlg : public CDialog<BR><BR>{<BR><BR>//...<BR><BR>};<BR><BR>//CAboutDlg的一些成员函数定义<BR><BR>//CTestDlg的一些成员函数定义<BR><BR>void CTestDlg::OnSum() <BR><BR>{<BR><BR>// TODO: Add your control notification handler code here<BR><BR>LoadDLL();<BR><BR>int nSum=Summary(10);<BR><BR>CString sResult;<BR><BR>sResult.Format("Sum(10)=%d",nSum);<BR><BR>AfxMessageBox(sResult);<BR><BR>}<BR><BR>void CTestDlg::OnFactorial() <BR><BR>{<BR><BR>// TODO: Add your control notification handler code here<BR><BR>LoadDLL();<BR><BR>int nFact=Factorial(10);<BR><BR>CString sResult;<BR><BR>sResult.Format("10!=%d",nFact);<BR><BR>AfxMessageBox(sResult);<BR><BR>}<BR><BR>void CTestDlg:oadDLL()<BR><BR>{<BR><BR>//如果DLL已经载入,则返回<BR><BR>if(ghMathsDLL!=NULL)<BR><BR>{<BR><BR>return; <BR><BR>}<BR><BR>//载入Mymaths.DLL文件.<BR><BR>ghMathsDLL=LoadLibrary("mymaths.DLL");<BR><BR>//如果载入DLL失败,提示用户<BR><BR>if(ghMathsDLL==NULL)<BR><BR>{<BR><BR>AfxMessageBox("Cannot load DLL file!");<BR><BR>}<BR><BR>//获得DLL中Summary函数的地址<BR><BR>Summary=(SUMMARY)GetProcAddress(ghMathsDLL,"Summary");<BR><BR>//获得DLL中Factorial函数的地址<BR><BR>Factorial=(FACTORIAL)GetProcAddress(ghMathsDLL,"Factorial");<BR><BR>}</P>
<><BR> <BR><BR>在testdlg.cpp文件开头,加入:<BR><BR>//The instance of the Mymaths.DLL library<BR><BR>HINSTANCE ghMathsDLL=NULL;<BR><BR>//declare the Summary() function from the Mymaths.DLL libray.<BR><BR>typedef int (*SUMMARY)(int);<BR><BR>SUMMARY Summary;<BR><BR>//declare the Factorial() function from<BR><BR>//the Mymaths.DLL library.<BR><BR>typedef int (*FACTORIAL)(int);<BR><BR>FACTORIAL Factorial;<BR><BR>首先加入一个ghMathsDLL的全局变量,它是动态连接库载入后的句柄(同应用程序一样,每个动态连接库载入都会有一个句柄和它相对应)。应用程序通过句柄访问库中的函数。然后加入Summary和Factorial函数指针的类型定义。<BR><BR>在LoadDLL()函数定义中,检查动态连接库句柄是否为空;若为空,则用LoadLibrary载入该动态连接库。然后用GetProcAddress取得Summary和Factorial函数地址。<BR><BR>在OnFactorial和OnSummary函数开头,调用LoadDLL(),载入动态连接库。现在编译运行程序,按Factorial按钮测试一下程序。<BR><BR>应用程序是如何查找DLL文件的<BR><BR>应用程序test按以下顺序查找动态连接库文件: <BR><BR>当前目录下(因此要将动态连接库拷贝至DEBUG目录下,因为可执行文件在该目录下) <BR>Windows目录 <BR>Windows系统目录 <BR>ATH环境变量中设置的目录 <BR>列入映射网络的目录表中的目录 <BR> <BR></P><BR>
 楼主| 发表于 2006-1-13 11:27:28 | 显示全部楼层
调用动态连接库中的函数的方法<BR><BR>有两种方法可以调用动态连接库中的函数:<BR><BR>1.通过引入库:<BR><BR>利用Visual C++提供的IMPLIB工具为动态连接库生成引入库,为引入库设计一个头文件:<BR><BR>#ifndef _MYMATH_H<BR><BR>#define _MYMATH_H<BR><BR>extern “C”<BR><BR>{<BR><BR>int Summary(int n);<BR><BR>int Factorial(int n);<BR><BR>}<BR><BR>#endif<BR><BR>将该头文件包含在使用动态连接库的源文件中,连接应用程序时会连接上该引入库。这样,应用程序就可以象使用静态连接库一样自由的使用动态连接库中的函数了。注意要把动态连接库拷贝到应用程序可执行文件所在的目录(\TEST\DEBUG)下。<BR><BR>这是一种常用的方法。实际上,应用程序就是通过这种方式访问Windows的API函数的。Windows为其内核动态连接库生成引入库并提供了头文件。应用程序在编译时将引入库的信息带入可执行文件中,在运行时通过引入库信息访问API函数。<BR><BR>2. 直接指定库和函数地址<BR><BR>这种方式适合于一些提供文件格式转换等服务的动态连接库。比如,一个程序带有多个动态连接库,分别用于访问JPG、BMP、GIF等多种图像文件格式,这些动态连接库提供了相同的库函数接口。此时,无法使用引入库方式指定库函数。可以采用下面的方法来解决这个问题。<BR>
<>HANDLE hLibrary;<BR><BR>FARPROC lpFunc;<BR><BR>int nFormat;<BR><BR>if(nFormat==JPEG)//如果是JPEG格式,装入JPEG动态连接库<BR><BR>{<BR><BR>hLibrary=LoadLibrary(“JPEG.DLL”);<BR><BR>}<BR><BR>else//是GIF格式<BR><BR>hLibrary= LoadLibrary(“GIF.DLL”);<BR><BR>if(hLibrary&gt;=32)<BR><BR>{<BR><BR>lpFunc=GetProcAddress(hLibrary,”ReadImage”);<BR><BR>if(lpFunc!=(FARPROC)NULL)<BR><BR>(*lpFunc)((LPCTSTR)strFileName);<BR><BR>FreeLibrary(hLibrary);<BR><BR>}</P>
<><BR>LoadLibrary函数装入所需的动态连接库,并返回库的句柄。如果句柄小于32,则载入库失败,错误含义参见有关手册。GetProcAddress函数使用函数名字取得函数的地址。利用该函数地址,就可以访问动态连接库的函数了。<BR><BR>FreeLibrary通过检查动态连接库的引用计数器,判断是否还有别的程序在使用这个动态连接库。如果没有,就从内存中移去该动态连接库;如果有,将动态连接库的使用计数器减1。LoadLibrary则将引用计数加1。<BR><BR>在用户动态连接库中,也可以使用MFC类。这时,可以选择静态连接和动态连接两种方式使用MFC库。<BR><BR></P>
 楼主| 发表于 2006-1-13 11:29:06 | 显示全部楼层
访问DLL中的资源<BR><BR>当应用程序使用资源时,它按以下顺序查找资源:首先查找应用程序本身,看有没有对应的资源;如果没有,查找MFC400.DLL(或MFC400D.DLL,它包含调试信息)。再查找应用程序所带的动态连接库中的资源。如果想在DLL中直接使用资源而不经过以上搜索顺序,可以使用AfxGetResouceHandle()和AfxSetResourceHandle()函数。<BR><BR>AfxGetResourceHandle()和AfxSetResouceHandle()函数分别用来保存旧的资源句柄和设置新的资源句柄。比如,要想直接从DLL中载入一个位图资源,可以这么调用:<BR>
<>CBitmap mybitmap;<BR><BR>HINSTANCE hInstOld=AfxGetResourceHandle()<BR><BR>AfxSetResouceHandler(extensionDLL.hModule);<BR><BR>if(!mybitmap.LoadBitmap(IDR_BITMAP));<BR><BR>{<BR><BR>//restore the old resouce chain and return error<BR><BR>AfxSetResouceHandle(hInstOld);<BR><BR>return FALSE;<BR><BR>}<BR><BR>AfxSetResouceHandle(hInstOld);<BR><BR>//use this bitmap...<BR><BR>return TRUE;<BR><BR>还可以使用FindResource()搜索资源表,寻找给定的资源。<BR><BR>HRSRC FindResource(<BR><BR>HMODULE hModule,<BR><BR> <BR><BR>LPCTSTR lpName, <BR><BR> <BR><BR>LPCTSTR lpType <BR><BR>);</P>
<><BR>FindResource带三个参数,第一个参数是模块句柄,第二个是要查找的资源名字,如“MYDIALOG”,第三个是资源类型,可参见Visual C++文档。如果查找成功,则返回该资源句柄。可以用LoadResouce以该句柄为参数装入资源。<BR>小 结<BR><BR>本章介绍了用户模块的创建和使用。<BR><BR>用户模块是由用户自己开发的、可以加入到最终用户应用程序中提供某一特定功能的函数和类的集合。<BR><BR>用户模块包括静态连接库和动态连接库两大类:静态连接库将函数的目标代码直接连入到应用程序中;动态连接库只是给出函数入口信息,在调用时访问DLL文件中函数的目标代码。<BR><BR>创建静态连接库:指定工程类型为Win32 Static Library,加入函数声明和定义,并编译和连接。提交函数库时只需要提供函数的lib文件和头文件。要使用静态库,可以将函数库和头文件包含在工程文件中。<BR><BR>创建动态连接库:提供函数定义、声明以及包含DLL文件函数信息的DEF文件。使用时需要将DLL文件拷贝至适当目录下。<BR><BR>两类动态连接库的创建:用户动态连接库和MFC扩展库。<BR></P>
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2025-2-6 01:53

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表