dll动态链接库简介
DLL(Dynamic Link Library)动态链接库是一种 Windows 程序库,其主要特点是动态加载和链接,使程序可以在运行时调用和卸载其中包含的函数或资源。DLL 动态链接库主要用于代码复用和资源共享。
与静态链接库不同,DLL 动态链接库并不在编译时链接到可执行文件中,而是在运行时由操作系统加载并链接到可执行文件中。这意味着可以在不停止程序运行的情况下更新 DLL 文件,从而实现程序的动态更新。此外,DLL 动态链接库的多个程序可以共享相同的 DLL(dll注入原理),从而减少了系统资源的消耗,提高了代码复用性。
通过导出函数,DLL 动态链接库可以暴露其功能并允许其他程序调用其中的函数。这使得 DLL 动态链接库非常适合实现公共功能。
创建项目
在vs中新建空项目,右键项目属性>配置属性>常规>配置类型>设置为.dll
代码
#include <windows.h>
#include <iostream>
/*
__declspec(dllexport)
在函数前加入表示该函数为导出函数
extern "C"
表示以c方式导出
*/
#define MY_API __declspec(dllexport)
extern "C" MY_API void hello(VOID);
// 导出函数实现
void hello(){
std::cout << "hello dll" << std::endl;
}
/*
DllMain 是 Windows DLL 动态链接库的入口函数,它会在 DLL 的加载、
卸载、线程连接、线程断开等情况下被系统自动调用。
在这些情况下,DllMain 函数可以执行一些初始化和清理操作,
例如初始化全局变量、创建进程、加载其他 DLL 等。
*/
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
DllMain函数相关
DllMain 是 Windows DLL 动态链接库的入口函数,它会在 DLL 的加载、卸载、线程连接、线程断开等情况下被系统自动调用。在这些情况下,DllMain 函数可以执行一些初始化和清理操作,例如初始化全局变量、创建进程、加载其他 DLL 等。
其中,参数 hinstDLL
表示 DLL 的实例句柄,参数 fdwReason
表示 DLL 被加载、卸载、线程连接、线程断开等情况,参数 lpvReserved
保留,一般为 NULL
。
以下是一些常见的使用场景:
当 DLL 被加载到内存时,fdwReason 为 DLL_PROCESS_ATTACH
。在这种情况下,DllMain 函数可以执行一些初始化操作,例如为全局变量分配内存、创建线程、注册类等。
当 DLL 被卸载时,fdwReason 为 DLL_PROCESS_DETACH
。在这种情况下,DllMain 函数可以执行一些清理操作,例如释放资源、关闭句柄等。
当线程连接到 DLL 时,fdwReason 为 DLL_THREAD_ATTACH
。在这种情况下,DllMain 函数可以执行一些初始化操作,例如为线程分配内存、创建句柄等。
当线程从 DLL 中断开时,fdwReason 为 DLL_THREAD_DETACH
。在这种情况下,DllMain 函数可以执行一些清理操作,例如释放资源、关闭句柄等。
需要注意的是,DllMain 函数的执行过程应该保持简单和快速,因为它在 DLL 的加载和卸载过程中会频繁调用,长时间的执行可能会影响系统性能。
注意:DllMain函数不是必须的,一些例子中,DLL并没有提供DllMain函数,应用工程也能成功引用DLL,这是因为Windows在找不到DllMain的时候,系统会从其它运行库中引入一个不做任何操作的缺省DllMain函数版本,并不意味着DLL可以放弃DllMain函数。
使用dll动态链接库
#include<Windows.h>
#include<iostream>
using namespace std;
// 声明函数指针和需要使用的函数一致
typedef VOID(*func)(void);
int main() {
HINSTANCE hDll; //DLL句柄
//加载dll注意这里需要填写正确的路径
//加L转换为Unicode
hDll = LoadLibrary(L"testDll.dll");
if (hDll != NULL)
{
// 从hDll句柄加载Dll中的方法
func proc = (func)GetProcAddress(hDll, "hello");
// 然后就可以像使用正常函数一样使用了
proc();
}
return 0;
}
说在最后
安全申明:本人才疏学浅,若有任何谬误,欢迎指正