C# 调用 C 写的 dll,历经千辛,缘于疏忽

jmcooler 2014-05-08 07:55:28
问题我已经解决了,写出来,只是望各位参照,以后多个小心。无用你们回答,但请你们顶贴,呵呵

用 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 的过错有多大。

...全文
443 9 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
WM_JAWIN 2014-05-08
  • 打赏
  • 举报
回复
不是要搞一个def文件么?
jimil 2014-05-08
  • 打赏
  • 举报
回复
帮顶,可惜不懂C,都是调用别人的。
laviewpbt 2014-05-08
  • 打赏
  • 举报
回复
最简单的方式就是用__stdcall + def 文件实现。
bigbaldy 2014-05-08
  • 打赏
  • 举报
回复
不写extern "C"的话导出的函数名字就不是你定义的那个,C#当然找不到
taoshuxian 2014-05-08
  • 打赏
  • 举报
回复
学习学习学习学习
gomoku 2014-05-08
  • 打赏
  • 举报
回复
相对C#,C++的入门是困难很多。 要了解: 1、函数导出 2、调用约定 3、函数名重整(name mangling)
jmcooler 2014-05-08
  • 打赏
  • 举报
回复
实话说,我是 C++ 高手,倒是不熟悉 C# 管你用不用 extern "C",都可以在 C++ 中调用该 dll。可是对于不写 extern "C" 的话,C# 就不认识。 既然是 VS 自动产生的代码(可以说,我一行代码都没改过),函数头和函数体都用宏导出,并且 C++ 能调。C# 却不认识 这多少有些让人想不通 给不熟悉写 C/C++ dll 的人多啰嗦一下: C/C++ 的 dll,确实有两种导出方式。传统的采用在 .def 文件里定义导出函数的列表 最好的方式,是采用如下的宏,前缀到函数头和函数体: #ifdef MYDLL_EXPORTS #define MYDLL_API __declspec(dllexport) //默认调用约定为 Cdecl #else #define MYDLL_API __declspec(dllimport) //默认调用约定为 Cdecl #endif 此时,在 DLL 预编译中加入宏 MYDLL_EXPORTS,则这些函数被解释成 __declspec(dllexport)。 而在调用方,不定义 MYDLL_EXPORTS 预编译宏,则函数被解释成 __declspec(dllimport) 非常自动化。你还可以添加上调用约定: #ifdef MYDLL_EXPORTS #define MYDLL_API __declspec(dllexport) WINAPI #else #define MYDLL_API __declspec(dllimport) WINAPI #endif
qwer_boo 2014-05-08
  • 打赏
  • 举报
回复
来,顶一个
arSavior 2014-05-08
  • 打赏
  • 举报
回复
帮顶,过来学习个

111,097

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧