C++怎么生成DLL C++动态链接库封装流程【指南】

7次阅读

C++怎么生成DLL C++动态链接库封装流程【指南】

怎么用 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) 配套释放
  • 所有参数和返回值限制为基本类型(intdoubleconst char*)、指针或固定大小结构体字符串建议用 UTF-8 编码的 const char* + 长度参数
  • 别让外部语言调用 delete析构函数——内存必须由 DLL 内部分配并释放,否则可能触发不同的崩溃

怎么让 DLL 在不注册、不放系统目录也能被加载

靠修改调用方的加载路径或使用延迟加载,而不是把 DLL 扔进 System32 ——那既不安全也不便部署。

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

  • 调用方启动前,用 SetDllDirectory(L".") 把当前目录加入搜索路径(注意宽字符)
  • 或者用 LoadLibrary(L"relativepathmylib.dll") 传绝对或相对路径,比依赖系统搜索更可控
  • Visual Studio 项目中可在链接器 → 输入 → 延迟加载 DLL 里填 mylib.dll,这样首次调用函数时才加载,失败可捕获异常
  • 避免用 LoadLibrary("mylib") 不带扩展名——windows 可能错加载同名的 mylib.exe 或其他文件

C++ 导出 DLL 表面简单,真正卡住人的永远是名字修饰、位数对齐、内存归属这三件事。只要导出函数签名干净、调用路径明确、内存边界划清,后面的事就只是路径和依赖的体力活。

text=ZqhQzanResources