进行DLL的编程主要涉及到两个方面的问题,一个是要保证DLL中要导出的函数名不被编译器不可控地更改(在C++中由于重载机制的存在,会造成程序被编译时函数名被改变),其实就是要保证DLL导出的函数名与使用DLL时引用的函数名一致;另一个是怎样在应用程序中使用DLL的问题,实质就是怎样生成一个引用DLL的可执行程序的问题。解决这两个问题都有两种方法。下面就这两个问题进行详细讨论。

一、DLL导出函数的两种方法

DLL是包含若干个函数的库文件,其中包括内部函数和外部函数两种。前者用于DLL内部实现的调用,外部应用程序无法引用;后者则是提供给外部应用程序引用的函数,从而体现DLL的作用。应用程序在使用DLL中的函数之前,应该先导出欲发布的函数(即形成外部函数),这样才应用程序才能使用。要导出这些函数有两种方法,一是在定义函数时使用导出关键字__declspec(dllexport);另外一种方法是在创建DLL文件时使用模块定义文件.Def。下面通过两个例子来说明如何使用这两种方法创建DLL文件。

方法1:使用导出函数关键字__declspec(dllexport)创建MyDll.dll,该动态链接库中有一个函数,实现对两个数做加法。在MyDll.h和MyDLL.cpp文件中代码如下:

//MyDLL.h
#ifndef MYDLL
#define MYDLL extern "C" __declspec(dllimport)
#endif
MYDLL int Add(int a,int b);
//MyDll.cpp
#define MYDLL extern "C" __declspec(dllexport) #include"MyDll.h"
int Add(int a, int b)
{
return a+b;
}

该动态链接库编译成功后,在MyDll工程中的debug目录下,可以看到MyDll.dll、MyDll.lib两个文件。LIB文件中包含DLL文件名和DLL文件中的函数名等,该LIB文件只是对应该DLL文件的"映像文件",与DLL文件相比,LIB文件的长度要小的多,在采用隐式链接DLL时要用到它。对于MyDll.h中的extern"C"修改符。只有当你编写C++代码而不是直接编写C代码时,才能使用这个修改符。通常来说,C++编译器可能会改变函数和变量的名字,从而导致严重的连接程序问题。如果使用extern"C",就可以告诉编译器不要改变变量名或函数名,这样,变量和函数就可以供使用C、C++或其他任何编程语言编写的可执行模块来访问。

方法2用.def文件创建工程MyDll。.def文件为链接器提供了有关被链接程序的导出、属性及其他方面的信息。使用.def文件创建DLL,就不需要再在上个例子创建的工程中的MyDll.h文件中包括extern"C"_declspec(dllexport)声明部分了。在该工程中加入一个文本文件,命名为MyDll.def,再在该文件中加入如下代码:

LIBRARY MyDll
EXPORTS
Add @

其中LIBRARY语句说明该def文件是属于相应DLL的,EXPORTS语句下列出要导出的函数名称。我们可以在.def文件中的导出函数后加@n,如Add@1,表示要导出的函数顺序号,在进行显式连时可以用到它。该DLL编译成功后,打开工程中的Debug目录,同样也会看到MyDll.dll和MyDll.lib文件。

二、使用DLL的两种方法(DLL的链接)

应用程序使用DLL可以采用两种方式:一种是隐式链接,另一种是显式链接。在使用DLL之前首先要知道DLL中函数的结构信息。VisualC++6.0在VC\bin目录下提供了一个名为Dumpbin.exe的小程序,用它可以查看DLL文件中的函数结构。另外,Windows系统将遵循下面的搜索顺序来定位DLL:

1.包含EXE文件的目录

2.进程的当前工作目录

3.Windows系统目录

4.Windows目录

5.列在Path环境变量中的一系列目录。

方法1: 隐式链接

隐式链接就是在程序开始执行时就将DLL文件加载到应用程序当中。实现隐式链接很容易,简单地说,只要将导入函数关键字__declspec(dllimport)函数名写到应用程序相应的头文件中就可以了(如果DLL是按照上面的方式一导出函数,并且在头文件已经考虑了dllimport声明的情况,自然就不需要再在应用程序中加此关键字了)。具体操作步骤如下:

(1)当创建可执行源代码文件时,必须加上DLL的头文件。如果没有头文件,输入的符号将不会被定义,这样编译器编译就会无法通过。其实这样做,编译器只是想确保你用正确的方法访问这些输入的符号。——DLL的头文件,供编译程序使用;

(2)接下来,链接程序将所有的.obj模块组合起来,生成可执行模块。该链接程序必须确定哪些DLL包含代码所引用的所有输入符号。这由DLL相应的.lib提供。因此必须将DLL的.lib文件传递给链接程序。——DLL的.lib文件,供链接程序使用;

下面的例子通过隐式链接调用MyDll.dll库中的Add函数。

//TestDll.cpp

#include
#include"MyDll.h"//上面定义的DLL对应的头文件
#pragmacomment(lib,"MyDll.lib") //保证应用程序在链接时能链接成功
void main()
{
printf("%d\n",Add(,));
}

在创建DllTest.exe文件之前,要先将MyDll.h和MyDll.lib拷贝到当前工程所在的目录下面,这样才能编译生成DllTest.ext;而在生成DllTest.exe文件后,无论是隐式还是显示链接,都只需将MyDll.dll文件拷贝到DllTest.exe所在目录,DllTest.exe就能加载到DLL文件,从而正常执行。当然,按照前面提到的应用程序搜索定位DLL的顺序,也可以将DLL放到其他目录如windows的System下。

如果DLL使用的是def文件,要删除TestDll.h文件中关键字extern "C"。TestDll.h文件中的关键字Progamcommit是要Visual C+的编译器在link时,链接到MyDll.lib文件,当然,开发人员也可以不使用#pragmacomment(lib,"MyDll.lib")语句,而直接在工程的Setting->Link页的Object/Moduls栏加入MyDll.lib既可。

方法2: 显式链接

显式链接是应用程序在执行过程中随时可以加载DLL文件,也可以随时卸载DLL文件,这是隐式链接所无法作到的,所以显式链接具有更好的灵活性,对于解释性语言更为合适。在应用程序中用LoadLibrary或MFC提供的AfxLoadLibrary显式的将需要的动态链接库调进来,此后再用GetProcAddress()获取想要引入的函数的地址。自此,你就可以像使用在应用程序自定义的函数一样来调用此引入函数了。在应用程序退出之前,应该用FreeLibrary或MFC提供的AfxFreeLibrary释放动态链接库。下面是通过显式链接调用DLL中的Add函数的例子。

#include
#include
void main(void)
{
typedef int(*pAdd)(int a,int b);
HINSTANCE hDLL;
pAdd Add;
hDLL=LoadLibrary("add.dll");//加载动态链接库MyDll.dll文件;
Add=(pAdd)GetProcAddress(hDLL,"add");
printf("%d\n",Add(,));
FreeLibrary(hDLL);//卸载MyDll.dll文件;
}

在上例中使用类型定义关键字typedef,定义指向和DLL中相同的函数原型指针,然后通过LoadLibray()将DLL加载到当前的应用程序中并返回当前DLL文件的句柄,然后通过GetProcAddress()函数获取导入到应用程序中的函数指针,函数调用完毕后,使用FreeLibrary()卸载DLL文件。同样,在运行程序时,需要先将DLL文件拷贝到系统能够搜到DLL文件的路径下。

使用显式链接的应用程序在编译生成时不需要使用前面提到的任何Dlltest.h头文件以及Lib文件。另外,使用GetProcAddress()函数时,可以利用MAKEINTRESOURCE()函数直接使用DLL中函数出现的顺序号,如将GetProcAddress(hDLL,"Add")改为GetProcAddress(hDLL,MAKEINTRESOURCE(1))(函数Add()在DLL中的顺序号是1),这样调用DLL中的函数速度很快,但是要记住函数的使用序号,否则会发生错误。

三、一点补充说明 

编译生成dll文件后,我们同时得到lib文件。这个lib和静态链接库的lib文件是完全不一样的:

静态链接库的lib文件包含实现的二进制码,链接后就不要lib的支持了,lib中的代码会合并到exe文件中。

dll输出的lib,链接后还要dll的支持。因为它仅含导出函数的地址和一些位址信息,而不包括实现信息,这可以帮助Link程序完成连接(在此时安排调用入口地址及函数回调信息),调用模块可以模拟这个lib去修改相应的import项。这样,在运行时才能将DLL中真正的代码调入执行,实现动态连接。

参考文献:Windows核心编程

DLL编程总结的更多相关文章

  1. VC++动态链接库(DLL)编程深入浅出(zz)

    VC++动态链接库(DLL)编程深入浅出(zz) 1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用 ...

  2. 基于Visual C++6.0的DLL编程实现

    整理自基于Visual C++6.0的DLL编程实现 本文通过通俗易懂的方式,全面介绍了动态链接库的概念.动态链接库的创建和动态链接库的链接,并给出个简单明了的例子,相信读者看了本文后,能够创建自己的 ...

  3. MFC下DLL编程(图解)

    MFC下DLL编程(图解) DLL(Dynamic Link Library,动态链接库)是微软公司为Windows和OS/2操作系统设计一种供应用程序在运行时调用的共享函数库.DLL是应用程序的一种 ...

  4. VC++动态链接库(DLL)编程深入浅出

    1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量.函数或类.在仓库的发展史上经历了“无库-静 ...

  5. Delphi下DLL编程知识(转)

    一.  DLL和系统变量     在 System 单元声明的变量中,有几个对DLL编程有特殊影响.IsLibrary 可以检测代码是执行在应用程序中还是执行在DLL中,在应用程序中 IsLibrar ...

  6. 重要:VC DLL编程

    VC DLL编程 静态链接:每个应用程序使用函数库,必须拥有一份库的备份.多个应用程序运行时,内存中就有多份函数库代码的备份. 动态连接库:多个应用程序可以共享一份函数库的备份. DLL的调用方式:即 ...

  7. 深入Delphi下的DLL编程

    深入Delphi下的DLL编程 作者:岑心 引 言 相信有些计算机知识的朋友都应该听说过“DLL”.尤其是那些使用过windows操作系统的人,都应该有过多次重装系统的“悲惨”经历——无论再怎样小心, ...

  8. 在DLL编程中,导出函数为什么需要extern "C"

    转自:http://blog.csdn.net/zhongjling/article/details/8088664 一般来讲,在DLL编程过程中,对于导出的函数前 都需要加入 extern “C”, ...

  9. VC++动态链接库(DLL)编程深入浅出(四)

    这是<VC++动态链接库(DLL)编程深入浅出>的第四部分,阅读本文前,请先阅读前三部分:(一).(二).(三). MFC扩展DLL的内涵为MFC的扩展,用户使用MFC扩展DLL就像使用M ...

  10. VC++动态链接库(DLL)编程深入浅出(一)

    1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量.函数或类.在仓库的发展史上经历了“无库-静 ...

随机推荐

  1. 面试系列17 redis cluster

    1.redis cluster介绍 redis cluster (1)自动将数据进行分片,每个master上放一部分数据(2)提供内置的高可用支持,部分master不可用时,还是可以继续工作的 在re ...

  2. UBOOT的的 C 语言代码部分

    调用一系列的初始化函数 1. 指定初始函数表: init_fnc_t *init_sequence[] = { cpu_init,           /* cpu 的基本设置         */ ...

  3. linux及windows安装maven

    一.linux安装maven 1.wget http://mirror.bit.edu.cn/apache/maven/maven-3/3.6.1/binaries/apache-maven-3.6. ...

  4. [NOIP2019模拟赛]数数(gcd)

    题目大意: 求l~r中有多少数与x互质,带单点修改 分析: 两个30的部分分很好打: ·n<=1000暴力O(nq)就好了 ·$a_i<=100$用树状数组维护每个x的前缀和就好了 100 ...

  5. AM历史消息及文件记录删除

    1.下载 folderclear.bat 文件 2.用编辑方式打开这个文件 3.对里面的参数做修改 4.这个批处理文件,保留了 完整的一个月的消息记录 (如 今天是 2017.3.15 ,那么 清除数 ...

  6. thinkphp 视图定义

    视图定义 视图通常是指数据库的视图,视图是一个虚拟表,其内容由查询定义.同真实的表一样,视图包含一系列带有名称的列和行数据.但是,视图并不在数据库中以存储的数据值集形式存在.行和列数据来自由定义视图的 ...

  7. order方法属于模型的连贯操作方法之一

    order方法属于模型的连贯操作方法之一,用于对操作的结果排序. 用法如下: $Model->where('status=1')->order('id desc')->limit(5 ...

  8. 一个windows 两个jar

    设置两个子JAVA_HOME,一个总设置两个子JAVA_HOME:JAVA_HOME6 = C:\Program Files\Java\jdk1.6.0_43JAVA_HOME8 = C:\Progr ...

  9. CDATA标签用法

    今天在xml文件里看到有CDATA标签的使用,   答案如下: CDATA 术语 CDATA 指的是不应由 XML 解析器进行解析的文本数据(Unparsed Character Data). 在 X ...

  10. 菜鸟nginx源码剖析数据结构篇(六) 哈希表 ngx_hash_t(上)[转]

    菜鸟nginx源码剖析数据结构篇(六) 哈希表 ngx_hash_t(上) Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.c ...