从 C 编译的 Dll 调用 C# 中的方法






2.84/5 (17投票s)
2004年5月2日
4分钟阅读

163638
描述了如何通过 C 中编译的 Dll 将 'C' 代码与 C# 进行接口。
网上有一些关于如何从 C# 调用 user.dll 中的 Win32 方法的例子,但我没有找到任何文章明确说明如何先用纯粹的“C”语言创建一个 DLL,然后从 C# 中导入该“C” DLL 中的方法。
这自然会引出一个问题:为什么要首先编写一个“C” DLL 呢?
嗯,在我的例子中(我会尽量简短),我有一个十五年前的 ISA 卡,它支持八个电子继电器。这些继电器可以通过计算机控制,通过 IO 总线来开关电子设备。这就是乐趣开始的地方,因为你不能像以前在旧版 Windows 中那样直接使用 ANSI “C” 方法 outportb() 将值直接发送到 IO 端口(当时所有进程共享同一个内存堆,这会导致所有那些有趣的访问冲突)。
我找到了一个现成的用“C”语言编写的设备驱动程序,它允许进程访问 XP 中的 IO 端口,但为了从 C# 调用 outportb(), 仍然需要我编写一个用“C”语言编写的“适配器” DLL。
我知道如何在使用 [DllImport()] 属性导入 user.dll 等中的本机 Win32 方法,但我发现这种技术对我自己用“C”语言编写的 DLL 不起作用。
第一个问题是 C# 编译器一直抛出错误,说“无法在 DLL PortIO.dll 中找到名为 OpenIO 的入口点”。仔细查看 OpenIO 中的方法签名后,我找不到任何问题,然后我才想起需要使用 .DEF 文件或之类的东西。我通过 Google 搜索找到了一些零散的信息,但没有解决我问题的文章。
总而言之,以下是学到的教训(有些是重温的):
- 在使用 .Net 编译器(或者 VC6 编译器)处理扩展名为 *.cpp 的源文件的“C”项目时,你必须通过将公共的(__declspec(dllexport) = 在“C”中是 public 的)方法包含在用 ‘extern “C”’ 定义的块中,或者使用 .DEF 文件。我选择了使用 ‘extern “C”’。名称修饰是 C++ 编译器区分具有相同名称的重载方法的方式。请注意,你不能重载任何包含在 ‘extern “C”’ 中的方法。我相信使用 VC6,可以通过简单地将源文件扩展名更改为 *.c 来关闭名称修饰,但我没有在 VS.Net 中尝试过。
- 你可以通过使用 DllImport 的 EntryPoint 参数来导入名称修饰过的或任何其他公共方法,该参数可以接受一个序号索引或方法名。我在示例代码中同时使用了方法名和序号位置来演示这一点。
- Dumpbin.exe(随 VS.Net 一起提供)对于排查用“C”语言编写的 DLL 非常有用。如何使用它以及示例输出在源代码的注释中。
- 如果你不在你的“C” DLL 函数定义(头文件 [.h] 中的原型)和声明(*.c 或 *.cpp 文件中的函数体)中包含 __declspec(dllexport) 修饰符,那么该方法将不会被导出为“public”,并且入口点也不会显示在 DLL 的二进制转储中。
extern "C"
{
//注意:必须使用 __declspec(dllexport) 来使(导出)方法为 'public'
__declspec(dllexport) void DoSomethingInC(unsigned short int ExampleParam, unsigned char AnotherExampleParam)
{
printf("You called method DoSomethingInC(), You passed in %d and %c\n\r", ExampleParam, AnotherExampleParam);
}
}//结束 'extern "C"' 以防止名称修饰
以下是 C# 中的导入声明:
[DllImport("C_DLL_with_Csharp.dll", EntryPoint="DoSomethingInC")]
public static extern voidDoSomethingInC(ushortExampleParam,charAnotherExampleParam);
以下是 DLL 转储的样子:
文件类型:DLL
段包含 C_DLL_with_Csharp.dll 的以下导出项
00000000 特性
409557E6 时间日期戳 2004 年 5 月 2 日星期日 13:19:50
0.00 版本
1 序号基数
2 函数数量
2 名称数量
序号 提示 RVA 名称
1 0 00011596 ?DoSomethingInMangledC@@YAXPAD@Z
2 1 0001110E DoSomethingInC
摘要
4000 .data
1000 .idata
5000 .rdata
2000 .reloc
1F000 .text
10000 .textbss