我对此有点疯狂,我已经花了几个小时才找到问题所以我想我需要一些WinAPI大师:)我使用VB .NET所以请善待:)
尝试与某些USB设备进行通信,并且在SetupDiGetDeviceInterfaceDetail()步骤中,(第一个)函数调用将失败,并显示ERROR_INVALID_USER_BUFFER。第二次调用现在没有意义了:)问题是为什么? DeviceInfoTable句柄是正确的,因为我在成功使用了更少的函数,并在每次调用后测试了Err.LastDllError。
我假设的InterfaceDataStructure也是正确的,因为其他SetupDiEnumDeviceInterfaces()将失败。我怀疑dll导入或结构的声明不正确。
If Not SetupDiGetDeviceInterfaceDetail(DeviceInfoTable, InterfaceDataStructure, Nothing, 0, StructureSize, Nothing) Then
ErrorStatus = Err.LastDllError ' <-- always 0x6F8, ERROR_INVALID_USER_BUFFER
End If
以下是声明
Dim DeviceInfoTable As IntPtr = INVALID_HANDLE_VALUE
Dim InterfaceDataStructure As SP_DEVICE_INTERFACE_DATA = New SP_DEVICE_INTERFACE_DATA
Dim InterfaceIndex As Integer = 0
Dim ErrorStatus As Integer = 0
Dim DevInfoData As SP_DEVINFO_DATA = New SP_DEVINFO_DATA
Dim dwRegType As Integer
Dim dwRegSize As Integer
Dim DetailedInterfaceDataStructure As SP_DEVICE_INTERFACE_DETAIL_DATA = New SP_DEVICE_INTERFACE_DETAIL_DATA
Dim StructureSize As Integer = 0
'Structures declarations
<StructLayout(LayoutKind.Sequential, Pack:=1)> _
Public Structure SP_DEVINFO_DATA
Public cbSize As UInteger
Public InterfaceClassGUID As Guid
Public DevInst As UInteger
Public Reserved As IntPtr
End Structure
<StructLayout(LayoutKind.Sequential, Pack:=1)> _
Public Structure SP_DEVICE_INTERFACE_DATA
Public cbSize As UInteger
Public InterfaceClassGuid As Guid
Public Flags As UInteger
Public Reserved As IntPtr
End Structure
<StructLayout(LayoutKind.Sequential, Pack:=1)> _
Public Structure SP_DEVICE_INTERFACE_DETAIL_DATA
Public cbSize As UInteger
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=256)> Public DevicePath As String
End Structure
<DllImport("setupapi.dll",
CharSet:=CharSet.Auto,
SetLastError:=True)> _
Public Shared Function SetupDiGetDeviceInterfaceDetail(ByVal hDevInfo As IntPtr,
ByRef deviceInterfaceData As SP_DEVICE_INTERFACE_DATA,
ByRef deviceInterfaceDetailData As SP_DEVICE_INTERFACE_DETAIL_DATA,
ByVal deviceInterfaceDetailDataSize As Int32,
ByRef RequiredSize As Int32,
ByRef deviceInfo As SP_DEVINFO_DATA) As Boolean
非常感谢,
答案 0 :(得分:1)
If Not SetupDiGetDeviceInterfaceDetail(..., Nothing, 0, StructureSize, Nothing)
您在使用基本的VB.NET时遇到困难,关键字 Nothing 并不意味着您希望它做什么。 api函数要求你做的是传递一个空指针。 IntPtr.Zero。那个可以什么都不是,但在这种情况下不是。您将参数类型声明为结构。它们是值类型。在值类型的情况下,没有什么意味着什么,它意味着“默认值”。所以你实际上是在这里传递一个指向结构的指针,这是一个零初始化的结构。该功能对此不满意并告诉您。
使用这些pinvoke声明时,无法传递IntPtr.Zero。您可以欺骗并声明函数的重载,它使用不同的参数类型。像这样:
<DllImport("setupapi.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Public Shared Function SetupDiGetDeviceInterfaceDetail(
ByVal hDevInfo As IntPtr,
ByRef deviceInterfaceData As SP_DEVICE_INTERFACE_DATA,
ByVal mustPassIntPtrZero As IntPtr,
ByVal mustPassZero As Int32,
ByRef RequiredSize As Int32,
ByVal mustPassIntPtrZero2 As IntPtr) As Boolean
现在您可以第一次调用该函数:
If Not SetupDiGetDeviceInterfaceDetail(..., IntPtr.Zero, 0, StructureSize, IntPtr.Zero)
您应该使用返回的RequiredSize通过Marshal.AllocHGlobal()分配内存。将返回的指针作为deviceInterfaceDetailData参数传递。现在必须将其声明为ByVal IntPtr。并在调用后使用Marshal.PtrToStructure()将其转换为结构。是的,Pack是64位操作系统上的一个问题。
通过使用CharSet:= CharSet.Auto声明结构来修复字符串问题,这样您就可以获得Unicode转换而不是Ansi转换。
答案 1 :(得分:0)
现在我想通了,实际上是半工作:)也许有人可以点亮我。
至少在VB .NET 2010上,SetupDiGetDeviceInterfaceDetail()不会将NULL(也就是没有)作为参数排成行,所以我不得不首先传递虚拟的东西:
DetailedInterfaceDataStructure.cbSize = 6
SetupDiGetDeviceInterfaceDetail(DeviceInfoTable, InterfaceDataStructure, DetailedInterfaceDataStructure, 1000, StructureSize, DevInfoData)
cbSize必须是&lt;&gt; 0和32位系统必须为6(DWORD为4,空终止宽字符串为2)。 1000它只是一个大数字,所以SetupDiGetDeviceInterfaceDetail()甚至不会返回ERROR_INSUFFICIENT_BUFFER
现在第二遍应该得到真实的东西:
SetupDiGetDeviceInterfaceDetail(DeviceInfoTable, InterfaceDataStructure, DetailedInterfaceDataStructure, StructureSize, StructureSize, Nothing)
哪个不会返回任何系统错误,但路径只是一个反斜杠字符“\”,这不好....它应该是一个有效的USB路径
“\\?\ USB#vid_01E5&安培; pid_00A2#5和; 1d4952dc&安培; 0和2#{18d0A210-85D2 -........”
任何人都可以帮助我吗?...
答案 2 :(得分:0)
是的,我正在努力使用VB,因为我来自纯C99和MCU的汇编程序:)事实上,经过几个小时的错误后,我在C#中得到了一些片段,它像魅力一样,但我必须知道为什么不是'在VB工作:)我终于解决了,部分喜欢你的建议
我用另一个重载了SetupDiGetDeviceInterfaceDetail(),只是为了接受某个非托管缓冲区的ptr:
<DllImport("setupapi.dll",
CharSet:=CharSet.Auto,
SetLastError:=True)> _
Public Shared Function SetupDiGetDeviceInterfaceDetail(ByVal hDevInfo As IntPtr,
ByRef deviceInterfaceData As SP_DEVICE_INTERFACE_DATA,
ByVal deviceInterfaceDetailData As IntPtr,
ByVal deviceInterfaceDetailDataSize As Int32,
ByRef RequiredSize As Int32,
ByRef deviceInfo As SP_DEVINFO_DATA) As Boolean
End Function
Now the problem was I used ByRef deviceInterfaceDetailData As IntPtr instead of ByVal deviceInterfaceDetailData As IntPtr, was my mistake from VB's quite simple perspective.
Indeed, now I can pass some unmanaged buffer at 2'nd call of SetupDiGetDeviceInterfaceDetail()
Dim PUnmanagedDetailedInterfaceDataStructure As IntPtr = IntPtr.Zero
PUnmanagedDetailedInterfaceDataStructure = Marshal.AllocHGlobal(StructureSize)
DetailedInterfaceDataStructure.cbSize = 6 ' cbSize = 4 bytes for DWORD + 2 bytes for Unicode null terminator
Marshal.StructureToPtr(DetailedInterfaceDataStructure, PUnmanagedDetailedInterfaceDataStructure, False) ' Copy the contents of the structure, to an unmanaged memory space
SetupDiGetDeviceInterfaceDetail(DeviceInfoTable, InterfaceDataStructure, PUnmanagedDetailedInterfaceDataStructure, StructureSize, StructureSize, DevInfoData)
这终于有效了。我希望有些积分可以挣扎:) 我在互联网上看到了很多类似的线程,但没有一个完全解决。
祝大家圣诞快乐