在Windows平台的C++开发中,动态链接库(DLL)可以让程序在运行时按需加载功能模块,避免静态链接带来的体积膨胀问题。使用LoadLibrary配合GetProcAddress是动态调用DLL函数的标准方式,不需要在编译时链接.lib导入库,灵活性更高。

动态调用DLL的核心流程
整个调用过程可以分为四个核心步骤,每个步骤都有对应的Windows API函数支持,下面逐一说明。
1. 加载DLL文件
首先需要使用LoadLibrary函数加载目标DLL文件,该函数会返回DLL模块的句柄,后续操作都依赖这个句柄。函数原型如下:
// 加载指定路径的DLL,返回模块句柄,失败返回NULL HMODULE LoadLibrary( LPCTSTR lpLibFileName // DLL文件路径,可以是相对路径或绝对路径 );
如果DLL和exe文件在同一个目录,直接传入DLL文件名即可,否则需要传入完整路径。加载成功后需要判断是否返回有效句柄,避免后续操作出错。
2. 获取目标函数地址
拿到DLL模块句柄后,使用GetProcAddress函数获取DLL中导出函数的地址。函数原型如下:
// 根据函数名获取DLL中导出函数的地址,失败返回NULL FARPROC GetProcAddress( HMODULE hModule, // LoadLibrary返回的模块句柄 LPCSTR lpProcName // 导出的函数名,注意是ANSI字符串 );
这里需要注意,传入的函数名必须是DLL实际导出的名称,如果DLL使用了C++的名称修饰,可能需要使用修饰后的名称,或者要求DLL用extern "C"导出函数避免名称修饰。
3. 定义函数指针并调用函数
获取到函数地址后,不能直接调用,需要先定义和DLL导出函数完全匹配的函数指针类型,再将地址转换为该指针类型后调用。函数指针的返回值、参数列表、调用约定都必须和DLL中的函数完全一致,否则会导致栈错误。
4. 释放DLL模块
调用完成后,需要使用FreeLibrary函数释放DLL模块,避免内存泄漏。函数原型如下:
// 释放已加载的DLL模块,返回非零值表示成功 BOOL FreeLibrary( HMODULE hLibModule // LoadLibrary返回的模块句柄 );
完整示例代码
假设我们有一个名为demo.dll的动态库,其中导出了一个加法函数,函数原型为int add(int a, int b),且使用了extern "C"和__stdcall调用约定导出,下面是完整的调用代码:
#include <windows.h>
#include <iostream>
// 定义和DLL导出函数匹配的函数指针类型
// 返回值int,两个int参数,调用约定__stdcall
typedef int (__stdcall *AddFunc)(int, int);
int main() {
// 步骤1:加载DLL
HMODULE hDll = LoadLibrary("demo.dll");
if (hDll == NULL) {
std::cout << "加载DLL失败,错误码:" << GetLastError() << std::endl;
return -1;
}
// 步骤2:获取add函数地址
AddFunc add = (AddFunc)GetProcAddress(hDll, "add");
if (add == NULL) {
std::cout << "获取函数地址失败,错误码:" << GetLastError() << std::endl;
FreeLibrary(hDll);
return -1;
}
// 步骤3:调用函数
int result = add(10, 20);
std::cout << "调用add函数结果:" << result << std::endl;
// 步骤4:释放DLL
FreeLibrary(hDll);
return 0;
}
注意事项与常见问题
- 调用约定匹配:DLL导出函数的调用约定(__stdcall、__cdecl等)必须和函数指针定义的调用约定一致,否则会导致栈不平衡,程序崩溃。
- 函数名称匹配:如果DLL是C++编写的且没有用extern "C"导出,函数名会被编译器修饰,需要使用工具(如Dependency Walker)查看实际导出的函数名,再传入GetProcAddress。
- 错误排查:每次调用Windows API后,如果返回失败,可以通过GetLastError()获取错误码,对照Windows错误码表排查问题。
- 32位与64位兼容:调用程序的位数必须和DLL的位数一致,32位程序不能加载64位DLL,反之亦然。
如果DLL提供了.lib导入库和头文件,也可以使用静态链接的方式调用,不需要手动使用LoadLibrary,但是动态调用的优势是可以在运行时决定是否加载DLL,更适合插件化架构的场景。
C++LoadLibraryGetProcAddressDLL调用动态库修改时间:2026-07-05 11:18:24