c#调用c++ dll的核心是dllimport,必须确保c++函数用extern "c"导出、调用约定匹配(如__cdecl),否则报entrypointnotfoundexception或accessviolationexception;用dumpbin /exports验证实际导出名,避免名字修饰导致找不到函数。

直接说结论:C# 调用 C++ DLL 的核心是 DllImport,但必须确保 C++ 导出函数是 C 风格、无修饰名(extern "C"),且调用约定匹配(通常是 __cdecl 或 __stdcall);否则会报 EntryPointNotFoundException 或 AccessViolationException。
怎么确认 C++ DLL 真的导出了你要的函数?
很多问题其实卡在“以为导出了,其实没导出”。C++ 默认 C++ 名字修饰(name mangling)会让函数名变成一串乱码,DllImport 根本找不到。
- 用
dumpbin /exports your.dll(VS 开发者命令行)看实际导出的符号名,确认是否是干净的函数名(如Add),而不是?Add@@YAHHH@Z - C++ 源码中必须用
extern "C" __declspec(dllexport)包裹函数,例如:extern "C" __declspec(dllexport) int __cdecl Add(int a, int b) { return a + b; } - 如果用了
__stdcall,C++ 侧要写int __stdcall Add(...),C# 侧DllImport必须显式加CallingConvention = CallingConvention.StdCall
DllImport 声明写不对,运行时就崩
声明和实际导出不一致,轻则返回错误值,重则直接 AccessViolationException —— 尤其涉及指针、结构体、字符串时。
- 字符串参数默认按
UnmanagedType.LPStr处理(ANSI),若 C++ 用的是wchar_t*,C# 必须加[MarshalAs(UnmanagedType.LPWStr)] - 结构体传参前,C# 中需加
[StructLayout(LayoutKind.Sequential)],字段顺序、对齐(Pack)必须和 C++ 完全一致 - 回调函数(function pointer)要用
delegate+UnmanagedFunctionPointer,不能直接传Action或Func - 推荐显式指定
CharSet = CharSet.Ansi或CharSet.Unicode,避免平台默认行为差异
为什么有时候能调通,换个机器就报错?
常见于依赖项缺失或架构不匹配,不是代码问题,而是环境问题。
- C# 项目平台目标(x86/x64/AnyCPU)必须和 C++ DLL 架构一致:x64 程序不能加载 x86 DLL,反之亦然
- C++ DLL 若依赖
MSVCP140.dll等 VC 运行库,目标机器没装对应版本的 Visual C++ Redistributable 就会提示The specified module could not be found - DLL 路径不在系统 PATH 或应用程序目录时,
DllImport找不到文件;建议用绝对路径或提前用LoadLibrary(通过kernel32.dll)手动加载并检查返回值 - 调试时可用 Process Monitor 监控
CreateFile操作,看它到底去哪找了哪些路径
最常被忽略的一点:C++ DLL 的全局变量、静态构造函数、线程局部存储(TLS)在 .NET Core/.NET 5+ 中行为可能和 .NET Framework 不同,跨进程域或热重载场景下容易出隐性问题。真要稳定交互,优先考虑纯函数导出,避开状态共享。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











