Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if WMI ManagementObject query is Nothing instead of using a Try/Catch?

Tags:

.net

vb.net

wmi

In my program, I am using the the WMI interface to query lots of information about the hardware that the program is running on. I'm then taking that information and putting it into a list to help with displaying it later, but not much else is done beyond that at the moment. This method so far has worked out pretty well, but there is one major issue: sometimes the query is/returns (don't know which one yet!) Nothing and results in a NullReferenceException.

Now, obviously I can wrap it in a Try/Catch and be on my merry way. However, I would like to avoid doing this because I will be querying hundreds of bits of information, and hundreds of them may result in an exception. This is just sloppy programming and is slowing my program down significantly!

My questions is: What do I check in order to use an If instead of a Try? I will put my current code below and then list the solutions I have already tried.

    Public Shared Function GetSomeInfo() As List(Of String)
        Dim ret As New List(Of String)
        Dim sq As New Management.SelectQuery("Win32_Processor")
        Dim mos As New Management.ManagementObjectSearcher(sq)
        For Each info As Management.ManagementObject In mos.Get()
            ret.Add(TryQuery(info, "Name"))
            ret.Add(TryQuery(info, "Caption")) 'this query may result in Nothing somewhere...
        Next
        Return ret
    End Function

    Private Shared Function TryQuery(ByRef info As 
            Management.ManagementObject, ByVal strID As String) As String
        Try
            Return strID & ": " & info(strID).ToString 'exception obviously thrown here...but WHERE?
        Catch ex As NullReferenceException
            Return String.Empty
        Catch ex As Management.ManagementException
            Return String.Empty
        End Try
    End Function

So, here's what I've tried in order to attempt and get around using this Try:

If Not info Is Nothing Then ... Still resulted in some uncaught exception

If Not info(strID) Is Nothing Then ... Still got an exception somewhere

If Not info.Equals(Nothing) Then ... Desperation

If Not Info(strID).ToString Is Nothing ... :(

I simply have no idea where to check for this exception being throwing within the WMI query. Any insight would be appreciated. Thanks!

like image 308
Jonas Zebari Avatar asked May 15 '18 13:05

Jonas Zebari


Video Answer


1 Answers

Based on your description, it appears that although a property name may be listed as existing for a given WMI class, but a WMI PropertyData item is not available for the given property name. A brute force approach should work to avoid generating a "Not Found" exception by iterating the proper PropertyDataCollection.

Private Shared Function TryQuery(ByRef info As ManagementObject, ByVal strID As String) As String
    Dim ret As String = String.Empty
    Dim propDatas As PropertyDataCollection
    If strID.StartsWith("__") Then
        ' system property, ref: https://msdn.microsoft.com/en-us/library/system.management.managementbaseobject.systemproperties(v=vs.110).aspx
        propDatas = info.SystemProperties
    Else
        ' object properties: ref: https://msdn.microsoft.com/en-us/library/system.management.managementbaseobject.properties(v=vs.110).aspx
        propDatas = info.Properties
    End If
    For Each data As PropertyData In propDatas
        If data.Name.Equals(strID, StringComparison.InvariantCultureIgnoreCase) Then
            ret = If(data.Value, String.Empty).ToString
            Exit For
        End If
    Next
    Return ret
End Function

Also, most of the WMI objects are Disposable and should be handled accordingly.

Public Shared Function GetSomeInfo() As List(Of String)
    Dim ret As New List(Of String)
    Dim sq As New Management.SelectQuery("Win32_Processor")
    Using mos As New Management.ManagementObjectSearcher(sq)
        Using objects As ManagementObjectCollection = mos.Get
            For Each info As Management.ManagementObject In objects
                Using info
                    ret.Add(TryQuery(info, "Name"))
                    ret.Add(TryQuery(info, "Caption")) 'this query may result in Nothing somewhere...
                End Using
            Next
        End Using
    End Using
    Return ret
End Function

Edit: To provide a bit of assurance that this technique is valid, you can inspect the source code for the indexer on the ManagementBaseObject. This method calls:

public Object GetPropertyValue(string propertyName)
{ 
    if (null == propertyName)
        throw new ArgumentNullException ("propertyName");

    // Check for system properties
    if (propertyName.StartsWith ("__", StringComparison.Ordinal))
        return SystemProperties[propertyName].Value;
    else
        return Properties[propertyName].Value;
}

You can see that this retrieves the property similar to the code I have provided. The issue is that the ProdertyDataCollection class will throw a "Not Found" error if if it can not find a matching property name.

like image 199
TnTinMn Avatar answered Oct 27 '22 22:10

TnTinMn