LoadLibrary失败先查GetLastError:126为依赖缺失,193为架构不匹配;用绝对路径、Dependency Walker查依赖、确保位数一致;C++导出需extern "C"防名字修饰;GetProcAddress返回值须强转为匹配调用约定的函数指针类型。

LoadLibrary 失败返回 NULL 怎么排查
调用 LoadLibrary 返回 NULL 是最常见卡点,不是路径错就是依赖缺失。先用 GetLastError() 拿错误码,再查对应含义——比如 126 表示找不到 DLL 或其某个依赖项(如 MSVCP140.dll),193 表示架构不匹配(x64 程序加载了 x86 DLL)。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 用绝对路径传给
LoadLibrary,避免当前工作目录干扰;路径中反斜杠必须双写:"C:\\path\\mylib.dll" - 用
Dependency Walker或dumpbin /dependents mylib.dll查看依赖项,确认所有 .dll 都在PATH或同目录 - 确保进程位数与 DLL 一致:VS 中项目属性 → 配置管理器 → 平台必须匹配(Win32 ≠ x64)
- 如果 DLL 有静态 C++ 运行时(/MT),而主程序用动态(/MD),可能引发初始化失败,此时
GetLastError可能返回 1114(DLL 初始化例程失败)
GetProcAddress 找不到函数名?注意 C++ 名字修饰
直接传 "MyFunc" 给 GetProcAddress 失败,大概率是 C++ 编译器对函数名做了修饰(name mangling)。DLL 导出的是 C 风格符号才可用原名查找;C++ 成员函数、重载函数、模板函数默认无法按名字导出。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- DLL 工程中,用
extern "C"包裹导出函数声明:extern "C" __declspec(dllexport) int MyFunc(int x);
- 或者在 .def 文件里显式指定导出名,绕过修饰:
EXPORTS
MyFunc @1 - 用
dumpbin /exports mylib.dll确认实际导出的符号名——如果看到类似?MyFunc@@YAHH@Z,说明没加extern "C" - 不要试图用修饰后的名字硬写进代码,跨编译器不可靠;坚持用
extern "C"+ 显式调用约定(如__cdecl)最稳妥
函数指针类型声明不对会导致调用崩溃
GetProcAddress 返回 FARPROC(即 void*),必须强制转成**完全匹配的函数指针类型**,否则参数压栈、返回值解析全错,轻则结果异常,重则访问违规。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 定义 typedef 时,调用约定必须和 DLL 中一致:
typedef int (__cdecl *MYFUNC)(int);
MYFUNC pFunc = (MYFUNC)GetProcAddress(hMod, "MyFunc"); - 忘记写
__cdecl或写成__stdcall是高频崩溃原因;若 DLL 是 C 函数,默认是__cdecl;若用WINAPI(即__stdcall)导出,这里也得同步 - 参数个数、类型、顺序、返回值类型缺一不可;bool 和 BYTE、int 和 long 在不同平台可能宽度不同,尽量用
int32_t等固定宽度类型 - 调用前务必检查
pFunc != nullptr,否则直接崩溃
卸载 DLL 前必须确保没有线程正在执行其中代码
FreeLibrary 不会立即释放 DLL 内存,而是递减引用计数;但如果某线程正停在 DLL 函数里(比如等待 IO 或 sleep),此时调用 FreeLibrary,后续该线程恢复执行时就会访问已释放内存,导致未定义行为。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 除非明确需要热更新,否则通常不需要主动
FreeLibrary;进程退出时系统自动清理 - 若必须卸载,确保所有调用方已退出相关函数,并且 DLL 内部无后台线程存活(比如它自己创建的 worker thread)
- 可以配合
DisableThreadLibraryCalls(hMod)减少线程附加/分离开销,但不影响安全性判断 - 多次
LoadLibrary同一个 DLL 会返回相同句柄,引用计数+1;对应要调用同样次数的FreeLibrary才真正释放








