Help calling SetupDiEnumDeviceInterfaces  from VB.NET

Posted on 2007-03-30
Last Modified: 2013-11-26
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

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

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()

            '// 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
            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
            Dim GUID_DEVINTERFACE_GRMNUSB As New Guid(&H2C9C45C2L, &H8E7D, &H4C08, &HA1, &H2D, &H81, &H6B, &HBA, &HE7, &H22, &HC0)

            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)
            If Not result Then
                If GetLastError() = ERROR_NO_MORE_ITEMS Then
                    gHandle = 0
                    GoTo CommonExit
                End If
            End If
        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
Question by:CASorter
  • 2
LVL 41

Expert Comment

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

    '    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
       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
    <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
LVL 41

Accepted Solution

graye earned 500 total points
ID: 18827517
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

    '    IN HDEVINFO  DeviceInfoSet,
    '    IN PSP_DEVINFO_DATA  DeviceInfoData, OPTIONAL
    '    IN LPGUID  InterfaceClassGuid,
    '    IN DWORD  MemberIndex,
    '    OUT PSP_DEVICE_INTERFACE_DATA  DeviceInterfaceData

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Have you ever wanted to restrict the users input in a textbox to numbers, and while doing that make sure that they can't 'cheat' by pasting in non-numeric text? Of course you can do that with code you write yourself but it's tedious and error-prone …
When designing a form there are several BorderStyles to choose from, all of which can be classified as either 'Fixed' or 'Sizable' and I'd guess that 'Fixed Single' or one of the other fixed types is the most popular choice. I assume it's the most p…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

867 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now