You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#封送带C接口的C++ DLL:传递对象时遇入口点未找到问题

问题:C#调用C++ DLL时遭遇EntryPointNotFoundException错误

我尝试封装一个带C接口的C++测试DLL,这个DLL用CFFI从Python调用完全正常,但在C#里调用时遇到了问题。

我的C++ DLL代码:

#define AS_TYPE(Type, Obj) reinterpret_cast<Type *>(Obj)
#define AS_CTYPE(Type, Obj) reinterpret_cast<const Type *>(Obj)
struct mytype_s;
typedef struct mytype_s mytype_t;
namespace TestDLL {
class Test {
public:
Test() { return; }
~Test() { return; }
int test_function() const { return 314159; }
};
}
mytype_t *test_new() {
return AS_TYPE(mytype_t, new TestDLL::Test());
}
int test_function(const mytype_t *mytype) {
return AS_CTYPE(TestDLL::Test, mytype)->test_function();
}

我的C#调用代码:

[DllImport(dllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr test_new();
[DllImport(dllPath, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern int test_function(IntPtr mytype);

IntPtr mytype;
mytype = test_new();
Console.WriteLine("Alloc complete");
int result;
result = test_function(mytype);
Console.WriteLine("test: {0}", result);

遇到的错误:

Alloc complete
Unhandled Exception: System.EntryPointNotFoundException: Unable to find an entry point named 'test_function' in DLL

我想知道这是因为mytype_t的封送方式不对,还是C++到C#传递对象时有更复杂的问题?


解答:

这个问题和mytype_t的封送方式完全无关,核心原因是C++编译器的名字修饰(Name Mangling)导致的。

C为了支持函数重载,会给导出的函数名称加上额外的修饰信息,而C语言不会做这件事。你的代码里虽然写了C风格的函数接口,但编译器还是会把它们当成C函数处理,导致导出的函数名不再是test_function,而是一串被修饰后的名字(比如类似?test_function@@YAHPBUsmytype_s@@@Z这样的),这就导致C#找不到对应的入口点了。

解决方法很简单,你需要告诉编译器把这些导出函数按照C语言的规则来处理:

修改后的C++代码:

在导出的C风格函数外面加上extern "C"块:

#define AS_TYPE(Type, Obj) reinterpret_cast<Type *>(Obj)
#define AS_CTYPE(Type, Obj) reinterpret_cast<const Type *>(Obj)
struct mytype_s;
typedef struct mytype_s mytype_t;
namespace TestDLL {
class Test {
public:
Test() { return; }
~Test() { return; }
int test_function() const { return 314159; }
};
}

// 用extern "C"包裹C接口函数,避免名字修饰
extern "C" {
mytype_t *test_new() {
return AS_TYPE(mytype_t, new TestDLL::Test());
}
int test_function(const mytype_t *mytype) {
return AS_CTYPE(TestDLL::Test, mytype)->test_function();
}
}

另外,你还可以检查一下你的DLL导出表,确认函数名是否正确——可以用工具比如dumpbin /exports yourdll.dll(Windows SDK自带)来查看导出的函数名称,这样就能直观看到名字是否被修饰了。

至于你担心的mytype_t封送问题,其实你的处理是对的:因为mytype_t在C#里只是一个不透明的指针,用IntPtr来传递完全没问题,不需要做额外的封送处理。


内容的提问来源于stack exchange,提问作者port80

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:19:35