c++调用与创建动态链接库(dll)

概述(废话)

应用程序使用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;
}

欢迎批评指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值