1.隐式链接
步骤一: 将.dll .lib文件放到工程目录下
在之前使用dll时我们根本没使用.lib文件,因为函数根本不在他里面。他不是静态链接库里的lib文件。
但是这里面有着辅助信息,所以我们要使用隐式链接的话就要使用他,来让编译器找到dll。
步骤二:将 #pragma comment(lib,"lib名.lib")添加到调用文件中
步骤三:加入函数声明(也可以把dll头文件放到目录下)
注意:
extern "C" _declspec(dllexport) ... ... ... ...
当我们使用上面这种方式的时候别忘了在函数声明时前面加上extern "C"
_declspec(dllimport) int add(int x, int y);
示例代码:
#include <stdio.h>
#include "StdAfx.h"
#include <Windows.h>
#pragma comment(lib,"Dll1.lib")
_declspec(dllimport) int add(int x, int y);
int main()
{
int x = add(1, 2);
printf("%d", x);
return 0;
}
注意:我在尝试的时候出现一个(无法找到dllmain.dll,程序无法运行)的错误。因为我放到该目录下的dll名字为dll1.dll但是他说无法找到dllmain.dll所以我改了下名字就可以正常运行了。
输出:

那么可能会有疑问,编译器如何找到我们的dll文件呢?我们又没有把它加载到内存。原来是.lib文件里面存在对dll文件的描述信息,因此编译器可以找到。
这段代码看起来好像是静态链接库的实现方式,我们看一下汇编代码。

可以看到在这里调用函数时调用的是一个地址,这个地址就是我们要用的函数地址。(间接调用) 我们在使用静态库时调用的直接就是函数。
2.隐式链接的实现
下面我们具体看看这种隐式链接的方式怎么实现的。
可能大家学过PE文件的话可能会知道除了导出表还有导入表(IAT)上面描述了使用的dll的各种信息。我们打开PE加载器看一下exe文件(我们使用dll程序的exe
)的导入表

可以看到里面导入了我们的dllmain.dll。还记载了用到了哪些函数

我们也可以点一下导出表,一般exe是没有导出表的(不过不是一定没用)。因为他不许要给别人提供函数,一般都是dll来提供。不过dll也有导入表,因为他也需要使用一些dll比如kernel32.dll。

(滴水视频上的直接截图过来了)
3.DLL的优点
之前在静态链接的时候说过,它的缺点就是dll的优点。

+
相信大家都对这个图很熟悉了。静态链接库是直接给进程复制一份代码放
进去,而dll文件就只有一份,使用时就映射到虚拟内存中,其实只有一份。那假如我们在使用时修改dll,这样会对其他进程产生影响呢?是不会的。我们在之前也说过,改的话会创建一个新的物理页,如图片右边。
4.DllMain函数
BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,//句柄
_In_ DWORD fdwReason,//指示调用 DLL 入口点函数的原因代码(有四种情况会被调用,具体看文档)
_In_ LPVOID lpvReserved
);
exe和dll除了导入,导出表有些差异。还有就是他们的入口函数执行时间不同。如果是exe文件都会从main函数地方进行,这就是exe的入口函数。
而dll的入口函数是DllMain。它不像main函数只执行一次,他可能执行多次。
1.当第一次使用LoadLibraryA时会调用DllMain.传的参数为DLL_THREAD_ATTACH
2.当调用FreeLibrary时会调用DllMain穿的参数为DLL_PROCESS_DETACH
下面我们论证一下
dllmain.cpp:
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include "dllmain.h"
#include <Windows.h>
#include <stdio.h>
BOOL WINAPI DllMain(HANDLE hModele,
DWORD fdwReason,
LPVOID lpReserved
)
{
switch (fdwReason)
{
//1. DLL_THREAD_ATTACH (LoadLibrary)
case DLL_PROCESS_ATTACH:
OutputDebugStringA("1.DLL_THREAD_ATTACH \n");
//2. DLL_PROCESS_DETACH (FreeLibrary)
break;
case DLL_PROCESS_DETACH:
OutputDebugStringA("2.DLL_PROCESS_DETACH \n");
break;
default:
printf("error");
break;
}
}
#include <stdio.h>
#include "StdAfx.h"
#include <Windows.h>
typedef int ( *lpadd)(int x, int y);
lpadd myadd;
int main()
{
HINSTANCE hModule = LoadLibraryA("Dll1.dll");//这里下断点
FreeLibrary(hModule);
return 0;
}
f11调试看到输出:

本文详细介绍了Windows环境下隐式链接DLL的过程,包括将DLL和LIB文件放入工程目录、添加#pragma comment(lib)、函数声明等步骤,并探讨了隐式链接的实现原理,涉及导入表(IAT)、DLLMain函数的执行情况。同时,讨论了DLL的优点,如节省内存,以及DllMain在DLL生命周期中的不同调用场景。
212

被折叠的 条评论
为什么被折叠?



