2014-01-07 102 views
4

问题简介:调用C DLL

我必须控制通过提供一个DLL文件,LIB文件API一定的设备,和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文件本身?
+0

这将有助于看到您正在使用的导出和导入签名。没有他们给出明确的答案是困难的。 –

+0

不,不,不,不。显然你对这个问题的猜测是行不通的。没有人能看到你所犯的错误,这不是YouTube。 –

+0

我看到有几个人投票结束了这个。请不要。 C#/ C++ P/invoke编程问题当然是堆栈溢出的话题,对于那些对P/invoke没有深入了解的人来说,它似乎是一个合理编写的问题。 –

回答

0

这种事情总是在屁股上痛。您必须确保传递的数据的字节结构与您的DLL期望的内容相符。 C#中的本地结构不知道它们是在外部传递的,所以你必须更严格地构造代码。

这里看到更多的信息:

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

+0

现在我甚至没有处理结构,只需使用参数调用某些函数即可。 –

+0

这是一个有效的观点 - 你没有使用COMPLEX结构。所有传递的变量实际上都是结构体。你需要匹配两边;即如果在您的DLL期待UINT32时传递Int32,事情并不总是正确。字符串是结构,需要特殊处理。有一个完整的站点显示了Windows API如何完成,也许你可以从那里得到一些很好的例子。 http://www.pinvoke.net/ –

4

那是因为在报头中的函数声明为dllimport的?

可能。这些功能需要导出。无论他们是否出口,取决于他们如何编译DLL,无论谁给了你。我猜他们应该是(或C++代码会尝试导入它们并失败)。
我在解决这类问题时所做的第一件事就是加载Dependency Walker中的DLL,它将向您显示所有导出的函数。如果他们没有出现,他们不会被导出,并且C#不能调用它们。如果它们出现了,那么你就可以了,你不需要改变任何C代码或创建任何包装函数。

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

编号C#只能使用DllImport调用C函数。当导出函数时,C++会做name mangling,这会使事情变得混乱并且通常不可行。

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

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

这些应该使功能导出,你应该看到它显示在依赖沃克。

从C#访问C DLL需要什么步骤?

CLR必须能够找到dll(通常只需将它放在与C#exe相同的目录中),并且必须将函数导出为C函数。这是非常多的。

在C#项目中,我还必须包含LIB文件吗?不只是DLL文件本身?

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

PS:获得依赖的步行者。我不能更强烈推荐它为这种事情

0

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

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

第一个参数Path有只为ilustration目的,我是分辩?

你可以使用depends.exe或PE Explorer(http://www.heaventools.com/download-pe-explorer.htm)打开DLL并查看DLL的导出表吗?

我问这是因为函数名饰也许,如果++的DLL被编译为C,而不是普通的C.

0

尝试declacring像这样可能发生(你只能这样做一次,以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); 

需要导出,并与外部的 “C” 声明。 __stdcall很方便,因为它是.net端的默认设置。我在我的C++项目中有一个宏,以确保每次都输入相同的宏。

是的,得到依赖行者....