VS 静态链接lib和动态链接dll的使用以及error link2019无法解析外部符号和error link2001错误

VS 静态链接lib和动态链接dll的使用以及error link2019无法解析外部符号和error link2001错误

静态链接lib和动态链接dll

首先介绍一下静态库(静态链接库)、动态库(动态链接库)的概念,共同点在于代码共享。

静态库:在链接步骤中,链接器将从库文件取得所需的代码,复制到生成的可执行文件中,这种库称为静态库,其特点是可执行文件中包含了库代码的一份完整拷贝;缺点就是被多次使用就会有多份冗余拷贝。即静态库中的指令都全部被直接包含在最终生成的 EXE 文件中了。在vs中新建生成静态库的工程,编译生成成功后,只产生一个.lib文件

动态库:动态链接库是一个包含可由多个程序同时使用的代码和数据的库,DLL不是可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个 DLL 中,该 DLL 包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。在vs中新建生成动态库的工程,编译成功后,产生一个.lib文件和一个.dll文件

那么上述静态库lib和动态库中的dll有什么区别呢?

静态库中的lib:该LIB包含函数代码本身(即包括函数的索引,也包括实现),在编译时直接将代码加入程序当中

动态库中的lib:该LIB包含了函数所在的DLL文件和文件中函数位置的信息(索引),函数实现代码由运行时加载在进程空间中的DLL提供

总之,lib是编译时用到的,dll是运行时用到的。如果要完成源代码的编译,只需要lib;如果要使动态链接的程序运行起来,只需要dll。

编译时错误libVS 静态链接lib和动态链接dll的使用以及error link2019无法解析外部符号和error link2001错误

比如上面的错误都是属于编译错误,出现2019错误只会是两种状况:
1.比如错误56,是没有将包含此函数的文件包含进此项目中
2.没有加载相对应的lib库文件

运行时出错dll

症状:出现闪退现象,程序运行不起来却没报任何编译错误
这里有2个小工具分享
viewdll可以查看包含哪些dll
DLLCall可以查看dll文件是否可以加载成功

项目生成依赖顺序查看方式

VS 静态链接lib和动态链接dll的使用以及error link2019无法解析外部符号和error link2001错误
主要是看项目编译时包含哪些lib文件,优先生成所需要的文件。

导入和导出dll

#pragma once
//下面是本项目的导出接口CRYPT_API的宏定义,所有需要导出的函数标注上CRYPT_API就可以导出到DLL的导出列表里面
//这样别的项目和exe才能在dll的导出列表里搜索到该函数进行加载
#ifdef PROJECT2
#define CRYPT_API __declspec(dllexport)
#else	
#define CRYPT_API __declspec(dllimport)
#endif // PROJECT2
 
//如果是生成DLL的项目,一定要像下面这样写好接口定义。
//因为使用你DLL的人的范围很广,他们都不知道源代码,所以要清楚的写明传入参数的意义
//和返回值的类型
 
//函数描述:对一个int变量进行加密后将加密数据赋值给返回值。
//传参a:需要加密的int变量
//返回值:加密后的int值
CRYPT_API int CryptInt(int a);

现在解释下为什么要在Project2里加上一个PROJECT2的项目标识宏定义。首先,dll的导出和导入的关键字区分在于__declspec()的括号里面是dllexport(导出)还是dllimport(导入)。在本项目中我需要告诉VS这个函数是导出的,在其他项目中需要告诉VS这个函数是从别的dll里面导入的。但是不管哪个项目,使用的都是cryptint.h这个头文件,这时宏定义作为编译开关的作用就体现出来了。

在Project2的项目生成中,由于我们定义了PROJECT2的宏定义,所以CRYPT_API是被定义为__declspec(dllexport)。在别的项目中引用头文件cryptint.h时,由于并没有定义PROJECT2的宏定义,所以CRYPT_API被定义为__declspec(dllimport)。这样就做到了同一份header不同的声明。

写好以后直接生成解决方案,会在生成目录下出现一个Project2.dll文件。我们通过下面的方法来检验下cryptint是否导出成功:

可以把Project2.dll用viewdll程序打开,可以查看它的导出函数列表。这里我没有下载,就直接文本打开。这个dll文件的内容是hex形式,不是文本字符,所以有很多乱码不可读。但没关系,因为导出函数的名字一定是字符串形式,所以我们只要在文本中搜索我们的导出函数名“CryptInt”:

在我的网盘里有viewdll和dllcall小工具PS(不要忘记了)
参考博文:
https://blog.****.net/luoyu510183/article/details/83999548
https://www.cnblogs.com/TenosDoIt/p/3203137.html