3

Am attempting to query the serial number and the model of the monitor.
I managed to use the WMI code creator to generate the below code:

Try
    Dim MInfo As New ManagementObjectSearcher("root\WMI", "SELECT * FROM WmiMonitorID")

    For Each Monitor In MInfo.Get()
        If Monitor("SerialNumberID") Is Nothing Then
            MsgBox("NA")
        Else
            Dim arrSerialNumberID As UInt16()
            arrSerialNumberID = Monitor("SerialNumberID")
            For Each arrValue As UInt16 In arrSerialNumberID
                Console.WriteLine("Serial: " & arrValue)
            Next
        End If
        If Monitor("UserFriendlyName") Is Nothing Then
            MsgBox("NA")
        Else
            Dim arrSerialNumberID As UInt16()
            arrSerialNumberID = Monitor("UserFriendlyName")
            For Each arrValue As UInt16 In arrSerialNumberID
                Console.WriteLine("Model: " & arrValue)
            Next
        End If
    Next
Catch err As ManagementException
    MessageBox.Show("An error occurred while querying for WMI data: " & err.Message)
 End Try

The output is as per below:

SerialNumberID: 67,78,75,52,49,49,49,49,55,57,0,0,0,0,0,0    
UserFriendlyName: 104,112,32,76,49,53,51,48,0,0,0,0,0

I am trying to convert the output to ASCII.

Jimi
  • 29,621
  • 8
  • 43
  • 61
Wilson Toh
  • 47
  • 6
  • "Am trying to convert the output to ASCII." OK - so what are you trying and what is not working? Have you looked up "convert numbers to ASCII characters in vb.net"? I am pretty sure that question in your favourite search engine will give you the answer quite quickly. – AJD Aug 03 '18 at 07:08
  • Yep I did try. Problem is there are delimiter which I could not find the workaround for. – Wilson Toh Aug 03 '18 at 07:14
  • Your serial number is put into an array, so just loop the array and convert each element into a character? – AJD Aug 03 '18 at 07:19
  • Otherwise, split the returning string on the delimiter into an array and then loop through that array. – AJD Aug 03 '18 at 07:21

1 Answers1

4

The returned array needs to be converted to a string, to become human-eye-friendly.
The UInt16 byte array can be converted with Convert.ToByte(UInt16), then transformed into string with Encoding.UTF8.GetString().

Here, a conversion method is included in a specialized class (MonitorID) that is used to return some information on all Monitors in a System, querying \WMI\WmiMonitorID.
It could be extended with \CIMV2\Win32_DesktopMonitor

You can use it this way:

Dim MonitorIds As List(Of MonitorID) = GetDesktopMonitorsID()

Will return (among other details):

MonitorIds(0).SerialNumberID = CNK4111179  
MonitorIds(0).UserFriendlyName = HP L1530  

Class and WMI Query method:

Imports System.Management

Public Class MonitorID
    Public Property Active As Boolean?
    Public Property InstanceName As String
    Public Property ManufacturerName As String
    Public Property ProductCodeID As String
    Public Property SerialNumberID As String
    Public Property UserFriendlyName As String
    Public Property WeekOfManufacture As String
    Public Property YearOfManufacture As String

    Public Shared Function ConvertToString(mObject As Object) As String
        If mObject Is Nothing Then Return String.Empty
        Return Encoding.UTF8.GetString(CType(mObject, UInt16()).
            TakeWhile(Function(ui) ui <> 0).Select(Function(ui) Convert.ToByte(ui)).ToArray())
    End Function
End Class


Public Shared Function GetDesktopMonitorsID() As List(Of MonitorID)
    Dim MonitorsIds As New List(Of MonitorID)()

    Dim ConnOptions As New ConnectionOptions() With {
        .EnablePrivileges = True,
        .Timeout = EnumerationOptions.InfiniteTimeout
    }

    Dim mOptions As New EnumerationOptions() With {
        .Rewindable = False,
        .ReturnImmediately = True,
        .DirectRead = True,
        .EnumerateDeep = False
    }

    Dim mQuery As New SelectQuery("SELECT * FROM WmiMonitorID")
    Dim mScope As New ManagementScope($"\\{Environment.MachineName}\root\WMI", ConnOptions)
    mScope.Connect()

    Using moSearcher As New ManagementObjectSearcher(mScope, mQuery, mOptions)
        For Each moMonitor As ManagementObject In moSearcher.[Get]()

        MonitorsIds.Add(New MonitorID() With {
            .Active = CType(moMonitor("Active"), Boolean?),
            .InstanceName = moMonitor("InstanceName")?.ToString(),
            .ManufacturerName = MonitorID.ConvertToString(moMonitor("ManufacturerName")),
            .ProductCodeID = MonitorID.ConvertToString(moMonitor("ProductCodeID")),
            .SerialNumberID = MonitorID.ConvertToString(moMonitor("SerialNumberID")),
            .UserFriendlyName = MonitorID.ConvertToString(moMonitor("UserFriendlyName")),
            .WeekOfManufacture = moMonitor("WeekOfManufacture")?.ToString(),
            .YearOfManufacture = moMonitor("YearOfManufacture")?.ToString()
        })
        Next
    End Using
    Return MonitorsIds
End Function
Jimi
  • 29,621
  • 8
  • 43
  • 61
  • Hi Jimi, thanks for your helpful reply. Have tried your function and it doesn't seem to work. Added a try catch exception at the WMI query and I'm getting this message: "Value cannot be null. Parameter name:source". Would you be able to advise on that? – Wilson Toh Aug 06 '18 at 06:53
  • @Wilson Toh This method is tested but it doesn't mean that it can work in all enviroments without adjusting it. Have you implemented it exactly how it is here? Can you tell me the VB version and the .Net FrameWork version you're using (VS 15.7.6 - FW 4.7.1 here)? Also, which is the instruction that generates the error (debug it step-by-step to find out). -- There's is no null check at this time in the `MonitorID` class `ConvertToString()` method. If one of the objects is null, it will not be handled. I'll make an edit for that. – Jimi Aug 06 '18 at 10:04
  • @Wilson Toh Note that older version of VB.Net can't handle this syntax `.InstanceName = moMonitor("InstanceName")?.ToString()`. It has to be rewritten as: `.InstanceName = If(moMonitor("InstanceName") Is Nothing, String.Empty, CType(moMonitor("InstanceName"), String))`. The same goes for the other two nullable strings results. – Jimi Aug 06 '18 at 10:20
  • Thanks Jimi, it is indeed an older version of VB.net. Am able to run the code after the change. Thanks! – Wilson Toh Aug 07 '18 at 06:37