在我的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,它有效吗? 最诚挚的问候
托比
答案 0 :(得分: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给出的答案?他是第一个提供这个声明的人,他的回答值得接受。
答案 1 :(得分: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。
答案 2 :(得分:1)
你正在犯一个经典的C程序员错误,你不检查函数的返回值。它会告诉您函数是否失败。可能的情况是SI_Open()返回了失败代码。您忽略它并使用未初始化的句柄值。 kaboom并不罕见。
下一个可能的错误是您不在[DllImport]语句中使用CallingConvention属性。它很可能是必需的,除非使用__stdcall声明本机函数,否则Cdecl是默认值。也是调用kaboom的绝佳方式。如果您仍然遇到问题,那么您将不得不调试本机代码。
顺便说一句,你通过使用 out 而不是 ref 来摆脱笨拙的语法。在这两个函数中。
[DllImport("SiUSBXp.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int SI_Open(UInt32 deviceNum, out IntPtr devHandle );
答案 3 :(得分:0)
坏: static extern void DoStuff(**byte[] inputByte**);
好: static extern void DoStuff(**[In, MarshalAs(UnmanagedType.LPArray)] byte[] inputByte**);