概述(废话)
应用程序使用DLL可以采用两种方式:一种是隐式链接,另一种是显式链接。
用它可以查看DLL文件中的函数结构,但是无法查看函数的入口参数.网上也很容易下载到dll查看工具.
另外,Windows系统将遵循下面的搜索顺序来定位DLL:
1.包含EXE文件的目录,
2.进程的当前工作目录,
3.Windows系统目录,
4.Windows目录,
5.列在Path环境变量中的一系列目录
参考文章:
http://www.cnblogs.com/fengzheng/archive/2013/07/17/3186677.html
http://www.cnblogs.com/laogao/archive/2012/12/07/2806528.html
创建dll:
以下工程均在visual stdio 2015 下创建
打开vs2015 单击文件->新建->项目.选择WIN32控制台应用程序->空工程,工程名为ExportDll
工程建好后,选中工程->添加->新建项 新建main.cpp和main.h两个文件
声明一个函数,注意要在头文件的声明中加上"_declspec(dllexport)"
main.h
#pragma once
_declspec(dllexport) int add(int a, int b);
main.cpp
#include"main.h"
int add(int a, int b) {
return a + b;
}
点击工具栏绿色三角进行编译,可能会出现如下警告,但是没什么影响
然后在工程所目录下的Release的文件下找到ExportDll.dll 这个就是刚才导出的dll(ExportDll.lib和ExportDll.dll在同一级目录下),接着用函数查看器查看一下ExportDll.dll ,发现导出的函数名和我们头文件中声明的并不一致.
这是因为在C++中存在函数的重载,允许函数重名,因此在编译器生成dll的时候,为了区别重名的程序,会将其进行一定算法进行名称转换,后面会写到如何让函数名在导出的时候不被修改.
显式调用dll(建议使用):
显式链接应用程序编译时不需要使用相应的Lib文件。
新建一个普通win32控制台工程,在工程中添加main.cpp
main.cpp中需要包含头文件Windows.h,原因在于程序中用到了LoadLibrary、FreeLibrary、GetProcAddress等Win32 API函数。
main.cpp:
int main(){
typedef int( *pAdd)(int a,int b);//使用类型定义关键字typedef,定义指向和DLL中相同的函数原型指针.
PAdd Add ;
HMODULE HDLL=LoadLibrary("ExportDll.dll"); //加载动态链接库dllname.dll文件, 返回当前DLL文件的句柄
Max=(pMax)GetProcAddress(hDLL,"?add@@YAHHH@Z"); //通过指定函数名来获得函数地址(方法一)
//也可以通过指定函数在dll中的顺序来获得函数地址(方法二)
//Max=(pMax)GetProcAddress(hDLL,MAKEINTRESOURCE(1));
int sum=Add(1,2);
cout<<"sum="sum;
FreeLibrary(HDLL); // 使用FreeLibrary()释放DLL
}
在定义函数指针的时候,最好像这样: typedef int(__stdcal *pAdd)(int a,int b);
在括号中加上__stdcall,这是因为如果对外提供api,供其它非C++程序使用时,调用方会无法清栈而出错。因此,对外提供api时还应该将接口声明为__stdcall,让api函数自己清栈。
注意:dll 默认路径为工程文件夹/debug/目录下,也可以在LoadLibrary中指定dll所在绝对路径
可以看到,如果导出的函数名不规范的话,通过指定函数名来调用函数非常麻烦,而且容易出错,有以下两种方式可以对导出的函数名进行规范化
方法一:用extern "C"修饰函数,也就是把头文件中的声明改为如下形式
extern "C"
{
_declspec(dllexport) int __stdcall Add(int a,int b);
}
再次编译,然后查看导出的函数名
方法二 使用模块定义文件.def
在解决方案管理器中选中ExportDll工程,右键->添加->新建项->代码->模块定义文件(.def)->添加
在source.def中添加以下代码
LIBRARY ExportDll
EXPORTS
Add;
注意:如果在实际工程中使用,在编译之前,要把Debug模式,改为Release模式,否则会出现无法预料的错误
隐式调用Dll
隐式链接调用过程相对简单
只需把显式调用中的代码换成以下形式
//....
#pragma comment(lib,"ExportDll.lib")
extern "C"_declspec(dllimport) int Add(int a,int b);
//....
int main()
{
int sumr=Add(10,8);
cout<<"sum="Add;
}
欢迎批评指正