LoadLibrary返回NULL主因是路径错误、依赖缺失或架构不匹配;需立即调用GetLastError判断:126(DLL或依赖未找到)、193(x86/x64不匹配)、1114(初始化失败);导出函数须用extern "C"或.def避免name mangling;GetProcAddress获取地址后需严格匹配函数签名;每次LoadLibrary对应一次FreeLibrary以防泄漏。

LoadLibrary 返回 NULL?90% 是路径、依赖或架构不匹配导致的,不是代码写错了。
LoadLibrary 失败时先看 GetLastError 是多少
它只返回 HMODULE(本质是 void*),失败就返回 nullptr,不抛异常。必须立刻调用 GetLastError() 查原因:
-
126:DLL 本身找不到,或某个依赖 DLL(比如MSVCP140.dll)缺失 —— 用dumpbin /dependents MyLib.dll看依赖,把缺失的 DLL 放到同目录或系统路径 -
193:架构不匹配 —— x64 程序不能加载 x86 DLL,反之亦然;检查 VS 项目属性里的「平台」是否和 DLL 一致(Win32 ≠ x64) -
1114:DLL 初始化失败 —— 常见于 C++ 运行时冲突(DLL 编译用 /MT,主程序用 /MD) - 路径含中文或空格?用绝对路径,并确保反斜杠双写:
L"C:\path\MyLib.dll",别信相对路径
GetProcAddress 找不到函数名?大概率是名字修饰惹的祸
GetProcAddress 查的是 DLL 导出表里的符号名,不是你源码里写的函数名。C++ 默认会做 name mangling,导出的可能是 ?Add@@YAHHH@Z 这种,GetProcAddress(hDll, "Add") 必然失败。
- DLL 源码中必须用
extern "C"包裹导出函数:extern "C" __declspec(dllexport) int Add(int a, int b); - 或者用 .def 文件显式导出:
EXPORTS Add @1,绕过编译器修饰 - 用
dumpbin /exports MyLib.dll确认实际导出名 —— 如果看到带@@的长串,说明没加extern "C" - 别用类成员函数直接导出 —— 成员函数有隐式
this参数,签名不匹配,调用必崩
函数指针类型声明错一个字,调用就可能崩溃
GetProcAddress 返回 FARPROC(即 void*),强制转换成函数指针时,调用约定、参数类型、返回值类型必须完全一致。
立即学习“C++免费学习笔记(深入)”;
- C 风格函数默认是
__cdecl,所以 typedef 要写全:typedef int (__cdecl *AddFunc)(int, int); - 如果 DLL 用
WINAPI(即__stdcall)导出,这里也得写__stdcall,否则栈平衡错乱 - 参数顺序、个数、const/volatile 修饰都不能差 ——
const char*和char*在某些 ABI 下不兼容 - 别省略
typedef直接写(int(*)(int,int))—— 可读性差,容易漏掉调用约定
FreeLibrary 不调用,迟早内存泄漏或 DLL 锁死
Windows 不会自动卸载已加载的 DLL,LoadLibrary 每成功一次,内部引用计数 +1;FreeLibrary 每调用一次,计数 -1;只有计数归零才真正释放。
- 忘记调用
FreeLibrary→ DLL 句柄泄露,多次加载后内存占用持续上涨 - 在 DLL 函数还在执行时调用
FreeLibrary→ 行为未定义,极可能崩溃 - 跨线程调用要小心:一个线程
LoadLibrary,另一个线程FreeLibrary是允许的,但需确保无函数正在执行 - 推荐模式:加载后立即检查所有函数指针,任一失败就
FreeLibrary并 return,避免资源悬挂
最易被忽略的一点:LoadLibrary 加载的是模块,不是函数;GetProcAddress 拿到的是地址,不是函数本身 —— 类型安全全靠人工保证,编译器不帮你校验签名。哪怕只多传一个 int,也可能破坏栈帧,崩溃时堆栈还看不出问题根源。


















