静态链接库

定义

静态链接库(Static Linking Library)是一种库文件,其中包含可重定位的二进制代码,以及与这些代码相关的数据和函数定义。在编译时,这些代码被静态地链接到程序的可执行文件中,以创建一个完全独立的可执行文件,该文件不需要在运行时与外部库文件进行交互,但也使得程序的可执行文件变得更大

创建静态库

Visual Studio新建项目时选择静态库, 然后再创建一个头文件StaticLib1.h

以下分别是StaticLib1.hStaticLib1.cpp的代码,StaticLib1.h用来声明静态库的函数,StaticLib1.cpp用来定义静态库的函数

//StaticLib1.h
pragma onceclass MyClass {public:int add(int x, int y);
};
// StaticLib1.cpp
include "pch.h"
include "framework.h"
include "StaticLib1.h"int MyClass::add(int x, int y)
{return x+y;
}

然后鼠标右键项目处生成StaticLib1.lib文件

调用静态库函数

方法一

若要调用静态库的函数, 需将静态库的头文件StaticLib1.h和库文件StaticLib1.lib复制到项目目录里

随后在项目添加引入头文件和引用库文件的代码, 如下所示

include <iostream>
include <windows.h>
include "StaticLib1.h"  //导入头文件
pragma comment(lib,"StaticLib1.lib")  //引用库文件int main()
{   MyClass myclass;std::cout << myclass.add(1, 2);
}

方法二

将头文件和库文件复制到VS安装目录,与系统库文件放在一起,如下是我Visual Studio的系统库目录

E:\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\lib  //系统库文件
E:\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.16.27023\include  //系统头文件

点击项目属性->链接器->输入, 在附加依赖项添加库文件

然后就可以像使用系统库函数那样来调用我们的静态库函数, 而无需将库文件和头文件放到项目目录里面, 如下代码所示

include <iostream>
include <windows.h>
include <StaticLib1.h>  //导入头文件int main()
{   MyClass myclass;std::cout << myclass.add(1, 2);
}

动态链接库

定义

动态链接库(Dynamic Linking Library),也被称为共享库(Shared Library),是一种可以在运行时动态加载并链接的库文件。与静态链接库不同,动态链接库的代码在程序运行时才会被加载到内存中,因此动态链接库相对于静态链接库来说更加灵活,且不会使目标可执行文件变得过于庞大

使用动态链接库的可执行文件在运行时需要依赖相应的动态链接库文件(通常是以.dll为后缀名),因为动态链接库的代码在程序运行时才会被加载到内存中

创建动态库

有两种方法来声明动态链接库的导出函数,方法一通过定义宏来实现, 方法二通过创建.def文件来实现

方法一

如下代码用于定义导出函数的宏以及声明导出函数。其中, __declspec(dllexport)用于导出DLL函数,这样在链接DLL的应用程序中就可以调用这些函数,__declspec(dllimport)用于导入DLL函数,这样在编译DLL的应用程序中就可以使用这些函数

//DllDemo.h
ifdef ADD_EXPORTS //判断是否为导出DLL函数
define ADD_API __declspec(dllexport) //若是则定义ADD_API为__declspec(dllexport)
else
define ADD_API __declspec(dllimport)  //否则定义ADD_API为__declspec(dllimport)
endifextern "C" ADD_API int add(int a, int b);  //声明导出函数
extern "C" ADD_API int sub(int a, int b);
//DllDemo.cppinclude "pch.h"
include "DllDemo.h"int add(int x, int y)
{   return x+y;
}int sub(int a, int b)
{return a-b;
}

将生成的dll文件拖入pe查看器查看其导出表,可以发现导出函数的名称是可见的,若你不想别人看到导出函数的名称,可以采用方法二来创建动态库

方法二

方法二可以通过函数编号来导出函数,首先工程新建一个.def文件,这里我创建的是Export.def文件

Export.def的代码如下所示, LIBRARY后接动态链接库的项目名称, EXPORTS表示DLL导出函数, NONAME表示不显示导出函数的名称

LIBRARY MyDll
EXPORTS
add @11
sub @12 NONAME

以下分别是DllDemo.hDllDemo.cpp文件的代码

//DllDemo.h
int add(int a, int b);
int sub(int a, int b);
//DllDemo.cpp
include "pch.h"
include "DllDemo.h"int add(int x, int y)
{   return x+y;
}int sub(int a, int b)
{return a-b;
}

将生成的Dll放入PE查看器查看,可以发现不能查看sub函数的名称,但是可以看到其编号

调用动态库函数

显示调用

显示调用模块函数通常是指使用LoadLibrary函数和GetProcAddress函数,首先使用LoadLibrary函数加载动态链接库,并返回模块句柄,然后使用GetProcAddress函数获取导出函数的地址,最后使用函数指针来调用导出函数。

include <iostream>
include <windows.h>
include <StaticLib1.h>//声明函数指针
typedef int(*p_add)(int, int);
typedef int(*p_sub)(int, int);//定义函数指针变量
p_add add;
p_sub sub;int main()
{   //导入dllHMODULE hModule = LoadLibrary("MyDll.dll");//获取dll的导出函数add = (p_add)GetProcAddress(hModule, "add");  //通过名称获取导出函数sub = (p_sub)GetProcAddress(hModule, (char*)12);  //通过序号获取导出函数//调用导出函数int result1 = add(1, 2);int result2 = sub(2, 1);std::cout << "Add_Result: " << result1 << std::endl;std::cout << "Sub_Result: " << result2 << std::endl;//释放DLLFreeLibrary(hModule);
}

隐式调用

隐式调用需将lib文件和dll文件放到当前项目目录中,隐式调用模块函数通常是指在编译期间就将动态链接库中的导出函数作为外部函数链接到可执行文件中,在代码中直接调用函数名即可

include <iostream>
include <windows.h>
include <StaticLib1.h>//引入动态链接库
pragma comment(lib,"MyDll.lib")//声明dll的导出函数
__declspec(dllimport) int add(int, int);
__declspec(dllimport) int sub(int, int);int main()
{   int result1 = add(1, 2);int result2 = sub(2, 1);std::cout << "add_result: " << result1 << std::endl;std::cout << "sub_result: " << result2 << std::endl;}

两者的区别

隐式调用模块函数是在编译期间就链接了导出函数,因此代码中直接调用函数名即可,但是会增加可执行文件的大小,且不能动态加载;而显示调用模块函数可以在运行时动态加载导出函数,可以更加灵活,但需要手动使用LoadLibrary和GetProcAddress函数来获取导出函数的地址

隐式调用动态链接库的可执行文件会有一个导入表,导入表是一个数据结构,它记录了可执行文件需要引用的动态链接库中的函数及其地址

两者Lib文件的区别

静态链接库的LIB文件包含函数的导出表和函数代码,而动态链接库的LIB文件则只包含函数的导出表

静态链接库的LIB文件在编译时被链接到目标程序中,使得目标程序可以直接调用静态链接库中的函数。而动态链接库的LIB文件只是为了在链接时提供函数的导出信息,实际的函数代码在运行时从DLL文件中加载

DllMain函数

DLLMain 是 DLL 的入口函数,用于在加载或卸载 DLL 时执行一些初始化或清理操作,DLLMain 函数在 DLL 加载和卸载过程中被系统自动调用,其语法格式如下:

BOOL WINAPI DllMain(HINSTANCE hinstDLL,   // DLL句柄,表示Dll模块的基址DWORD fdwReason,      // 调用原因LPVOID lpvReserved   // 保留参数
){switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:case DLL_THREAD_ATTACH:case DLL_THREAD_DETACH:case DLL_PROCESS_DETACH:break;}return TRUE;
}

fdwReason 参数有以下几种取值:

  • DLL_PROCESS_ATTACH: DLL 被加载到进程地址空间中(LoadLibrary),此时可以进行初始化操作。
  • DLL_PROCESS_DETACH: DLL 被从进程地址空间中卸载(FreeLibrary),此时可以进行清理操作。
  • DLL_THREAD_ATTACH: 进程创建了一个新线程并且此线程使用了 DLL,此时可以进行线程相关的初始化操作。
  • DLL_THREAD_DETACH: 线程结束时调用,可以进行线程相关的清理操作

win32api之链接库的创建与调用(八)相关推荐

  1. 包含目录、库目录、附加包含目录、附加库目录、附加依赖项如何使用? 及静态库,动态库的创建与调用和vs里引用的使用

    引言:vs中怎么添加外部头文件? 如过直接在项目头文件处,添加一下,如下图: 否则,依然会报错,如下图: 有两种方法,来解决(你不在vs上的添加它也没事): (1) 直接把外部头文件复制过来,放在此项 ...

  2. 基于vs2019的静态链接库的创建与使用(超详细)

    文章目录 前言 一.什么是静态链接库? 二.静态链接库的建立与使用 1.静态链接库的建立 创建一个静态链接库项目 创建一个头文件 编写自己的静态库 生成静态库 2.静态链接库的使用 创建一个新项目 写 ...

  3. Linux下Makefile中动态链接库和静态链接库的生成与调用

    背景:写这篇博客的原因是:最近在搞嵌入式,需要交叉编译opencv库文件,自己写Makefile,通过arm-linux-g++编译.链接.生成可执行文件,从而实现了移植的过程.平台是Toradex的 ...

  4. vc6.0静态链接库的创建与使用方法

    1.建立如下的工程 选择该界面的最后一个,即创建了一个静态链接库,注意填写工程的名称. 2.在该工程下创建lib.h和lib.cpp两个文件 lib.h中源代码如下: #ifndef LIB_H #d ...

  5. easyui 调用dialog中的方法_SolidWorks中标准件库的创建及调用方法

    在使用SolidWorks进行产品设计时,常用的标准件(如螺栓.螺母.垫圈等)通常可以在安装了SolidWorksToolbox插件后调出使用,而许多标准件在Toolbox并不存在,不能从插件中直接调 ...

  6. 调用iframe中的js方法_SolidWorks中标准件库的创建及调用方法

    在使用SolidWorks进行机械设计时,常用的标准件(如螺栓.螺母.垫圈等)通常可以在安装了SolidWorksToolbox插件后调出使用,而许多标准件在Toolbox并不存在,不能从插件中直接调 ...

  7. Windows下动态链接库和静态链接库的生成以及调用

    Windows下静态库和动态库的生成和调用 一.简介 二.生成静态链接库(.lib)和动态链接库(.dll) 三.静态链接库的调用 四.动态链接库的调用 动态链接库的两种调用方式 仅使用.dll文件 ...

  8. Qt文档阅读笔记-共享库的创建与调用

    使用共享库的符号 这个符号可以作用在变量.类.函数中,并且这些都可以被调用端使用. 在编译共享库中,需要使用export符号.在使用端调用的时候使用import符号. 这里是本人从文档中记录的笔记,大 ...

  9. C++静态链接库(lib)的创建及调用

    C++静态链接库(lib)的创建及调用 1. 静态链接库的创建 2. 静态链接库的调用 1. 静态链接库的创建 首先在新建项目中,选择Visual C++,Win32控制台应用程序.这里我将新建的文件 ...

最新文章

  1. flume采集数据报错问题解决
  2. Thymeleaf显示表格
  3. 最强六大开源轻量级人脸检测项目分析 | 附打包下载
  4. 数字电路 模拟电路 先学哪个_国外经典电子资料:电子电路分析与设计
  5. 计算机网络---计算机网络分层结构
  6. 代码管理学:域名、产品名、应用名等都不是你能决定的,要上报备案
  7. Python3 NaN+NaN等于0
  8. java的安装_java 安装步骤
  9. [python3]坦克大战
  10. dirent--文件以及文件夹相关操作(跨平台)
  11. VS2010-MFC(Ribbon界面开发:为Ribbon Bar添加控件)
  12. NOAA GSOD数据中 国家与地区缩写对应全称
  13. 从0到1的电商架构应该怎么做?
  14. 持刀男子也地级市小女子背景
  15. ORACLE获取月初、月末日期
  16. I2P和TOR 有趣网络精灵
  17. Centos7 安装VLC播放器
  18. 大数据分析案例-对电信客户流失分析预警预测
  19. Git和小乌龟的下载安装及简单使用
  20. 美国姑娘项美丽与邵洵美的跨国恋

热门文章

  1. JDK1.8 HashMap源码分析
  2. 从爆款IP到独家IP,汽车之家内容战略如何登高?
  3. vs2019无法连接到远程服务器,VS2019无法添加引用问题
  4. sql中日期和时间戳的相互转换
  5. 车型选择三级联动插件
  6. 年薪500k阿里云大咖:掌握好以下数据库八大要点,月薪50k不是梦
  7. 图像处理与计算机视觉:基础,经典以及最近发展(总结)
  8. linux(ubuntu)下vi命令(例:sudo vi ~/.bashrc)
  9. html网页中两侧浮动广告怎么做,JavaScript 网页两侧对联浮动广告
  10. Google I/O 2022: 促进知识和计算机技术发展