博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
c++动态链接库的创建和使用
阅读量:4487 次
发布时间:2019-06-08

本文共 3158 字,大约阅读时间需要 10 分钟。

动态库

动态链接库(Dynamic Link Library,DLL)是Windows操作系统中实现共享函数库概念的一种方式,这些库函数的扩展名是 ”.dll”、”.ocx”(包含ActiveX控制的库);

在使用动态库的时候,往往需要提供两个文件:一个引人库(.lib)和一个DLL文件(.dll);

  1. 引人库(.lib)

    引入库是包含该dll导出的函数和变量的符号名,可以认为是函数和变量的声明;在编译和链接可执行文件时,需要引用引人库中的符号名;

  2. DLL文件(.dll)

    当可执行文件运行并且使用到DLL文件中的函数和变量时,系统才去加载相对应的DLL,并将DLL文件映射到进程的地址空间,然后去访问DLL文件中的导出函数;一句话,dll文件应用于程序运行时。


创建Win32 DLL文件

1.创建工程

在工程中右键添加新项目,项目类型:Win32,模板:Win32项目,输入Dll名字;在弹出的对话框中,选择应用程序类型为“DLL(D)选项”。如下图所示:

这里写图片描述

2.添加导出函数

应用程序如果想要访问某个dll中的函数,那么该函数必须是已经被导出的函数;设置方法如下:

需要在每一个被导出的函数前面增加标识符:_declspec(dllexport);

形如:_declspec(dllexport) int add(int a, int b);

按照指定格式添加其他的导出函数后,点击Build按钮就可以生成.lib文件和.dll文件;我将动态链接库的工程名命名为Sampledll,生成结果位于Ctest解决方案下的Debug目录:

这里写图片描述


隐式链接方式加载dll头

1.函数名字改编问题

由于C++语言中有函数重载特性,在实际目标文件中函数名会被编译器作特殊处理,比如目标文件的函数名会包含参数类型,而C语言则不会包含参数类型,比如:

int  add(int a, int b);//代码函数声明_add                   //C语言的目标文件函数名_add_int_int           //c++语言的目标文件函数名

为了C语言和C++都能调用dll文件中API函数,我们希望动态链接库文件在编译时,导出函数的名称不要发生变化,为了实现这个目的,在定义导出函数时,需要添加上限定符:extern “C”,C一定要大写

利用限定符:extern “C”可以解决C++和C语言之间相互调用时函数命名的问题,但是该方法只能用于导出全局函数,不能用于导出一个类的成员函数。

另外,如果导出函数的调用约定方式发生了变化,即使添加了限定符extern “C”,函数名字在编译dll时还会发生变化。

2.隐式加载dll方式

  1. 利用extern声明的外部函数,形如:

    extern int _stdcall add(int a, int b);

  2. 利用_declspec(dllimport)声明的外部函数

    _declspec(dllexport) int _stdcall add(int a, int b);

与extern关键字这种方式相比,使用_declspec(dllimport)标识符声明的外部函数时,它将告诉编译器该函数是从动态链接库中引入的,编译器可以生成运行效率更高的代码。因此,如果调用的函数来自于动态链接库,应该采用_declspec(dllimport)声明外部函数。

3.头文件设计

为了方便其他模块引用DLL文件中的API函数,我们在DLL工程中,添加Sampledll.h头文件;其他模块需要使用dll文件中的函数,则先添加Sampledll.h至本工程;

需要注意的,如果使用这种共享头文件的方式,一定要用_declspec(dllexport)声明的方式,否则没有.lib文件生成。

头文件内容如下:

#ifndef _SAMPLE_H_#define  _SAMPLE_H_#ifdef DLL_API    //内部调用#else    #define DLL_API extern "C" _declspec(dllexport)//外部调用#endif//接口APIDLL_API  int _stdcall add(int a, int b);DLL_API  int _stdcall  Multiply(int a,int b);#endif

4.使用动态链接库编程

我们创建一个MultiThread Win32控制台程序,并在该工程中使用dll文件中的API函数,主要关键步骤如下:

1. MultiThread工程中添加.lib文件;
2. 将.lib文件和dll文件放在MultiThread 工程目录下;
3. #include”Sampledll.h”

添加.lib文件参考文章。

在MultiThread 工程中,主要关键代码如下:

stdafx.h

#pragma once#include "targetver.h"#include 
#include
//新增内容,添加lib文件#pragma comment(lib, "..\\Debug\\SampleDll.lib")

MultiThread .cpp

#include "..\\SampleDll\\SampleDll.h"int _tmain(int argc, _TCHAR* argv[]){    cout << "add      func: " <<      add(2,4) << endl;    cout << "Multiply func: " << Multiply(2,4) << endl; }

运行结果:

这里写图片描述


显示加载方式加载dll

显示加载dll需要用到以下几个API函数,其函数声明如下:

//加载dll文件到进行地址空间HMODULE WINAPI LoadLibrary(  __in  LPCTSTR lpFileName);//获取导出函数的地址FARPROC WINAPI GetProcAddress(  __in  HMODULE hModule,  __in  LPCSTR lpProcName);//释放加载的dll文件BOOL WINAPI FreeLibrary(  __in  HMODULE hModule);//如果有DllMain函数,系统加载dll会调用该函数BOOL WINAPI DllMain(  __in  HINSTANCE hinstDLL,  __in  DWORD fdwReason,  __in  LPVOID lpvReserved);

需要注意的是,若dll中的导出函数采用的是标准调用约定时,则访问该dll的客户端程序也应该是采用标准调用约定的导出函数,两者需要一致。

导通加载dll时,客户端程序不再需要包含导出函数声明的头文件和引入库文件,需要的dll文件即可。

对于显示加载和隐式链接加载dll的区别如下:

  1. 隐式链接方式加载dll客户端调用简单、便捷;
  2. 在程序启动时,dll文件已经完成加载,并映射到进程的地址空间,可以随时的调用导出函数,没有调用的顺序要求;
  3. 若应用程序需要加载较多的dll文件,则更适用于显示加载dll方式,可以在需要用到某个dll的某个导出函数时,再加载dll,节约程序的启动时间。

最后,我们想要查看动态链接库导出信息的时,可以使用Dumpbin命令和Depends工具;

转载于:https://www.cnblogs.com/jinxiang1224/p/8468279.html

你可能感兴趣的文章
二叉搜索树(搜索二叉树)转换成一个双向链表
查看>>
(转)Linux 系统性能分析工具图解读(一、二)
查看>>
(转)python3之模块io使用流的核心工具
查看>>
阶乘模版
查看>>
ShellShock 攻击实验
查看>>
BAT及各大互联网公司前端笔试面试题--Html,Css篇
查看>>
Linux下的时间戳
查看>>
xpath的学习
查看>>
kvm系列之四:热添加技术
查看>>
grep命令
查看>>
powershell的stable和preview版本
查看>>
DateTime
查看>>
火狐浏览器设置bypass
查看>>
XMLHttpRequest 对象
查看>>
C语言中的循环结构与选择结构
查看>>
加锁解锁PHP实现 -转载
查看>>
java Object类的公共方法
查看>>
floodlight make the VMs can not getDHCP IP address
查看>>
利用unittest+ddt进行接口测试(二):使用yaml文件管理测试数据
查看>>
11 个创新的网站滑动效果设计案例展示
查看>>