14.自己动手研究动态链接库和静态链接库的区别

在学习注入dll时候 一直不理解如何区分动态链接库和静态链接库
今天让我们自己写程序将它理解清楚
首先我们打开vs
创建一个动态链接库文件
下面就是创建完文件之后 生成的代码
我们在动态链接库的入口处写入自己的函数

自己动手写一个dll导出函数

#include "pch.h"
// _declspec(dllexport) 声明导出函数将该函数从该dll开放提供给其他函数使用
 extern "C" _declspec(dllexport) void ccc();
void ccc() {
    MessageBox(NULL,"导出函数被调用成功","信息:",MB_YESNO);
}
//api信息框 来查看是否调用成功
     //动态链接库的入口函数
BOOL APIENTRY DllMain( HMODULE hModule,           //DLL模块的句柄
                       DWORD  ul_reason_for_call, //DLL被调用的原因 
                       LPVOID lpReserved          //保留项也是Windows的保留参数
                     )                         //保留参数不是不使用的参数,而是Windows不想让我们知道
                                             //作用的参数
{
    switch (ul_reason_for_call)
    { 
    case DLL_PROCESS_ATTACH:      //当进程加载时 DLL被调用
    case DLL_THREAD_ATTACH:         // 有线程被创建时DLL被调用
    case DLL_THREAD_DETACH:          //有线程结束时DLL被调用
    case DLL_PROCESS_DETACH:         //当DLL被进程卸载时DLL被调用
        break;
    }
    return TRUE;
}

extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern "C"后,会指示编译器这
部分代码按C语言(而不是C++)的方式进行编译。由于C++支持函数重载,因此编译器编译函数的过程中会将函数的
参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不
会带上函数的参数类型,一般只包括函数名。
这个功能十分有用处,因为在C++出现以前,很多代码都是C语言写的,而且很底层的库也是C语言写的,
为了更好的支持原来的C代码和已经写好的C语言库,需要在C++中尽可能的支持C,而extern "C"就是其中
的一个策略。

这个功能主要用在下面的情况:
C++代码调用C语言代码
在C++的头文件中使用
在多个人协同开发时,可能有的人比较擅长C语言,而有的人擅长C++,这样的情况下也会有用到

有人可能不理解为什么写这么多分支呢
答:因为DLMain函数不止一次的被调用,每次调用可能执行不同的代码,
比如进程加载dll时,可能在DLL中要申请一些资源,在进程卸载DLL时,DLL则要释放自己申请的资源*/

程序与dll导出函数的静态链接

我们创建完dll导出函数 再写一个调用的程序
创建一个空项目c++

#include<Windows.h>
#pragma comment(lib,"Dll1")
extern "C" _declspec(dllexport) void ccc();
int main()
{
	ccc();
	return 0;
}

#pragma comment(lib,“dl”)注意:没有分号
#pragma comnent(comment-type,["comentstring]”)
coment-type是一个预定义的标识签,指定注释的类型,应该是compiler,gxestr,1ib,linker之一。
coumentstrig.是一个提供为comment-type提供附加信息的字符串。
#pragma comment( lib , “Dll1” )的意思是指本文件生成的.obj文件应与Dll1一起连接
写完之后运行产生了不兼容的问题,我们需要更改一下属性
在这里插入图片描述然后我们打开 dll导出函数和这个函数所在的文件位置

在这里插入图片描述
把dll导出函数的debug文件夹里生成的这5个文件复制到
在这里插入图片描述由于是静态链接,静态链接把(lib)文件中用到的函数代码直接链接进目标程序,程序运行的时候不再需要其它的库文件
所以我们只用把lib后缀的文件复制到
在这里插入图片描述就可以运行了
我们总结一下
静态链接库的使用:
需要的文件: 头文件 .h 、静态库 .lib
头文件.h中有函数的声明,使用静态链接库的项目需要引用该文件才能编译通过
.lib包含了实际执行代码、符号表等等
加载lib的方法: 法1.使用编译链接参数或者VS的配置属性来设置 法2.使用pragma编译语句,例如pragma comment(lib,“a.lib”)
.lib中的指令将全部被直接包含在最终生成的 EXE 文件中

程序与dll导出函数的动态链接

创建一个空项目 -c++

 #include<Windows.h>
typedef void(*pMessage_Box)();
int main()
{
	HMODULE hModule = LoadLibrary("Dll1.dll");
	//判断这个句柄是否为空防止出bug
	if (hModule == NULL)
	{
		MessageBox(NULL, "句柄出错","标题",MB_OK); 
			return -1;
	}
	//GetProcAddress是从指定的动态链接库(DLL)中检素导出的函数ccc的地址
	pMessage_Box plMsg = (pMessage_Box)GetProcAddress(hModule,"ccc");
		//执行函数
	plMsg();

	return 0;
}

用动态库步骤:

1、创建一个函数指针,其指针数据类型要与调用的 DLL 引出函数相吻合。
2、通过 Win32 API 函数LoadLibrary()调用DLL,此函数返回DLL 的实例句柄。
3、通过 Win32 API 函数GetProcAddress()获取要调用的DLL 的函数地址,把结果赋给自定义函数的指针类型。
4、使用函数指针来调用 DLL 函数。
5.最后调用完成后,通过 Win32 API 函数FreeLibrary()释放DLL 函数。

我们再看一下他的文件
在这里插入图片描述经过了大量的尝试 发现 只需要把dll放到这个位置 和程序同一个文件夹就可以了

静态链接库和动态链接库的优缺点

从表面上来看

静态链接

需要复制很多文件到可执行文件的debug中,然后再复制lib到工程项目下

动态链接

只需要一个dll在可执行文件的debug中 ,

深入的来看

静态链接

是在在编译时直接将代码加入程序当中,而工程项目文件夹就是编译生成的.obj等其他文件,链接器从静态链接库LIB获取所有被引用函数,并将库同代码一起放到可执行文件中。

它的优点

(1) 代码装载速度快,执行速度略比动态链接库快;

(2) 只需保证在开发者的计算机中有正确的.LIB文件,在以二进制形式发布程序时不需考虑在用户的计算机上.LIB文件是否存在及版本问题,可避免DLL地狱等问题。

它的缺点

使用静态链接生成的可执行文件体积较大,包含相同的公共代码,造成浪费;

动态链接

就是把调用的函数所在文件模块(DLL)和调用函数在文件中的位置等信息链接进目标程序,程序运行的时候再从DLL中寻找相应函数代码,因此需要相应DLL文件的支持。
动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。使用动态库的优点是系统只需载入一次动态库,不同的程序可以得到内存中相同的动态库的副本,因此节省了很多内存
动态lib相当于一个h文件,是对实现部分(.dll文件)的导出部分的声明。编译后只是将导出声明部分编译到宿主程序中,运行时候需要相应的dll文件支持

它的优点

(1) 更加节省内存并减少页面交换;

(2) DLL文件与EXE文件独立,只要输出接口不变(即名称、参数、返回值类型和调用约定不变),更换DLL文件不会对EXE文件造成任何影响,因而极大地提高了可维护性和可扩展性;

(3) 不同编程语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数;

(4)适用于大规模的软件开发,使开发过程独立、耦合度小,便于不同开发者和开发组织之间进行开发和测试。

它的缺点

使用动态链接库的应用程序不是自完备的,它依赖的DLL模块也要存在,如果使用载入时动态链接,程序启动时发现DLL不存在,系统将终止程序并给出错误信息。而使用运行时动态链接,系统不会终止,但由于DLL中的导出函数不可用,程序会加载失败;速度比静态链接慢。当某个模块更新后,如果新模块与旧的模块不兼容,那么那些需要该模块才能运行的软件,统统撕掉。这在早期Windows中很常见。

贴一个小知识

在这里插入图片描述

有人可能要问为什么两个debug文件夹

在解决方案目录下的是最终文件(即可执行文件)存放的目录,在工程目录下的是中间文件(编译生成的.obj等其他文件)存放的目录,中间文件对用户来说没什么用的,只是在链接成最终文件时有用到

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章