4

在我的 C# 代码中,我想导入一个 C++ DLL。我使用 dllimport,它可以很好地处理一些功能。但是在一个函数中,我得到了一个 HANDLE,稍后我需要调用另一个函数。

   [DllImport("SiUSBXp.dll")]
   public static extern int SI_Open(UInt32 deviceNum,ref IntPtr devHandle );   // this function gets the HANDLE
   [DllImport("SiUSBXp.dll")]
   public static extern int SI_Write([In]IntPtr devHandle, [In, Out] byte[] inputByte, UInt32 size,ref UInt32 bytesWritten); // this function needs the HANDLE

在我的代码中,这些函数的调用方式如下:

   IntPtr devHandle = new IntPtr();
   UInt32 bytesWritten = new UInt32();
   byte[] byteArr = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
   SI_Open(0, ref devHandle);
   SI_Write(devHandle, byteArr, 10, ref bytesWritten);

如果我这样做,我会得到一个“System.AccessViolationException”。我在这里和互联网上搜索过,但没有找到具体的答案。如何正确使用 IntPtr,使其正常工作?最好的祝福

托比

4

4 回答 4

1

试试这个:

   [DllImport("SiUSBXp.dll")]
   public static extern int SI_Open(UInt32 deviceNum, ref IntPtr devHandle);   // this function gets the HANDLE
   [DllImport("SiUSBXp.dll")]
   public static extern int SI_Write(IntPtr devHandle, ref byte[] inputByte, UInt32 size, ref UInt32 bytesWritten); // this function needs the HANDLE

编辑:

@Hans Passant 是对的。这是将 byte[] 传递给 LPVOID 参数的正确方法。ref 用于将对象强制转换为 LPVOID,但数组不需要。当你尝试这个时会发生什么?

   [DllImport("SiUSBXp.dll")]
   public static extern int SI_Write(IntPtr devHandle, byte[] inputByte, UInt32 size, ref UInt32 bytesWritten); // this function needs the HANDLE

您是否尝试过@Simon Mourier 给出的答案?他是第一个提供此声明的人,他的回答值得接受。

于 2011-05-08T16:41:16.970 回答
1

您的 SI_Write 函数看起来很像 Windows Kernel32 的WriteFile

所以,我会这样做:

[DllImport("SiUSBXp.dll", SetLastError = true)]
static extern int SI_Open(uint dwDevice, ref IntPtr cyHandle);  

[DllImport("SiUSBXp.dll", SetLastError = true)]
static extern int SI_Write(IntPtr cyHandle, byte[] lpBuffer,
   uint dwBytesToWrite, out uint lpdwBytesWritten);

编辑:我在网上找到了这个文档USBXPRESS® PROGRAMMER'S GUIDE,它指出 SI_Write 原型实际上看起来比我想象的更接近 WriteFile。该文档指出:

SI_STATUS SI_Write (HANDLE Handle, LPVOID Buffer, DWORD NumBytesToWrite,
DWORD *NumBytesWritten, OVERLAPPED* o = NULL)

这意味着 .NET 原型应该是这样的:

[DllImport("SiUSBXp.dll")]
static extern int SI_Write(IntPtr Handle, byte[] Buffer,
   uint NumBytesToWrite, out uint NumBytesWritten, IntPtr o);

o是可选的,因此您可以传递 IntPtr.Zero。

于 2011-05-08T17:19:01.307 回答
1

你犯了一个典型的 C 程序员错误,你没有检查函数的返回值。它告诉您该功能是否失败。一种可能的情况是 SI_Open() 返回了失败代码。您忽略它并使用未初始化的句柄值。卡布姆并不罕见。

下一个可能的错误是您没有在 [DllImport] 语句中使用 CallingConvention 属性。很有可能需要,除非使用 __stdcall 声明本机函数,否则 Cdecl 是默认值。也是调用 kaboom 的绝佳方式。如果您仍然遇到问题,那么您将不得不调试本机代码。

顺便说一句,您可以通过使用out而不是ref来摆脱尴尬的语法。在这两个功能中。

   [DllImport("SiUSBXp.dll", CallingConvention = CallingConvention.Cdecl)]
   public static extern int SI_Open(UInt32 deviceNum, out IntPtr devHandle );
于 2011-05-08T18:16:40.853 回答
0

坏的: static extern void DoStuff(**byte[] inputByte**);

好的: static extern void DoStuff(**[In, MarshalAs(UnmanagedType.LPArray)] byte[] inputByte**);

于 2012-04-12T00:11:53.117 回答