在c#中调用c dll

Calling c dll in C#

本文关键字:dll 调用      更新时间:2023-10-16

问题简介:

我必须通过API来控制某个设备,该API提供了一个DLL文件、LIB文件和c头文件,这些文件的函数被声明为dllimport

当我在C++项目中使用API时,一切都很好——我包含了头、lib、dll,并调用了头文件中声明的函数。

当试图使用[DllImport]属性从C#.NET项目调用这些函数时,问题就开始了:这些函数是用确切的名称和参数声明的,运行代码没有引发任何异常。然而,该设备根本没有响应,就像从未真正调用过这些函数一样。

如何在C标头中声明:

int __declspec(dllimport) Init_Card_RTx(unsigned short device_num, unsigned short enabled_channels, unsigned short xmt_channels);

如何在C#中声明:

[DllImport(Path, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Init_Card_RTx")]
public static extern int Init_Card_RTx(UInt16 device_num, UInt16 enabled_channels, UInt16 xmt_channels);

问题:

  • 这是因为标头中的函数被声明为dllimport吗
  • 在这种情况下,我是否必须用声明为dllexport的C++函数包装DLL
  • 从C#访问C DLL需要哪些步骤
  • 在C#项目中,我是否也必须包含LIB文件?不仅仅是DLL文件本身

这是因为标头中的函数被声明为dllimport吗?

可能。需要导出函数。它们是否被导出取决于它们的DLL是如何由提供给你的人编译的。我想它们应该是(或者C++代码会尝试导入它们并失败)
排除此类故障时,我要做的第一件事是在Dependency Walker中加载DLL,它将向您显示所有导出的函数。如果它们没有出现,它们就不会被导出,C#也不能调用它们。如果它们出现了,那么您就可以了,不需要更改任何C代码或创建任何包装函数。

在这种情况下,我是否必须用声明为dllexport的C++函数包装DLL?

否。C#只能使用DllImport调用C函数。C++在导出函数时会进行名称篡改,这会使事情变得一团糟,而且通常不可行。

您需要做的是以某种方式导出您的函数。我的猜测是,它们已经导出了,但如果没有,您可以制作一些这样的包装器函数。

int __declspec(dllexport) Init_Card_RTx(unsigned short device_num, unsigned short enabled_channels, unsigned short xmt_channels) {
// just call the other function here
}

这些应该会使函数导出,并且您应该看到它显示在依赖项walker中。

从C#访问C DLL需要哪些步骤?

CLR必须能够找到dll(通常只需将其与C#exe放在同一目录中),并且函数必须导出为C函数。差不多了。

在C#项目中,我是否也必须包含LIB文件?不仅仅是DLL文件本身?

您根本不需要在C#项目中包含任何内容,只需要包含带有DllImport属性的public static extern包装函数即可。只要CLR能够在运行时找到dll,这就是您所需要的。如果它在运行时找不到它,那么在调用第一个导入的方法时应该会得到一个异常。

附言:获取依赖助行器。对于这种东西,我再怎么推荐它也不为过了

这种事情总是让人头疼。您必须确保传递的数据的字节结构与DLL所期望的一致,并且准确无误。C#中的本机结构不知道它们是从外部传递的,所以必须更严格地构造代码。

请参阅此处了解更多信息:

http://msdn.microsoft.com/en-us/library/awbckfbz(v=vs.110).aspx

函数被声明为dllimport的原因是(如果我错了,请纠正我)DLL是由您的卡供应商提供的,这没关系,因为只有在构建DLL时才需要dllexport

[DllImport(Path, CallingConvention = CallingConvention.Cdecl, EntryPoint = "Init_Card_RTx")]

第一个论点Path只是为了说明问题,对吗?

你能用dependens.exe或PE资源管理器打开DLL吗(http://www.heaventools.com/download-pe-explorer.htm)并查看DLL的导出表?

我之所以这么问,是因为函数名可能被修饰了,如果DLL被编译为C++而不是普通的C.,就会发生这种情况

试着这样解密(在CPP文件中只做一次,而不是头文件)

extern "C" __declspec(dllexport) int __stdcall Init_Card_RTx(unsigned short device_num, unsigned short enabled_channels, unsigned short xmt_channels)
{
//
}

在C#中:

[DllImport("MyDll.dll")]
int Init_Card_RTx(ushort device_num, ushort enabled_channels, ushort xmt_channels);

您需要导出它并用extern"C"声明__stdcall很方便,因为它是.net端的默认值。我在C++项目中有一个宏,以确保每次都键入相同的宏。

是的,依赖行者。。。。