如何制作vb.net多线程WMI查询应用程序

时间:2012-11-19 04:20:36

标签: .net vb.net multithreading wmi

我是初学者,请原谅我,如果这是一个愚蠢的问题...我有一个机器列表,然后我想拉取WMI信息(在这种情况下是它的操作系统信息),然后更新一个ListView形成。我正在寻找最简单的方法,使用Task Factory以高效的方式使下面的代码多线程?从我读过的内容来看,似乎需要将每台计算机放入一个集合中,然后每个线程都需要更新集合中的对象?

这是我的原始代码:

Imports System.Management

Public Class Form1
Public PC As New pc
Public WMI As New WMIConnect
Public i As Integer = 1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    With lv_Inventory
        .Visible = True
        .UseCompatibleStateImageBehavior = False
        .View = View.Details
        .Scrollable = True
        .Sort()
        .HideSelection = False
        .FullRowSelect = True
        .GridLines = True
        .AllowColumnReorder = True
        .Columns.Add("Name", 100)
        .Columns.Add("LastBoot", 150)
        .Columns.Add("OS", 125)
        .Columns.Add("Version", 100)
        .Columns.Add("SP", 75)
    End With

    For Each Machine As ListViewItem In lv_Machines.SelectedItems
        lv_Inventory.Items.Add(Machine.Text)
        'Dim PC As New pc
        WMI.WMIConnect(Machine.Text, tb_user.Text, tb_pass.Text)
        PC.Name = Machine.Text
        GetOS()
        lv_Inventory.Items(i - 1).SubItems.Add(PC.LastBootTime)
        lv_Inventory.Items(i - 1).SubItems.Add(PC.OperatingSystem)
        lv_Inventory.Items(i - 1).SubItems.Add(PC.OSVersion)
        lv_Inventory.Items(i - 1).SubItems.Add(PC.ServicePack)
        i += 1
    Next

End Sub

Public Sub GetOS()

    On Error Resume Next
    Dim lastboot As String = Nothing
    Dim m As ManagementObject
    Dim queryCollection As ManagementObjectCollection
    queryCollection = wmi.wmiQuery _
    ("SELECT Caption, Lastbootuptime, version, csdversion, csname, SystemDirectory FROM   Win32_OperatingSystem")

    If queryCollection Is Nothing Then
        ' Me.LostConnection()
        Exit Sub
    End If

    For Each m In queryCollection
        pc.Hostname = UCase(m("csname"))
        pc.LastBootTime = m("LastBootUpTime")
        pc.OSVersion = m("Version")
        pc.ServicePack = m("CSDVersion")
        pc.OperatingSystem = m("Caption")
    Next
End Sub

End Class


Public Class WMIConnect
Public Shared wmiScope As Management.ManagementScope
Public Shared RegScope As Management.ManagementScope

Public Sub WMIConnect(ByVal Machine As String, ByVal Username As String, ByVal Pass As String)
    Dim wmiConnectionOptions As New Management.ConnectionOptions

    With wmiConnectionOptions
        .Impersonation = System.Management.ImpersonationLevel.Impersonate
        .Timeout = New TimeSpan(0, 0, 10)
        .Authentication = System.Management.AuthenticationLevel.Packet
        .Username = Username
        .Password = Pass
        .EnablePrivileges = True
    End With

    Try
        Dim wmiScope As New Management.ManagementScope("\\" & _
                   Machine & "\root\cimv2", wmiConnectionOptions)
        wmiScope.Connect()
        Dim RegScope As New Management.ManagementScope("\\" & _
                   Machine & "\root\default:StdRegProv", wmiConnectionOptions)
        RegScope.Connect()
    Catch e As Exception
        MsgBox("Error: " & e.ToString)
    End Try


End Sub

Public Function wmiQuery(ByVal QueryString As String) As Management.ManagementObjectCollection
    Try
        Dim query As Management.ObjectQuery
        query = New Management.ObjectQuery(QueryString)
        Dim searcher As Management.ManagementObjectSearcher
        searcher = New Management.ManagementObjectSearcher(wmiScope, query)
        Dim queryCollection As Management.ManagementObjectCollection
        queryCollection = searcher.Get()
        Return queryCollection
    Catch
        Dim queryCollection As Management.ManagementObjectCollection = Nothing
        Return queryCollection
    End Try

End Function
End Class


Public Class pc

Public Shared Name As String
Public Hostname As String
Public OperatingSystem As String
Public ServicePack As String
Public OSVersion As String
Public LastBootTime As String

End Class

以下是并行任务中更新的代码:

        Parallel.ForEach(lv_Machines.SelectedItems.Cast(Of Object), _
                 Sub(machine)

                     ' ... work with currentElement
                     Try
                         Dim WMI As New wmiConnection
                         Dim PC As New pc
                         Dim i As Integer = 1
                         Dim int As Integer = 1
                         tb_Log.Text += "working on machine " & machine.text & vbCrLf
                         WMI.WMIConnect(machine.Text, tb_user.Text, tb_pass.Text)
                         tb_Log.Text += "WMI connect to machine " & machine.text & vbCrLf
                         PC.Name = machine.Text
                         GetOS(PC, WMI)
                         GetHardware(PC, WMI)
                         GetNetwork(PC, WMI)

                         With lv_Inventory
                             .Items.Add(PC.Name.ToString)
                             With .Items(.Items.Count - 1).SubItems
                                 .Add(PC.LastBootTime.ToString & "")
                                 .Add(PC.OperatingSystem.ToString & "")
                                 .Add(PC.OSVersion.ToString & "")
                                 .Add(PC.ServicePack.ToString & "")
                                 .Add(PC.SerialNumber.ToString & "")
                                 .Add(PC.ChassisType.ToString & "")
                                 .Add(PC.CPU.ToString & "")
                                 .Add(PC.PhysicalMemory.ToString & "")
                                 .Add(PC.Model.ToString & "")
                                 .Add(PC.Manufacturer.ToString & "")
                                 .Add(PC.MacAddress.ToString & "")
                             End With
                         End With

                         tb_Log.Text += "Processing: " & machine.Text & " Thread ID: " & Thread.CurrentThread.ManagedThreadId & vbCrLf
                     Catch ex As Exception
                         tb_Log.Text += "Error: " & ex.ToString & vbCrLf
                     End Try

                 End Sub)

我认为使用新代码我现在可能正在与线程同步问题作斗争......跟踪日志似乎表明WMI对象似乎被上一个/下一个任务覆盖,因此我的列表视图中的最终信息最终只是拥有与我们创建和连接的最后一个PC对象相同的结果集(达到竞争条件)。我是否需要在WMI连接上执行同步锁定并在完成数据获取后将其释放?如果是这样,那么它会比非多线程for / each快得多,因为我需要锁定WMI对象和PC对象吗?我基本上只需要一种方法来获取计算机列表并连接到每一台计算机并以多线程方式获取详细信息。以下是我的跟踪日志的输出:

  1. 使用机器col-01
  2. 使用机器col-02
  3. WMI连接到机器WI-01
  4. 获取cpu信息......适用于WI-01
  5. 获取驱动器信息......适用于WI-01
  6. 获取机箱类型。对于WI-01
  7. 处理:WI-01线程ID:10
  8. WMI连接到计算机sta-01
  9. WMI连接到机器sta-02
  10. 获取cpu信息...... WI-01
  11. 获取cpu信息...... WI-01
  12. 获取驾驶信息...... WI-01
  13. 获取驾驶信息...... WI-01
  14. 获取机箱类型。对于WI-01
  15. 获取机箱类型。对于WI-01
  16. 处理:sta-01主题ID:9
  17. 处理:sta-02线程ID:6

1 个答案:

答案 0 :(得分:0)

嗯,可能最简单的方法是使用Threaded.ForEach。你可以在这里找到详细信息:

http://msdn.microsoft.com/en-us/library/dd460720(v=vs.100).aspx

这需要.net4或更高版本。