
怎么用 Visual Studio 创建一个能被调用的 DLL
必须显式导出函数,否则生成的 DLL 里没有可调用符号。默认情况下 C++ 编译器会做名字修饰(name mangling),GetProcAddress 找不到原始函数名。
- 在函数声明前加
extern "C" __declspec(dllexport),比如:extern "C" __declspec(dllexport) int add(int a, int b) { return a + b; } - 不加
extern "C"会导致导出名类似?add@@YAHHH@Z,调用方几乎无法硬编码匹配 - 项目属性 → 配置属性 → 常规 → 配置类型必须设为
DynamicLibrary (.dll),不是静态库或应用程序 - 生成后检查是否真有导出:用
dumpbin /exports your.dll,输出里得看到干净的add,而不是一串乱码
为什么 C++ DLL 被 C# 或 Python 调用时总报“找不到入口点”
根本原因通常是调用方用的名字和 DLL 实际导出的不一致,尤其在没加 extern "C" 时最常见。
- C# 的
[DllImport]必须和dumpbin显示的导出名完全一致;如果用了extern "C",就写"add";如果没加,就得写修饰后的全名(不推荐) - Python 的
ctypes.CDLL().add同理,属性访问名必须匹配导出名 - 32/64 位必须严格匹配:x64 程序不能加载 x86 DLL,反之亦然,错误信息常是“模块未找到”而非“入口点”,容易误判
- 依赖的运行时(如
msvcp140.dll)没部署到目标机器也会表现为“找不到过程入口”,用Dependencies.exe查真实缺失项
导出类或 C++ 对象给外部语言安全吗
不安全,也不可行。跨语言调用只应走纯 C 接口,对象模型、异常、内存布局、RTTI 全都不兼容。
- 不要导出
class MyClass或任何含虚函数、std::string、vector 的类型 - 可以导出工厂函数,比如
extern "C" __declspec(dllexport) MyHandle create_instance();,内部用 new 分配,再提供destroy_instance(MyHandle)配套释放 - 所有参数和返回值限制为基本类型(
int、double、const char*)、指针或固定大小结构体;字符串建议用 UTF-8 编码的const char*+ 长度参数 - 别让外部语言调用
delete或析构函数——内存必须由 DLL 内部分配并释放,否则可能触发不同堆的崩溃
怎么让 DLL 在不注册、不放系统目录也能被加载
靠修改调用方的加载路径或使用延迟加载,而不是把 DLL 扔进 System32 ——那既不安全也不便部署。
立即学习“C++免费学习笔记(深入)”;
- 调用方启动前,用
SetDllDirectory(L".")把当前目录加入搜索路径(注意宽字符) - 或者用
LoadLibrary(L"relative\path\mylib.dll")传绝对或相对路径,比依赖系统搜索更可控 - Visual Studio 项目中可在链接器 → 输入 → 延迟加载 DLL 里填
mylib.dll,这样首次调用函数时才加载,失败可捕获异常 - 避免用
LoadLibrary("mylib")不带扩展名——Windows 可能错加载同名的mylib.exe或其他文件
C++ 导出 DLL 表面简单,真正卡住人的永远是名字修饰、位数对齐、内存归属这三件事。只要导出函数签名干净、调用路径明确、内存边界划清,后面的事就只是路径和依赖的体力活。










