进行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. JS while 循环

    while循环:只要条件成立,就重复不断的执行循环体代码 while(条件判断) { 如果条件为true,则执行循环体代码 } while循环结构说明:   在循环开始前,必须要对变量初始化(声明变量 ...

  2. LightOJ-1007-Mathematically Hard-欧拉函数打表+前缀和+预处理

    Mathematically some problems look hard. But with the help of the computer, some problems can be easi ...

  3. QT之QComboBox

    1.addItems需要注意的事项: 1.在QT中设置maxVisibleItems的值,设置Items的最大可显示的值.(一般默认为10) 2.在每次需要清除已经添加的tems的时候需要注意,ui. ...

  4. 【转】5G标准——独立组网(SA)和非独立组网(NSA)

    独立组网模式(SA):指的是新建5G网络,包括新基站.回程链路以及核心网.SA引入了全新网元与接口的同时,还将大规模采用网络虚拟化.软件定义网络等新技术,并与5GNR结合,同时其协议开发.网络规划部署 ...

  5. UASCO Cow Pedigrees /// oj10140

    题目大意: 输入n,m :二叉树 输出 n个点分为m层 的方案数: 每个点的分支要么是0要么是2 Sample Input 5 3 Sample Output 2 即 两个方案为          O ...

  6. 2019-5-29-Roslyn-让-VisualStudio-急速调试底层库方法

    title author date CreateTime categories Roslyn 让 VisualStudio 急速调试底层库方法 lindexi 2019-5-29 20:2:9 +08 ...

  7. 【学术篇】NOIP2016 D1T3 luogu1850换教室

    题目链接:点击这里献出你宝贵的时间(是用来做题不是捐赠Emmmm).. Emmmm我太弱了= = 做完这题我觉得我应该去打星际..这题怎么就有重边了呢.. 这题就是一道期望= =当时考场上好像完全不会 ...

  8. linux的mysql权限错误导致看不到mysql数据库

    1.首先停止mysql服务:service mysqld stop2.加参数启动mysql:/usr/bin/mysqld_safe --skip-grant-tables & 然后就可以无任 ...

  9. 小米手机 DELETE_FAILED_INTERNAL_ERROR Error while Installing APKs

    手机:小米2s,MIUI 9 7.11.16 开发版 手机已处于开发者模式,启用了USB调试,已使用USB线连接了手机,在Android Studio 工具栏点击 "Run ‘app’(Sh ...

  10. html--图片背景兼容,兼容IE6

    在IE6中对图片格式png24支持度不高, 如果使用的图片格式是png24,则会导致透明效果无法正常显示 解决方法: 1.可以使用png8来代替png24,即可解决问题, 但是使用png8代替png2 ...