0

我对此有点疯狂,我已经花了几个小时来找到问题,所以我想我需要一些 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

首先十分感谢,

4

3 回答 3

1
If Not SetupDiGetDeviceInterfaceDetail(..., Nothing, 0, StructureSize, Nothing)

您在这里为基本的 VB.NET 使用而苦苦挣扎,关键字Nothing并不意味着您希望它做的事情。api 函数想要你做的是传递一个空指针。IntPtr. 零。那可能是Nothing,但在这种情况下不是。您将参数类型声明为结构。它们是值类型。在值类型的情况下,没有什么别的意思,它意味着“默认值”。所以你实际上在这里传递了一个指向结构的指针,一个零初始化的结构。该功能对此不满意并告诉您。

当您使用这些 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 转换。

于 2012-12-20T20:56:30.673 回答
0

现在我想通了,实际上工作了一半 :) 也许有人可以照亮我。

至少在 VB .NET 2010 上,SetupDiGetDeviceInterfaceDetail() 不会将 NULL(也就是什么都没有)作为参数,所以我必须首先传递一些虚拟的东西:

    DetailedInterfaceDataStructure.cbSize = 6

    SetupDiGetDeviceInterfaceDetail(DeviceInfoTable, InterfaceDataStructure, DetailedInterfaceDataStructure, 1000, StructureSize, DevInfoData)  

cbSize 必须为 <> 0,在 32 位系统上必须为 6(4 用于 DWORD,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-........”

任何人都可以帮助我吗?...

于 2012-12-20T20:01:18.853 回答
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)

这终于奏效了。我期待一些挣扎的要点:)我在互联网上看到了很多类似的线程,但没有一个可以完全解决。

祝大家圣诞节快乐

于 2012-12-20T22:06:34.237 回答