C# DLLImport->;如何在C中处理句柄# 我的C代码中,我想导入一个C++ DLL。我使用dllimport,它可以很好地处理一些函数。但是在一个函数中,我得到了一个句柄,我需要稍后调用另一个函数 [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

C# DLLImport->;如何在C中处理句柄# 我的C代码中,我想导入一个C++ DLL。我使用dllimport,它可以很好地处理一些函数。但是在一个函数中,我得到了一个句柄,我需要稍后调用另一个函数 [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,c#,c++,dllimport,handle,intptr,C#,C++,Dllimport,Handle,Intptr,在我的代码中,这些函数的调用方式如下: 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); 如果我

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

   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,使其正常工作? 致意

托比试试这个:

   [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
编辑:

@汉斯·帕桑是对的。这是将字节[]传递给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

你试过西蒙·穆里尔给出的答案了吗?他是第一个提供此声明的人,他的回答值得接受。

您的SI_Write函数与Windows内核32非常相似

所以,我会这样做:

[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);
编辑:我在网上找到了这篇文档,它指出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。

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

下一个可能的错误是您没有在[DllImport]语句中使用CallingConvention属性。很可能需要,除非本机函数是用u stdcall声明的,否则Cdecl是默认值。这也是调用kaboom的一个很好的方法。如果仍然有问题,则必须调试本机代码

顺便说一句,在两个函数中都使用out而不是ref.来摆脱笨拙的语法

   [DllImport("SiUSBXp.dll", CallingConvention = CallingConvention.Cdecl)]
   public static extern int SI_Open(UInt32 deviceNum, out IntPtr devHandle );
错误:
静态外部无效DoStuff(**字节[]输入字节**)


好:
static extern void DoStuff(**[In,marshallas(UnmanagedType.LPArray)]字节[]inputByte** < /P> SIEOPEN和SIO写的C++函数原型是什么样的?您将字节数组初始化为10个元素,但这足够用于SIAWrad函数吗?siiStaseWiAPI siAuthOn(DWord DWDebug,句柄*CyPrAd);SI_状态WINAPI SI_写入(句柄cyHandle、LPVOID lpBuffer、DWORD dwBytesToWrite、LPDWORD LPDWBYTESSWRITED);对于字节数组=>它用C++代码中的“相同”数组工作。此外,我还尝试了一些方法->我初始化了一个类似“IntPtr Test=new IntPtr()”的IntPtr-当我用这个IntPtr调用Write函数时,它不会引发异常…因此我实际上认为错误与IntPtr有关,但我尝试写入的字节没有正确写入uC:(调用后写入的BytesWrite的值是多少?此答案可能不正确,数组已作为指针(LPVOID)传递。声明为ref将使其成为指向指针(LPVOID*)的指针。在本例中,我将获得“通常”AccessViolation异常…所以至少我们指出错误在字节数组中,而不是IntPtr!我确实检查了返回值(并且SI_Open成功),但我只是删除了它,以便您对源代码的关键点有一个更清晰的了解。请毫不犹豫地在MSDN库中查找。发布更新。但它不应该是“CallingConvention.Stdcall”而不是Cdecl吗?因为在MSDN上它说“被调用方清理堆栈。这是使用平台调用调用非托管函数的默认约定。"是的,它是默认的。只有负责任的C/C++程序员在声明中使用“y-STDCKED关键字”。这才不常见。我看不出这里的代码,你就更接近了。“托比-奇怪。也许C++实现做了一些不寻常的事情。当你说它不起作用时,它仍然是访问权限。异常错误?没错……我不知道问题出在哪里。如果我a)将SI_Write中的缓冲区声明为out(但正如在另一个答案中已经提到的,这实际上是错误的),我可以解决这个问题。如果我这样做,我会得到到达设备的奇怪值。和b)如果我声明要写入的字节数为零,但是,嘿,这也不是解决方案^^-但是我认为问题在于字节数组,因为我可以使用IntPtr调用SI_Close函数(这里没有提到)而不会出现问题!好吧,我有一个好消息和一个坏消息-好消息是,这个错误没有发生-现在^^-坏消息是现在SI_Write函数返回12(0x0C),它在头中定义为:SI_SYSTEM_error_CODE 0x0C-现在要做一些尝试和错误,然后再报告。@Toby-从文档中,SI_SYSTEM_ERROR_代码意味着您现在可以使用Marshal.GetLastWin32Error并获取“真实”的底层windows错误。请注意,我在回答中已将SetLastError添加到C#原型中,因此Marshal.GetLastWin32Error将起作用。哦,我亲爱的上帝,它起作用了!!!实际上,我做了一个小小的改变——我从上一个IntPtr中删除了“out”关键字。-->静态外部内部写入(IntPtr句柄、字节[]缓冲区、uint NumBytesToWrite、out uint NUMBYTESWORITED、IntPtr o);现在数据正确到达设备,功能正确关闭!所以我会说就这样。。。?或者删除out关键字是错误的??!无论如何,我已经想告诉你->非常感谢你花时间帮助我!!!