Working With Devices: Actually getting to the devices

Up to this point we've worked with Device Classes. We now should get into the actual devices. Devices are grouped into Device Information Sets. If I understand Microsoft's description of it, Devices are grouped by Device Setup and Device Interface Classes. As mentioned previously Setup Classes are things like Network Adapters, while Interface Classes are things like PCI connections. These groupings can be pulled by using the SetupDiGetClassDevs function.

Private Declare Auto Function SetupDiGetClassDevs Lib "Setupapi.dll" (ByRef ClassGuid As Guid, ByVal Enumerator As UInt32, ByVal hwndParent As IntPtr, ByVal Flags As UInt32) As IntPtr

Out of the four arguments, I am only going to use the first and last. The first argument is the Guid that I want to retrieve. The Guid(s) we retrieved from the SetupDiClassGuidsFromNames can be used here. I think that Device Interface Class Guids could be used as well, I just never had a need for it.

The second argument are the flags we will use. The enumeration is defined below. You can refer to the function definition as to which one you want to use. You probably want to experiment with these to see which one suits your needs. I think that Present and Profile are your best bets if you are unsure.

'Scope to retrieve devices
Public Enum DeviceInfoSet_Scope
DIGCF_DEFAULT = &H1
DIGCF_PRESENT = &H2
DIGCF_ALLCLASSES = &H4
DIGCF_PROFILE = &H8
DIGCF_DEVICEINTERFACE = &H10
End Enum

Here is our code.

'Returns a Device Info Set based on Class Guid
Private Function GetDeviceInfoSet(ByVal ClassGuid As Guid, ByVal Scope As DeviceInfoSet_Scope) As IntPtr
Dim Result As IntPtr = SetupDiGetClassDevs(ClassGuid, Convert.ToUInt32(0), IntPtr.Zero, Convert.ToUInt32(Scope))
Return Result
End Function

Our result is returned as an IntPtr variable type.

It is important to note that once you are done with this object you need to destroy it. You can use the SetupDiDestroyDeviceInfoList to destory the IntPtr's. Here is the definition along with the code.

Private Declare Auto Function SetupDiDestroyDeviceInfoList Lib "Setupapi.dll" (ByVal DeviceInfoSet As IntPtr) As Boolean

'Destroys the device Info set
Public Sub DestroyDeviceInfoSet(ByVal DevInfoSet As IntPtr)
SetupDiDestroyDeviceInfoList(DevInfoSet)
End Sub

So the end result is a pointer to an object that will contain a list of devices.

Working With Devices: Getting Friendly Class Names

Ok, so once again I haven't posted in a long time. I'd like to say that I've decided to post at least once per week. Hopefully that will stay true. Given my past track record, your guess is as good as mine.

So, this time around we are going to get the friendly names for our device classes. Previously we may have retrieved a device class name of 'net'. Looking in the Device Manager we only find 'Network adapters'. That is the friendly name and the name you'll likely want to display.

So here is the code using the SetupDiGetClassDescription function.

Private Declare Auto Function SetupDiGetClassDescription Lib "setupapi.dll" (ByRef ClassGuid As Guid, ByVal ClassDescription As System.Text.StringBuilder, ByVal ClassDescriptionSize As Integer, ByRef RequiredSize As IntPtr) As Boolean

'Returns the Class Description (Friendly name for the Class is a better way to put it)
Public Function GetClassDescription(ByVal ClassName As String) As String

'The First section we get the length that we need

Dim intSize As IntPtr
Dim ClassGuid As Guid = GetClassGuid(ClassName)
Dim Result As Boolean = SetupDiGetClassDescription(ClassGuid, Nothing, 0, intSize)
If Not Result Then
Dim intErrorCode As Integer = Marshal.GetLastWin32Error
If intErrorCode <> 122 Then '122 is insufficient buffer (We expect it to happen)
Throw New Win32Exception(intErrorCode)
End If
End If


'The Second section we instantiate an object of the given size and get the Description

Dim ClassDesc As New System.Text.StringBuilder(intSize.ToInt32)
Result = SetupDiGetClassDescription(ClassGuid, ClassDesc, intSize.ToInt32, intSize)
If Not Result Then
Throw New Win32Exception(Marshal.GetLastWin32Error)
End If
Return ClassDesc.ToString
End Function

The above code seems to be pretty typical for these functions. First we get the size of the Class Description and then we get the actual description and return it.