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
CASorterAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

grayeCommented:
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
0
grayeCommented:
I hate typo's...

I messed up the API documentation part (but not the VB.Net part!).   I just now saw that when I talk about the "P" in the API documenation that I had edited the first letter out (so there is no "P").  So my comment on how to determine if a parameter is a point didn't make much sence in that example, PSP_DEV... vs SP_DEV...  

Here is how the original API documentation had it before I edit out the "P"s

    'WINSETUPAPI BOOL WINAPI
    'SetupDiEnumDeviceInterfaces(
    '    IN HDEVINFO  DeviceInfoSet,
    '    IN PSP_DEVINFO_DATA  DeviceInfoData, OPTIONAL
    '    IN LPGUID  InterfaceClassGuid,
    '    IN DWORD  MemberIndex,
    '    OUT PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData
    ');
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.