VC2005创建和加载.DLL文件的方法
来源:互联网 发布:高会军 争议 知乎 编辑:程序博客网 时间:2024/05/22 04:58
转自:http://blog.sina.com.cn/s/blog_6a0cb8bc0100uzhn.html
动态链接库(DLL)简介
动态库
DLL文件的创建
这是工程中会自动添加一个与工程名称一样的.cpp文件
删除编译器自动产生的代码
然后自己添加需要实现的函数(包括函数体)
例如:
然后编译....
完成后会出现如下提示
此时直接点击取消即可,这是就能在工程目录中找到DLL文件了,但是此时没有.lib文件
DumpBin命令
可以首先进入到目标DLL文件的目录下,然后运行Dumpbin命令
例如:
dumpbin -exports testDll.dll
这里没有看见任何与函数相关的信息,这说明testDll.dll中没有导出的函数
从DLL中导出函数
于是需要修改原函数定义为
然后编译,通过dumpbin命令即可查看导出的函数了
此时又生成了两个新文件,包含引入库(testDll.lib)文件和输出库(testDll.exp)文件..lib中保存的就是相对应的.dll文件中导出的函数和变量的符号名,输出库不重要.
通过dumpbin命令查看
dumpbin -exports testDll.dll
这里多出来的一些输出信息,一共有4列
ordinal:"1"和"2"是导出函数的序号;
hint:列出的数字是提示码,该信息不重要.
RAV:列出的地址值是导出函数在DLL模块中的位置,也就是说,通过该地址值,可以在DLL中找到他们.
name:列出的是导出函数的名称,这里的函数名称比较奇怪,这是因为C++重载函数的原因,因为冲在函数有相同的函数名,为了加以区分,C++编译器在编译链接的时候会按照自己的规则篡改函数名称,这一过程称为"名字改编"
加载DLL链接库
例
extern int add(int a,int b);
extern int subtract(int a,int b);
这时候编译...
会出现三个错误,都是发生在链接阶段
看来是因为没有加入dll的原因,因为程序无法找到add和subtract的函数主体,没法调用
为了解决这个问题可以将目标原先创建的引入库(.lib)文件复制到Dlltest项目所在的目录下,这这文件中就包含了testDll.dll中的导出函数的符号名.
先找到准备移动的引入库文件
复制
引入完成后需要在VS2005工程属性中加入这个testDLL.lib文件,如下:
这时候再次编译的,则会成功的生成test2.exe可执行文件.也就是说,当应用程序需要调用某个动态链接库提供的函数时,在程序链接时只需要包含该动态链接库提供的输入库文件(.lib)就可以了.(函数的引入库.lib没有包含实际的代码,他只是用来为链接程序提供必要的信息,以便在可执行文件中建立动态链接时需要用到的重定位表)
仍然可以通过dumpbin查看可执行(.exe)文件的输入信息以及其加载DLL的信息
dumpbin -imports test2.exe
从图中的输入信息可以看到,test2.exe程序需要调用到的testDll.dll链接库中的两个函数:add和subtract,另外还可以从中看到一些需要用到的其他DLL文件以及其中所需要用到的函数,并不是dll中的所有函数这个文件都会用上
注意:这里是通过复制.lib的方法使程序编译成功的,另外一种方法是可以在VS2005项目属性中设置相应的属性完成对.lib文件的引用,这样就不用复制.lib文件到项目所在目录中了,上图:
然后继续像第一种方法一样在输入中加入testDll.lib即可
再次运行test2.exe程序,但发现程序会弹出如下图所示的错误对话框,提示无法找到testDll.dll文件
这涉及到.dll文件的加载顺序规则问题了,当引用程序运行的时候,系统将为它分配一个4GB的地址空间,然后加载模块会分析该应用程序的输入信息,从中找到该程序要访问动态链接库信息,然后在用户机器上搜索这些动态链接库,进而加载他们.搜索的顺序如下:
1.程序的运行目录,即.exe所在的目录:
例如
即.exe所在的目录
2.当前目录
3.系统目录:
4.path环境变量中所列出的路径
其实总结起来,就是按照path环境变量来处理.dll的加载规则的
利用_declspec(dllimport)声明外部.dll中的函数
除了使用extern关键字声明函数是外部定义的函数外,还可以使用_declspec(dllimport)来声明函数是从动态链接库中引入的.例如:
_declspec(dllimport) int add(int a,int b);
_declspec(dllimport) int subtract(int a,int b);
然后编译....
一样可以运行,与使用extern关键字这种方式比,使用_declspec(dllimport)声明的外部函数会告诉编译器该函数是从动态链接库中引入的,编译器可以生成运行效率更高的代码.
完善DLL例子
一个dll实现之后通常都会交给客户程序,以便后者能够访问该dll.但是客户端程序如何知道该dll中有哪些导出函数呢?通常在编写动态链接库时都会提供一个头文件,在此文件中提供的dll导出函数原型的声明,以及函数的有关注释文档.这样可以在工程中添加一个头文件testDll.h
内部添加
_declspec(dllimport) int add (int a,int b);
_declspec(dllimport) int subtract(int a,int b);
这里注意testDll.h是给该dll的客户端,即调用该dll的程序使用,就是这里的test2.exe,因此在声明的函数头部使用的是"dllimport"关键字,向客户端程序表明他们是从动态链接库中导入的.
然后在test2工程中加入头文件testDll.h,在程序的头部加入#include"testDll.h"随即可以使用了
这里可以对testDll.h进行改造,使其不仅能够为调用动态链接库的客户端程序服务,同时也能够由动态链接库程序自身来使用:
#ifndef
#define DLL_API _delcspec(dllimport)
#endif
DLL_API int add(int a,int b);
DLL_API int subtract(int a,int b);
接下来,在动态链接库的源程序:testDll.cpp文件中首先利用#define指令定义DLL_API宏,然后在用#include"testDll.h"包含上述的头文件,之后在定义add和subtract函数时就不用再指定_declspec(dllimport)了,如下
#define DLL_API _declspec(dllexport)
#include "testDll.h"
int add(int a,int b);
int subtract(int a,int b);
在程序编译的时候头文件是不参与编译的,源文件单独编译.
从DLL中导出C++类
跟函数情况基本相同,是在class 和类名之间加入导出标识符DLL_API宏,这样就能导出整个类了.
但是像private和protected在外界是无法访问的,只有public能直接访问
#ifndef DLL_API
#define DLL_API _declspec(dllimport)
#else
#define DLL_API _declspec(dllexport)
class DLL_API Point{
}
而其余的步骤与只包括函数的dll文件是一样的,即把一个class当做一个function处理即可!~
- VC2005创建和加载.DLL文件的方法
- VC中创建DLL文件的方法和步骤
- 创建DLL文件 以及 动态加载和静态加载 以及两者之间的区别
- 创建自己的dll和lib文件
- 创建自己的dll和lib文件 .
- vs2013 dll 文件的创建和引用
- vs2013 dll 文件的创建和引用
- vs2013 dll 文件的创建和引用
- VC2005文件的读写
- 在VC中创建DLL文件的方法步骤--DLL文件与exe文件的区别
- 在VC中创建DLL文件的方法步骤
- 在VC中创建DLL文件的方法步骤
- 在VC中创建DLL文件的方法步骤
- 在VC中创建DLL文件的方法步骤
- 【转】在VC中创建DLL文件的方法步骤
- 【转】在VC中创建DLL文件的方法步骤
- 使用VS2008创建一个DLL文件的方法
- 创建DLL文件,封装窗体的实现方法实例
- linux rcu
- 利用ContentProvider机制读写联系人信息。
- Android异步下载网络图片(其一Handler)
- 猫猫学iOS之tableView的下拉放大图片的方法
- 为什么需要内存屏障
- VC2005创建和加载.DLL文件的方法
- [Leetcode]Single Number II
- svn下本地工程在服务器上的url以及信息
- android shape的使用
- Sublime Text 2 支持GB2312和GBK
- 硬链接 and 软链接
- 栈的应用-表达式求值-数据结构
- java.util.concurrent之CountDownLatch
- 无锁编程(二) - 原子操作