C++ 怎么调用DLL C++ LoadLibrary动态加载库文件【动态库】

14次阅读

LoadLibrary 返回 NULL 需先调用 GetLastError 获取错误码(如 126 表示模块未找到),再检查 DLL 路径是否为绝对路径、位数是否匹配(32/64 位)、依赖项是否完整(可用 Dependencies 工具扫描),并确保使用 LoadLibraryW 处理 Unicode 路径。

C++ 怎么调用 DLL C++ LoadLibrary 动态加载库文件【动态库】

LoadLibrary 返回 NULL 怎么排查

调用 LoadLibrary 返回 NULL 是最 常见问题,本质是系统找不到或无法加载目标 DLL。不是代码写错,而是路径、依赖、位数或权限出了问题。

  • 先用 GetLastError() 获取错误码,再查 Windows 错误码文档,比如 126ERROR_MOD_NOT_FOUND)表示找不到 DLL 或其某个依赖项
  • DLL 路径必须是绝对路径,相对路径会按 Windows 搜索顺序找(当前目录、System32、PATH 等),极易失败;推荐用 GetFullPathName 转成绝对路径再传给 LoadLibrary
  • 32 位程序只能加载 32 位 DLL,64 位同理;混用会导致 LoadLibrary 静默失败(GetLastError 返回 193,即 ERROR_BAD_EXE_FORMAT
  • 检查 DLL 是否依赖其他 DLL(如 Visual C++ 运行库、OpenSSL 等),可用 Dependencies 工具(替代旧版 Dependency Walker)扫描缺失项

GetProcAddress 获取函数地址时崩溃或返回 NULL

GetProcAddress 返回 NULL,通常不是函数名写错就是导出方式不匹配——C++ 编译器默认对函数名做 C++ name mangling,而 GetProcAddress 只认 C 风格的未修饰名。

  • 确保 DLL 中导出函数用 extern "C" 声明,例如:
    extern "C" __declspec(dllexport) int add(int a, int b) {return a + b;}
  • 导出函数名必须和 GetProcAddress 传入的字符串完全一致(区分大小写),可用 dumpbin /exports your.dll 查看实际导出名
  • 不要直接把函数指针当普通函数调用;必须先定义函数类型别名,再强制转换:
    typedef int (*AddFunc)(int, int);
    AddFunc pAdd = (AddFunc)GetProcAddress(hMod, "add");
    if (pAdd) result = pAdd(2, 3);
  • 若 DLL 导出的是类或成员函数,不能直接用 GetProcAddress;应导出工厂函数(如 CreateInstance),返回接口指针

FreeLibrary 后继续调用函数导致崩溃

FreeLibrary 卸载 DLL 后,所有通过 GetProcAddress 获取的函数地址立即失效。此时调用它们属于野指针行为,大概率触发访问冲突(0xC0000005)。

  • 卸载前务必确保所有相关函数调用已结束,且无任何线程仍在执行该 DLL 中的代码
  • 不要在 DLL 的导出函数内部调用 FreeLibrary(this_module)(即“自卸载”),Windows 不允许,会引发未定义行为
  • 如果 DLL 被多次 LoadLibrary,需对应次数的 FreeLibrary 才真正卸载;可用 GetModuleHandle 判断是否已加载,避免重复加载
  • 建议封装一个 RAII 类管理 HMODULE 生命周期,构造时 LoadLibrary,析构时 FreeLibrary,防止遗漏

Unicode 路径下 LoadLibraryW 失败但 LoadLibraryA 成功

Windows 中 LoadLibrary 是宏,ANSI 版(LoadLibraryA)无法正确处理含中文或特殊字符的路径,尤其在非系统 locale 下容易截断或乱码,导致找不到文件。

立即学习C++ 免费学习笔记(深入)”;

  • 一律使用宽字符版本:LoadLibraryW,传入 LPCWSTR(即 const wchar_t*
  • 路径字符串必须以 L 前缀声明,或用 MultiByteToWideChar 转换 UTF-8 路径(如从命令行或 配置文件 读取)
  • 确认项目字符集设置:VS 中若设为“Use Multi-Byte Character Set”,LoadLibrary 宏会指向 A 版本,需显式调用 LoadLibraryW
  • SetCurrentDirectoryW 不影响 LoadLibraryW 的路径解析逻辑,别指望切工作目录来绕过绝对路径要求

DLL 动态加载看着就三步(Load → Get → Call),但每个环节都卡在环境细节里。最容易被忽略的是依赖链完整性——哪怕只少一个 vcruntime140.dllLoadLibrary 就会静默失败,而错误码还可能被中间层覆盖。动手前,先用 Dependencies 扫一遍,比反复改代码快得多。

text=ZqhQzanResources