一、Dll 可执行文件的编写
首先我们需要在 VS 创建一个动态链接库(DLL)项目,然后会生成如下代码:
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
BOOL APIENTRY DllMain( HMODULE hModule, // 指向 Dll 模块的句柄
DWORD ul_reason_for_call, // 指示调用 DllMain 的原因
LPVOID lpReserved // 保留参数,忽略
)
{
switch (ul_reason_for_call)
{
// 进程加载本 Dll 后执行
case DLL_PROCESS_ATTACH:
MessageBoxA(NULL, "Dll 加载成功", NULL, NULL);
break;
// 线程被创建后执行
case DLL_THREAD_ATTACH:
break;
// 线程正常退出后执行
case DLL_THREAD_DETACH:
break;
// 进程卸载本 Dll 后执行
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
直接编译即可生成一个最简单的 Dll 可执行文件,那么如果我们想要在 Dll 文件中导出相关函数,那么要怎么操作呢?
我们需要定义一个导出函数声明,并且对这个导出函数进行实现:
extern "C" __declspec(dllexport) void MsgBox(LPCSTR msg, LPCSTR title)
{
MessageBoxA(NULL, msg, title, NULL);
}
上面的代码中,我们声明并实现了一个 MsgBox 函数,函数中调用了 MessageBoxA 函数。其中,__declspec(dllexport)
修饰符表示该函数用于导出,extern "C"
表示在对该函数进行编译的时候按照 C 语言编译方式进行。
其实除了导出函数外,我们还可以通过 __declspec(dllimport)
修饰符来告诉编译器,被它修饰的函数或变量需要从其他的 Dll 导入,由于 Dll 可执行文件很少用到导入功能,在此不做详述。
二、动态调用 Dll 可执行文件的导出函数
首先,我们需要定义一个函数指针用来接收这个导出函数:
// 定义一个函数指针
typedef void(*PMSGBOX)(LPCSTR msg, LPCSTR title);
然后我们通过 LoadLibrary
函数来动态加载 Dll 可执行文件,并通过 GetProcAddress
函数来从 Dll 可执行文件中获取特定的导出函数:
// 加载 Dll 模块
HMODULE hModule = LoadLibraryA("./console_Dll.dll");
if (hModule)
{
PMSGBOX pMsgBox = (PMSGBOX)GetProcAddress(hModule, "MsgBox");
pMsgBox("hello", "msgbox");
}
调用的结果如下: