Link to home
Start Free TrialLog in
Avatar of CASorter
CASorterFlag for United States of America

asked on

Help calling SetupDiEnumDeviceInterfaces from VB.NET

I've been pounding on this pretty hard, and have yet to find a solution.
I need to call the SetupDiEnumDeviceInterfaces API function from VB.NET (Not C#). I get a PInvoke error which usually results from not having declared something properly. Any help would be greatly appreciated!!!

Public Structure SP_DEVINFO_DATA
      Public cbSize As Long
      Public ClassGuid As Guid
      Public DevInst As Long
      Public Reserved As Long
End Structure

Public Structure SP_DEVICE_INTERFACE_DATA
        Dim cbSize As Int64
        Dim InterfaceClassGuid As Guid
        Dim Flags As Integer
        Dim Reserved As UInt32
End Structure

Public Enum DEVICEFLAGS
    DIGCF_ALLCLASSES = &H4&
    DIGCF_DEVICEINTERFACE = &H10
    DIGCF_PRESENT = &H2
    DIGCF_PROFILE = &H8
End Enum

Public Declare Function SetupDiGetDeviceInterfaceDetail  lib "setupapi.dll" Alias  "SetupDiGetDeviceInterfaceDetailA" (ByVal DeviceInfoSet As Integer, ByRef DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA, ByVal DeviceInterfaceDetailData As Integer,  ByVal DeviceInterfaceDetailDataSize As Integer, ByRef RequiredSize As Integer, ByVal DeviceInfoData As Integer) As Integer

Public Declare Auto Function SetupDiEnumDeviceInterfaces Lib "setupapi.dll" (ByVal Handle As Long, ByVal InfoPtr As IntPtr, ByRef GuidPtr As IntPtr,  ByVal MemberIndex As Integer, ByRef InterfaceDataPtr As IntPtr) As Boolean

Public Declare Function SetupDiGetClassDevs Lib "setupapi.dll"           Alias "SetupDiGetClassDevsA" (ByRef ClassGuid As IntPtr, ByVal Enumerator As String,  ByVal hwndParent As Int32, ByVal flags As DEVICEFLAGS) As Int64

    Private Sub Initialize()
        Try

   IOCTL_ASYNC_IN = CTL_CODE(FILE_DEVICE_UNKNOWN, 850,   METHOD_BUFFERED, FILE_ANY_ACCESS)
1010:       IOCTL_USB_PACKET_SIZE = CTL_CODE(FILE_DEVICE_UNKNOWN, 851, METHOD_BUFFERED, FILE_ANY_ACCESS)
            '// Make all the necessary Windows calls to get a handle to our USB device
1015:       Dim szOfPacket_T As Integer
            Dim theBytesReturned As Long = 0
            Dim theDevInfoData As Int64
            Dim theDevInfo As Int64
            Dim theInterfaceData As SP_DEVICE_INTERFACE_DATA
            Dim holderForSizeCalc As SP_DEVINFO_DATA
            Dim hldForSP_DEVINFO_DATA As New SP_DEVINFO_DATA
            Dim holderForPacket_t As Packet_T
            Dim devDetailData As SP_DEVICE_INTERFACE_DETAIL_DATA
            Dim ptrToDevDetailData As IntPtr

1025:       theDevInfoData = Marshal.SizeOf(hldForSP_DEVINFO_DATA)
            hldForSP_DEVINFO_DATA.cbSize = Marshal.SizeOf(hldForSP_DEVINFO_DATA)

            Dim theStartSessionPacket As Packet_T
            theStartSessionPacket.mPacketId = 0
            theStartSessionPacket.mReserved3 = 5
            theStartSessionPacket.mDataSize = 0
            theStartSessionPacket.mData = 0
1040:
            szOfPacket_T = Marshal.SizeOf(holderForPacket_t)
1045:       Dim thePacket As IntPtr
            thePacket = Marshal.AllocHGlobal(szOfPacket_T)

1050:       Dim gd As Guid
            Dim devcFlags As DEVICEFLAGS
1060:       devcFlags = DEVICEFLAGS.DIGCF_PRESENT Or DEVICEFLAGS.DIGCF_DEVICEINTERFACE
            Dim GUID_DEVINTERFACE_GRMNUSB As New Guid(&H2C9C45C2L, &H8E7D, &H4C08, &HA1, &H2D, &H81, &H6B, &HBA, &HE7, &H22, &HC0)
            gd = GUID_DEVINTERFACE_GRMNUSB

            Dim s1 As String = DEVICE_CLASS_USB_DEVICE
            Dim ptr As IntPtr = Marshal.StringToHGlobalAuto(s1)
            Dim guidPtr As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(gd))
            'The SetupDiGetClassDevs function retrieves a device information set
            'that contains all the devices of a specified class
1080:       theDevInfo = SetupDiGetClassDevs(guidPtr, 0&, callersHandle, devcFlags)

1090:       Dim ptrToTheIntfData As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(theInterfaceData))
            theInterfaceData.cbSize = Marshal.SizeOf(theInterfaceData)
1095:       Marshal.StructureToPtr(theInterfaceData, ptrToTheIntfData, False)

1100:       Dim result As Boolean
            'The SetupDiEnumDeviceInterfaces function retrieves a context structure for a device
            'interface of a device information set. Each call returns information about one device
            'interface. The function can be called repeatedly to get information about several
            'interfaces exposed by one or more devices.
            result = SetupDiEnumDeviceInterfaces(theDevInfo, 0&, guidPtr, 0, ptrToTheIntfData)
"ABOVE GIVES THE PINVOKE ERROR
            If Not result Then
                If GetLastError() = ERROR_NO_MORE_ITEMS Then
                    gHandle = 0
                    GoTo CommonExit
                End If
            End If
CommonExit:
        Catch ex As Exception
            Dim sNum As Long
            sNum = GetLastError()
            Dim errText As String
            errText = FormatError("Error initializing USB Device.")
            MsgBox(errText, MsgBoxStyle.Critical, "Error Initializing USB Device")
            LogError(errText, "USBComm::Initialize")
        End Try
    End Sub
Avatar of graye
graye
Flag of United States of America image

Let's do a quick review on how to translate API documenation into VB.Net Declare statements...

    'WINSETUPAPI BOOL WINAPI
    'SetupDiEnumDeviceInterfaces(
    '    IN HDEVINFO  DeviceInfoSet,                                               <- "H" means handle (a pointer to a handle obtained by SetupDiGetClassDevs)
    '    IN SP_DEVINFO_DATA  DeviceInfoData, OPTIONAL              <- "P" means pointer to a SP_DEVINFO_DATA structure
    '    IN LPGUID  InterfaceClassGuid,                                           <- "LP" means a long pointer (in this case a GUID)
    '    IN DWORD  MemberIndex,                                                   <- Integer
    '    OUT SP_DEVICE_INTERFACE_DATA  DeviceInterfaceData    <- "P" means pointer to a SP_DEVICE_INTERFACE_DATA  structure
    ');
    Declare Auto Function SetupDiEnumDeviceInterfaces Lib "" ( _
        ByVal DeviceInfoSet As IntPtr, _                                                    <- this might seem strange, but ByVal is correct for an IntPtr that is a pointer to a handle
        ByRef DeviceInfoData As SP_DEVINFO_DATA, _                            <- structures are value types, so a ByRef make is this a pointer
        ByRef InterfaceClassGuid As Guid, _                                             <- likewise, a ByRef makes this a pointer
        ByVal MemberIndex As Integer, _                                                 <- plain ole integer
        ByRef DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA _    <- ByRef makes this a pointer to a structure
    )

Optionally, you could substitute
       ByVal DeviceInfoSet As IntPtr         <- the preferred method
with
       ByRef DeviceInfoSet as Integer

As for the structures, all API-style structures are "packed", so we need to decorate the structures with the LayoutKind.Sequential attribute

    'typedef struct _SP_DEVINFO_DATA {
    '  DWORD  cbSize;                                           <- Integer
    '  GUID  ClassGuid;                                          <- GUID
    '  DWORD  DevInst;                                         <- Integer
    '  ULONG_PTR  Reserved;                                <- pointer to an usigned long
    '} SP_DEVINFO_DATA, *PSP_DEVINFO_DATA;
    <StructLayout(LayoutKind.Sequential)> _
        Structure SP_DEVINFO_DATA
        Dim cbSize As Integer
        Dim ClassGuid As Guid
        Dim DevInst As Integer
        Dim Reserved As IntPtr
    End Structure

I only did one API declare and one structure, but I bet you can take it from here.

... if not, let us know and we'll continue
ASKER CERTIFIED SOLUTION
Avatar of graye
graye
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial