C# 调用 C 写的 dll,历经千辛,缘于疏忽
问题我已经解决了,写出来,只是望各位参照,以后多个小心。无用你们回答,但请你们顶贴,呵呵
用 VS 2010 写了一个 C 的 win32 dll,就连最简单的函数 void Func(),都无法在另外一个 C# 工程里被调用,总是提示"无法找到这个函数的入口"。有这么蹊跷么,办法用尽,还是调不了。
首先,怀疑是函数名 Copy 错了,再次几个调用约定都试过了。在网上找了一大堆资料,包括 C# 调用C 注意事项,微软官方的例子,整个比对下来,没发现我的代码有任何问题。
于是开始怀疑 VS 2010 建的 C 动态库,有自身的 Bug。
可是整个动态库,无论用什么查看软件,都能清楚地看见输出函数的列表。
网上一些人的 dll 中,总是有 extern "C" __declspec(dllexport) void Func(),这引起了我的注意,我也原样照搬。然而编译时 VS 提示我,extern "C" 是古老的用法,我不得不又去掉 extern "C" 字样。问题仍然如初。
我差点想下载一个 VC6 来建立和编译我的 dll,不过,随着折腾越多,有些不经意的发现起了作用
我发现,我建的 win32 动态库,默认添加了输出宏:
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport)
#else
#define MYDLL_API __declspec(dllimport)
#endif
头文件中的函数声明和.c 文件中的函数体,都加了 DLL_API 来输出函数:
MYDLL_API void Func();
MYDLL_API void Func() { }
显然,就是没有 extern "C" 字样。
首先干掉输出宏,并干掉头文件中的函数声明,直接将函数体写为 __declspec(dllexport) void Func() { },然而还是不行
真是不可思议,黔驴技穷了。
偶然间想起来,刚刚 extern "C" __declspec(dllexport) void Func() { } 在函数体前面加了 extern "C",但函数声明里,还是用的输出宏,换句话说,函数体是 extern "C" __declspec(dllexport) void Func() { },但头文件里的声明仍旧是 __declspec(dllexport) void Func();
这种不一致,导致 VS 提示 extern "C" 是古老的用法,误导了我,我还以为 VS2010 真就不支持 extern "C" 了呢。
当将函数体写为 extern "C" __declspec(dllexport) void Func() { } 之后,这次,报的错是,调用约定不一致,加上 CallingConvention = CallingConvention.Cdecl 之后,即成功了。
一切都是因为 VS2010 的 Bug 和误导,才让我折腾了一整天。
结论就是:VS2010 建立的 win32 动态库,按照默认输出宏,虽然编出的 DLL 完全正确,但 C# 就是不认识。
唯有仅写函数体为:
extern "C" __declspec(dllexport) void Func()
{
}
方可被 C# 识别,你说 VS 的过错有多大。