Windows下C++调用DLL有隐式链接和显式链接两种方式:前者编译时绑定,需DLL、.lib和头文件,调用简单但路径固定;后者运行时用LoadLibrary/GetProcAddress加载,灵活适用于插件等场景,需注意名称修饰、路径、位数匹配等问题。

在 Windows 下用 C++ 调用 DLL,主要有两种方式:隐式链接(静态链接导入)和显式链接(运行时加载)。区别在于链接时机和灵活性——隐式链接编译时就绑定 DLL,简单但依赖固定路径;显式链接在运行时用 LoadLibrary 和 GetProcAddress 手动加载,更灵活,适合插件机制或避免启动失败。
隐式链接:编译期绑定,用起来最简单
隐式链接需要三样东西:DLL 文件、对应 .lib 导入库(由 DLL 生成)、以及头文件(声明导出函数)。编译器靠 .lib 知道函数签名和符号名,链接器在生成 EXE 时写入导入表,系统启动时自动加载 DLL。
- 确保 DLL 已正确导出函数(用
__declspec(dllexport)或 .def 文件) - 把 DLL 放在可执行文件同目录、系统 PATH 路径,或 Windows 系统目录下
- 在 C++ 代码中
#include对应头文件,并链接 .lib(如project.lib) - 直接调用函数,像调用普通函数一样,无需手动加载
例如:int result = MyAdd(3, 5); —— 只要头文件里声明了 MyAdd,且链接了 mylib.lib,就能工作。
显式链接:运行时加载,控制力更强
显式链接不依赖 .lib,完全靠 Win32 API 在运行时操作。适合需要按需加载、容错处理(比如 DLL 缺失时友好提示)、或多版本共存的场景。
立即学习“C++免费学习笔记(深入)”;
- 用
HMODULE hLib = LoadLibrary(L"mylib.dll");加载 DLL(注意宽字符) - 检查返回值:为
NULL表示失败,可用GetLastError()查原因 - 用
GetProcAddress(hLib, "MyAdd")获取函数地址,强转为对应函数指针类型 - 调用前务必判空,防止崩溃;用完后调用
FreeLibrary(hLib)卸载
小技巧:函数指针类型建议用 typedef 或 using 定义,比如 using AddFunc = int(*)(int, int);,让代码更清晰安全。
这是一个免费的企业网站系统,任何人可以免费下载、修改和使用本程序,也可以用来为企业建网站。没有任何功能限制,且不发布收费版。容兴免费企业网站系统后台功能简介:1.基本设置:基本信息,联系方式,网站设置,导航管理,模块启闭,静态设置,安全设置,数据库管理2.产品管理:产品列表,添加产品,产品分类3.文章管理:文章列表,发表文章,文章分类,公司简介,网站公告4.客服互动:留言管理,在线客服,友情链接5
导出函数要注意名字修饰(Name Mangling)
C++ 编译器会对函数名做修饰(比如加参数类型信息),导致 GetProcAddress 找不到原始名字。解决方法有二:
- 用
extern "C"包裹导出函数声明,禁用 C++ 名字修饰(推荐用于 C 风格接口) - 用 .def 文件显式指定导出名,绕过编译器修饰(适合必须用 C++ 成员函数的场景)
验证导出名是否正确?可用 dumpbin /exports mylib.dll(VS 工具)或 Dependency Walker 查看实际导出符号。
常见坑和调试建议
很多初学者卡在“找不到 DLL”或“找不到过程入口”,其实多数是路径或符号问题:
- DLL 路径不对:显式链接时传绝对路径最稳妥;隐式链接优先查当前目录 → PATH → 系统目录
- 位数不匹配:32 位程序不能加载 64 位 DLL,反之亦然(检查项目平台设置)
- 依赖缺失:用
Dependencies.exe(现代版 Dependency Walker)查看 DLL 是否还缺其他依赖项 - Unicode/ANSI 混淆:
LoadLibrary推荐用LoadLibraryW+L"xxx.dll",避免多字节编码陷阱
写个简单的封装类或 RAII 封装 HMODULE,能显著减少资源泄漏和重复判断。










