When it comes to hardware interaction, many .net developers feel frustrated and uncertain about the capability of doing what they have in mind. One common problem we face is to enumerate the devices installed on your computer. A harder problem is to get the devices that are not working properly or disabled!. If you are writing an application that requires the existence of a specific hardware device, it makes common sense to test whether the desired device is working and enabled.
In Windows, you can view the lis of devices from the Device Manager. Disabled devices appear with a down arrow next to the device and devices that are not working properly appear with a yellow exclamation mark icon next to it:

The solution to such problems in .Net Framework languages becomes simple if we make us of WMI Queries or Windows Management Instrumentation. Writing a WMI query to retrieve system information is as simple as wrting an SQL Query.In fact, it’s almost exactly the same syntax except the objects we are querying do differ. Take a look at the WMI query below that retrieves all installed devices on the local system:
Select * from Win32_PnPEntity
As simple as that, the Win32_PnpEntity stores information about installed devices. So if want to filter out the results by getting only the non working devices, we simply add a Where clause just like we do if we filtering data from an sql table.
Select * from Win32_PnPEntity WHERE ConfigManagerErrorCode 0
The ConfigManagerErrorCode property stores the state of the device, a value of 0 means Working and any other different value means the device is not working or disabled.
Lets create a Device class to convert each retrieved device to an object that we can deal with in our application. After all, we would want to list out all non working devices and bind the list to some bindable data object such as a DataGrid or a ListView.
Below is our base Device class having all the properties we need to show:
Public Class Device
Private mName As String
Private mManufacturer As String
Private mDescription As String
Private mService As String
Private mDeviceID As String
Private mPNPDeviceID As String
Private mClassGUID As String
Public Property Name() As String
Get
Return mName
End Get
Set(ByVal value As String)
mName = value
End Set
End Property
Public Property Manufacturer() As String
Get
Return mManufacturer
End Get
Set(ByVal value As String)
mManufacturer = value
End Set
End Property
Public Property Description() As String
Get
Return mDescription
End Get
Set(ByVal value As String)
mDescription = value
End Set
End Property
Public Property Service() As String
Get
Return mService
End Get
Set(ByVal value As String)
mService = value
End Set
End Property
Public Property DeviceID() As String
Get
Return mDeviceID
End Get
Set(ByVal value As String)
mDeviceID = value
End Set
End Property
Public Property PNPDeviceID() As String
Get
Return mPNPDeviceID
End Get
Set(ByVal value As String)
mPNPDeviceID = value
End Set
End Property
Public Property ClassGUID() As String
Get
Return mClassGUID
End Get
Set(ByVal value As String)
mClassGUID = value
End Set
End Property
End Class
We are ready now to implement our two main function, GetAllDevices and GetNonWorkingDevices and add them to the Device class. Both methods will be Shared methods because they are generic and produce the same result across all instances of the Device class. Below is the impelemtation of both methods, note the use of the GetObject method which retrieves an instance of WMI on the local computer system:
Public Shared Function GetAllDevices() As List(Of Device)
Dim pc As String = "." 'local
Dim wmi As Object = GetObject("winmgmts:\\" & pc & "\root\cimv2")
Dim allDevices As New List(Of Device)
Dim devices As Object = wmi.ExecQuery("Select * from Win32_PnPEntity")
Dim device As Device
For Each d As Object In devices
device = New Device
With Device
.mClassGUID = IIf(IsDBNull(d.ClassGuid), 0, d.ClassGuid)
.mDescription = IIf(IsDBNull(d.Description), 0, d.Description)
.DeviceID = IIf(IsDBNull(d.DeviceID), 0, d.DeviceID)
.Manufacturer = IIf(IsDBNull(d.Manufacturer), 0, d.Manufacturer)
.Name = IIf(IsDBNull(d.Name), 0, d.Name)
.PNPDeviceID = IIf(IsDBNull(d.PNPDeviceID), 0, d.PNPDeviceID)
.Service = IIf(IsDBNull(d.Service), 0, d.Service)
End With
allDevices.Add(device)
Next
Return allDevices
End Function
Public Shared Function GetNonWorkingDevices() As List(Of Device)
Dim pc As String = "." 'local
Dim wmi As Object = GetObject("winmgmts:\\" & pc & "\root\cimv2")
Dim notWorking As New List(Of Device)
Dim devices As Object = wmi.ExecQuery("Select * from " & _
"Win32_PnPEntity WHERE ConfigManagerErrorCode 0")
Dim device As Device
For Each d As Object In devices
device = New Device
With Device
.mClassGUID = IIf(IsDBNull(d.ClassGuid), 0, d.ClassGuid)
.mDescription = IIf(IsDBNull(d.Description), 0, d.Description)
.DeviceID = IIf(IsDBNull(d.DeviceID), 0, d.DeviceID)
.Manufacturer = IIf(IsDBNull(d.Manufacturer), 0, d.Manufacturer)
.Name = IIf(IsDBNull(d.Name), 0, d.Name)
.PNPDeviceID = IIf(IsDBNull(d.PNPDeviceID), 0, d.PNPDeviceID)
.Service = IIf(IsDBNull(d.Service), 0, d.Service)
End With
notWorking.Add(device)
Next
Return notWorking
End Function
Our Device class is now ready, we can simply now bind the results of each method to a DataGrid as i have done in the figure below:

Here is the code that produces the above results after adding a DatagridView to a form:
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
DataGridView1.DataSource = Device.GetNonWorkingDevices
End Sub
The project with its source code can be downloaded here(remove the .jpg extension).
Recent Comments