如何正确将C++/CLR包装器链接到非托管C++ DLL并在C#中使用
解决非托管C++ DLL与C++/CLR包装器、C#项目的兼容配置问题
我之前也碰到过完全一样的问题,核心症结在于非托管DLL不能直接作为程序集引用给CLR项目,而且运行时CLR进程需要能定位到非托管DLL的位置。下面是一步步的具体解决办法:
一、统一非托管C++ DLL的编译基础配置
- 对齐平台工具集:
右键非托管项目 → 属性 → 配置属性 → 常规 → 平台工具集,选择和你的C++/CLR项目完全一致的版本(比如VS2017对应的v141),避免因工具集版本差异导致的兼容性问题。 - 统一目标平台架构:
确保非托管项目、CLR项目、C#项目的目标平台完全一致(要么全是x86,要么全是x64),跨架构的依赖会直接导致加载失败。操作路径:右键项目 → 属性 → 配置属性 → 常规 → 平台。 - (可选)统一输出目录:
把非托管项目的输出目录改成和CLR项目一致,比如设置为$(SolutionDir)$(Configuration)\,这样编译后两个DLL会自动放在同一个文件夹,减少运行时的路径问题。操作路径:右键非托管项目 → 属性 → 配置属性 → 常规 → 输出目录。
二、正确在C++/CLR项目中关联非托管DLL
非托管DLL不能直接通过“添加引用”关联,要通过链接器配置来实现:
- 添加头文件路径:
右键CLR项目 → 属性 → 配置属性 → VC++目录 → 包含目录,添加非托管项目的头文件所在路径(比如../Project2/)。 - 添加库文件路径:
同样在VC++目录 → 库目录,添加非托管项目的输出目录(比如$(SolutionDir)$(Configuration)\),让链接器能找到非托管DLL对应的.lib文件。 - 配置链接器依赖:
进入链接器 → 输入 → 附加依赖项,添加非托管DLL对应的.lib文件名(比如Project2.lib)—— 只要你在非托管代码里用了__declspec(dllexport),编译时默认会生成这个.lib文件。
三、确保运行时非托管DLL可被找到
即使编译通过,CLR进程(也就是你的C#程序)运行时必须能找到非托管DLL,这里推荐几种靠谱的方式:
- 自动复制到C#输出目录:
右键非托管项目 → 属性 → 生成事件 → 后期生成事件 → 命令行,添加复制命令:
这样每次编译非托管项目,都会自动把DLL复制到C#程序的运行目录。copy "$(TargetPath)" "$(SolutionDir)ConsoleApp3\bin\$(Configuration)\" - 临时添加环境变量(仅开发阶段用):
把非托管DLL的输出目录添加到系统PATH环境变量里,CLR进程会自动从PATH路径查找依赖。 - 代码中指定路径(灵活但需要额外代码):
在C#程序启动时,通过调用Win32 API的SetDllDirectory方法,手动指定非托管DLL的存放路径。
四、代码细节优化(避免名字修饰问题)
你的代码里可以加个小优化:给非托管函数加上extern "C",避免C++的名字修饰导致CLR项目找不到函数。修改非托管头文件UnmanagedHeader.h:
// UnmanagedHeader.h #pragma once extern "C" __declspec(dllexport) void HelloDLL();
按照上面的步骤配置完成后,重新编译所有项目,运行C#程序应该就能正常调用非托管DLL的函数了。
内容的提问来源于stack exchange,提问作者Henry
相关产品推荐
相关产品推荐

