DLL编程总结
进行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编程总结的更多相关文章
- VC++动态链接库(DLL)编程深入浅出(zz)
VC++动态链接库(DLL)编程深入浅出(zz) 1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用 ...
- 基于Visual C++6.0的DLL编程实现
整理自基于Visual C++6.0的DLL编程实现 本文通过通俗易懂的方式,全面介绍了动态链接库的概念.动态链接库的创建和动态链接库的链接,并给出个简单明了的例子,相信读者看了本文后,能够创建自己的 ...
- MFC下DLL编程(图解)
MFC下DLL编程(图解) DLL(Dynamic Link Library,动态链接库)是微软公司为Windows和OS/2操作系统设计一种供应用程序在运行时调用的共享函数库.DLL是应用程序的一种 ...
- VC++动态链接库(DLL)编程深入浅出
1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量.函数或类.在仓库的发展史上经历了“无库-静 ...
- Delphi下DLL编程知识(转)
一. DLL和系统变量 在 System 单元声明的变量中,有几个对DLL编程有特殊影响.IsLibrary 可以检测代码是执行在应用程序中还是执行在DLL中,在应用程序中 IsLibrar ...
- 重要:VC DLL编程
VC DLL编程 静态链接:每个应用程序使用函数库,必须拥有一份库的备份.多个应用程序运行时,内存中就有多份函数库代码的备份. 动态连接库:多个应用程序可以共享一份函数库的备份. DLL的调用方式:即 ...
- 深入Delphi下的DLL编程
深入Delphi下的DLL编程 作者:岑心 引 言 相信有些计算机知识的朋友都应该听说过“DLL”.尤其是那些使用过windows操作系统的人,都应该有过多次重装系统的“悲惨”经历——无论再怎样小心, ...
- 在DLL编程中,导出函数为什么需要extern "C"
转自:http://blog.csdn.net/zhongjling/article/details/8088664 一般来讲,在DLL编程过程中,对于导出的函数前 都需要加入 extern “C”, ...
- VC++动态链接库(DLL)编程深入浅出(四)
这是<VC++动态链接库(DLL)编程深入浅出>的第四部分,阅读本文前,请先阅读前三部分:(一).(二).(三). MFC扩展DLL的内涵为MFC的扩展,用户使用MFC扩展DLL就像使用M ...
- VC++动态链接库(DLL)编程深入浅出(一)
1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量.函数或类.在仓库的发展史上经历了“无库-静 ...
随机推荐
- JS 拷贝传值和引用传值
1.拷贝传值:基本数据类型都是“拷贝传值”. 拷贝传值,就是将一个变量的值“拷贝”一份,传给了另一个变量. 拷贝传值中,两个变量之间没有任何联系,修改其中一个变量的值,另一个不会改变. 这两个变量之间 ...
- socket远程执行命令
两个脚本模拟远程执行命令 cmd_server.py import socket import subprocess # 运行系统命令 sk = socket.socket() addess = (' ...
- 第十九篇:Mysql两次Group by和ip转数字作比较的一次优化
业务场景:两张表,ipconfig_group表存了单位和 ip 起始段信息 visit_info表存储了访问次数,失败次数,访问流量,用户ip等信息 两张表的关系为: 一个部门下有若干ip段, ...
- Team Train Recorder 2.0
Bubble Cup 12 - Finals Online Mirror, unrated, Div. 1 2019/10/4, solved 4/9, upsolved
- 最难的工作 /// SPFA模板 oj1396
题目大意: Input 第一行是一个整数T ( T ≤ 100 ),表示测试用例的个数. 每个测试用例的第一行是两个整数 n 和 m ( 1 ≤ n ≤ 200 , 0 ≤ m ≤ 10000 ),分 ...
- iOS开发系列-Block本质篇
概述 在iOS开发中Block使用比较广泛,对于使用以及一些常规的技术点这里不再赘述,主要利用C++角度分析Block内部数据底层实现,解开开发中为什么这样编写代码解决问题. Block底层结构窥探 ...
- eclipse 克隆 https 地址的 Git 仓库报错:cannot open git-upload-pack
解决方法:Window >Preferences >Team>Git>User settings点击Add Entry设置key:http.sslVerify value:fa ...
- Android开发 Html工具类详解
前言 在一些需求富文本显示或者编辑的开发情况下,数据都是用html的格式来保存文本信息的.而google是有提供解析html的工具类那就是Html.有了Html可以让TextView也支持富文本(其实 ...
- JavaWeb实现文件下载
1. 编写文件上传Servlet public class FileUpload1 extends HttpServlet { @Override protected void doGet(HttpS ...
- odoo js
1.相关库/框架 主要:jQuery(使用1.8.3,如果使用新版本,其他jQuery插件也要升级或修改).Underscore.QWeb 其他:都在addons\web\static\lib路径下. ...