使用 Vb.Net 从 WMI 读取事件后可能会导致长时间延迟的原因

发布于 2024-07-29 11:10:34 字数 22740 浏览 4 评论 0原文

我有一个 Windows 用户控件,可以从远程服务器的应用程序日志中读取事件。 我可以正常读取信息,而且似乎发生得非常快,但是线程随后挂起大约 30 秒,并使我的应用程序无法显示日志。

恐怕这可能是由于我缺乏处理线程的经验造成的,但我不能确定。 我绝对愿意接受任何关于我的线程的建议。

查看我所指内容的最简单方法是调用 btnClear_click 事件处理程序。 跳过线程虫洞后,转到LoadFilteredEvent方法。 结果从 ManagementObjectSearcher 加载得相当快,但在下一条语句时会挂起 30 到 60 秒。

Imports System.Management

Public Class LogMonitor
#Region "attributes"

    Private _currentWql As StringBuilder
    Private _enabled As Boolean
    Private _entries As ArrayList
    Private _logWatcher As ManagementEventWatcher
    Private _machine As StringBuilder
    Private _previousFromDate As DateTime
    Private _previousToDate As DateTime
    Private _previousStatus As Int16
    Private _previousMessage As StringBuilder
    Private _scope As ManagementScope
    Private _service As StringBuilder
    Private _tempEntries As ArrayList

    Public Event ExportCompleted()
    Public Event ExportStarted(ByVal ExportedResultCount As Integer)
    Public Event ExportUpdated(ByVal CurrentEntry As Integer)
    Public Event FilteringCompleted()
    Public Event FilteringStarted(ByVal LogEntryCount As Integer)
    Public Event FilteringUpdated(ByVal CurrentEntry As Integer)

#End Region
#Region "constructor"

    Public Sub New(ByVal ComputerName As String, ByVal ServiceName As String)
        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        _machine = New StringBuilder(ComputerName)
        _service = New StringBuilder(ServiceName)

        Me.Icon = Nothing
        Me.Text = ServiceName

        _enabled = True
        _previousFromDate = Now
        _previousToDate = Now
        _previousStatus = 0
        _previousMessage = New StringBuilder()

        _tempEntries = New ArrayList()

        Dim compPath As String = "\\" & _machine.ToString & "\root\cimv2"
        _scope = New ManagementScope(compPath, New ConnectionOptions())

        _scope.Connect()

        _logWatcher = New ManagementEventWatcher(New EventQuery(BuildWatcherWql()))
        _logWatcher.Scope = _scope
        AddHandler _logWatcher.EventArrived, AddressOf EventAdded

        Dim watcherThread As New Threading.Thread(AddressOf _logWatcher.Start)
        watcherThread.Start()
    End Sub

#End Region
#Region "events"

    Private Sub btnClear_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClear.Click
        dtpFilter.Value = Now.ToShortDateString
        SetCurrentWqlToCurrent()

        _logWatcher.Start()

        ' use a thread from the application's thread pool
        Threading.ThreadPool.QueueUserWorkItem(AddressOf FilterLogWorker)
    End Sub

    Private Sub btnFilter_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFilter.Click
        SetCurrentWqlToFiltered()

        If dtpFilter.Value.Equals(Now.ToShortDateString) Then
            _logWatcher.Start()
        Else
            _logWatcher.Stop()
        End If
        ' use a thread from the application's thread pool to load the new working directory
        Threading.ThreadPool.QueueUserWorkItem(AddressOf FilterLogWorker)
    End Sub

    Private Sub btnSearch_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSearch.Click
        Dim sf As New SearchFields
        sf.FromDate = _previousFromDate
        sf.ToDate = _previousToDate
        sf.EventStatus = _previousStatus
        sf.Message = _previousMessage.ToString

        If sf.ShowDialog = Windows.Forms.DialogResult.OK Then
            _previousFromDate = sf.FromDate
            _previousToDate = sf.ToDate
            _previousStatus = sf.EventStatus
            _previousMessage = New StringBuilder(sf.Message.Trim)

            SetCurrentWqlToSearched()

            _logWatcher.Stop()

            ' use a thread from the application's thread pool to load the new working directory
            Threading.ThreadPool.QueueUserWorkItem(AddressOf FilterLogWorker)
        End If
    End Sub

    Private Sub cmExport_ExportToFile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmExport_ExportToFile.Click
        If sfdExport.ShowDialog = Windows.Forms.DialogResult.OK Then
            ExportEntriesToFile(sfdExport.FileName)
        End If
    End Sub

    Private Sub cmExport_ExportToEmail_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmExport_ExportToEmail.Click
        ExportEntriesToEmail()
    End Sub

    Private Sub cmExport_ExportToExcel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmExport_ExportToExcel.Click
        If sfdExcel.ShowDialog = Windows.Forms.DialogResult.OK Then
            ExportEntriesToExcel(sfdExcel.FileName)
        End If
    End Sub

    Private Sub EventAdded(ByVal sender As Object, ByVal e As EventArrivedEventArgs)
        Dim handler As New ReceiveNewEventHandler(AddressOf ReceiveNewEvent)
        Dim args() As Object = {e}

        Me.Invoke(handler, args)
    End Sub

    Private Sub LogMonitor_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
        _logWatcher.Stop()
        _logWatcher.Dispose()
    End Sub

    Private Sub LogMonitor_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        dtpFilter.Value = Now.ToShortDateString()
    End Sub

    Private Sub tvEntries_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles tvEntries.DoubleClick
        If IsNothing(tvEntries.SelectedNode) = False Then
            Dim id As Long = CLng(tvEntries.SelectedNode.Tag)

            Dim ev As New EventViewer(_machine.ToString, id)
            ev.Show()
        End If
    End Sub

#End Region
#Region "functions"

    Private Sub AddNewEvent(ByVal EventObject As ManagementObject)
        tvEntries.Nodes.Add(BuildLogNodeFromObject(EventObject))
    End Sub

    Private Sub AddNewEvent(ByVal EventProperty As PropertyData)
        tvEntries.Nodes.Add(BuildLogNodeFromProperty(EventProperty))
    End Sub

    Private Function BuildLogNodeFromObject(ByVal EventObject As ManagementObject) As TreeNode
        Dim tempGenTime As String = EventObject.GetPropertyValue("TimeGenerated").ToString()
        Dim eventGenTime As DateTime = New DateTime(CInt(tempGenTime.Substring(0, 4)),
                                                    CInt(tempGenTime.Substring(4, 2)),
                                                    CInt(tempGenTime.Substring(6, 2)),
                                                    CInt(tempGenTime.Substring(8, 2)),
                                                    CInt(tempGenTime.Substring(10, 2)),
                                                    CInt(tempGenTime.Substring(12, 2)))
        Dim eventMessage As String = EventObject.GetPropertyValue("Message").ToString
        Dim newLineIndex As Integer = eventMessage.IndexOf(vbCrLf)

        Dim msg As New StringBuilder
        msg.Append(eventGenTime.ToString("MM/dd/yyyy HH:mm:ss"))
        msg.Append(" - ")
        msg.Append(eventMessage.Substring(0, newLineIndex))
        If eventMessage.Length > newLineIndex + 2 Then msg.Append("(more)")

        Dim myNode As New TreeNode
        myNode.Text = msg.ToString
        myNode.Tag = EventObject.GetPropertyValue("RecordNumber").ToString

        If EventObject.GetPropertyValue("Type").ToString.Equals("Error") Then myNode.ForeColor = Color.Red
        If EventObject.GetPropertyValue("Type").ToString.Equals("Warning") Then myNode.ForeColor = Color.Orange

        Return myNode
    End Function

    Private Function BuildLogNodeFromProperty(ByVal EventProperty As PropertyData) As TreeNode
        Dim mbo As ManagementBaseObject = CType(EventProperty.Value, ManagementBaseObject)
        Dim tempGenTime As String = mbo.Properties("TimeGenerated").Value.ToString()
        Dim eventGenTime As DateTime = New DateTime(CInt(tempGenTime.Substring(0, 4)),
                                                    CInt(tempGenTime.Substring(4, 2)),
                                                    CInt(tempGenTime.Substring(6, 2)),
                                                    CInt(tempGenTime.Substring(8, 2)),
                                                    CInt(tempGenTime.Substring(10, 2)),
                                                    CInt(tempGenTime.Substring(12, 2)))
        Dim eventMessage As String = mbo.Properties("Message").Value.ToString()
        Dim newLineIndex As Integer = eventMessage.IndexOf(vbCrLf)

        Dim msg As New StringBuilder
        msg.Append(eventGenTime.ToString("MM/dd/yyyy HH:mm:ss"))
        msg.Append(" - ")
        msg.Append(eventMessage.Substring(0, newLineIndex))
        If eventMessage.Length > newLineIndex + 2 Then msg.Append("(more)")

        Dim myNode As New TreeNode
        myNode.Text = msg.ToString
        myNode.Tag = mbo.Properties("RecordNumber").Value.ToString

        If mbo.Properties("Type").Value.ToString.Equals("Error") Then myNode.ForeColor = Color.Red
        If mbo.Properties("Type").Value.ToString.Equals("Warning") Then myNode.ForeColor = Color.Orange

        Return myNode
    End Function

    Private Function BuildWatcherWql() As String
        Dim wql As New StringBuilder("SELECT TimeGenerated, Message, RecordNumber, Type FROM __InstanceCreationEvent WHERE TargetInstance ISA  'Win32_NTLogEvent' ")
        wql.Append("AND TargetInstance.LogFile = 'Application' AND TargetInstance.SourceName = '")
        wql.Append(_service.ToString)
        wql.Append("'")

        Return wql.ToString
    End Function

    Private Sub DisableControls()
        Me.Invoke(New DisableControlsHandler(AddressOf DisableControls_Impl))
    End Sub

    Private Sub DisableControls_Impl()
        Enabled = False
    End Sub

    Private Sub EnableControls()
        Me.Invoke(New EnableControlsHandler(AddressOf EnableControls_Impl))
    End Sub

    Private Sub EnableControls_Impl()
        Enabled = True
    End Sub

    Private Sub EventLogWorker(ByVal state As Object)
        SyncLock tvEntries.GetType
            tvEntries.Invoke(CType(AddressOf LoadServiceHistory, MethodInvoker))
        End SyncLock
    End Sub

    Private Sub ExportEntriesToEmail()
        RaiseEvent ExportStarted(tvEntries.Nodes.Count)

        Try
            Dim outlook As Object = CreateObject("Outlook.Application")
            Dim mailMsg As Object
            Const olMailItem = 0

            mailMsg = outlook.CreateItem(olMailItem)

            Dim bodyText As New StringBuilder
            For i As Integer = 0 To tvEntries.Nodes.Count - 1
                bodyText.AppendLine(tvEntries.Nodes(i).Text)
                RaiseEvent ExportUpdated(i)
            Next

            mailMsg.Body = bodyText.ToString
            mailMsg.Subject = Me.Text & " exported results"
            mailMsg.Display()

            mailMsg = Nothing
            outlook = Nothing
        Catch ex As Exception
            MessageBox.Show("Problem exporting to Outlook." & vbCr & ex.Message, "Service Monitor Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try

        RaiseEvent ExportCompleted()
    End Sub

    Private Sub ExportEntriesToFile(ByVal FileName As String)
        RaiseEvent ExportStarted(tvEntries.Nodes.Count)

        Try
            Dim myFile As New IO.FileInfo(FileName)
            Dim myWriter As IO.TextWriter = myFile.CreateText()

            For i As Integer = 0 To tvEntries.Nodes.Count - 1
                myWriter.WriteLine(tvEntries.Nodes(i).Text)
                RaiseEvent ExportUpdated(i)
            Next

            myWriter.Close()
            myWriter.Dispose()
        Catch ex As Exception
            MessageBox.Show("Problem exporting to text file." & vbCr & ex.Message, "Service Monitor Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try

        RaiseEvent ExportCompleted()
    End Sub

    Private Sub ExportEntriesToExcel(ByVal FileName As String)
        RaiseEvent ExportStarted(tvEntries.Nodes.Count)

        Dim excel As Object = Nothing
        Dim xlWorkbook As Object = Nothing
        Dim xlWorksheet As Object = Nothing

        Try
            'Try to Open Excel, Add a workbook and worksheet
            excel = CreateObject("Excel.Application")
            xlWorkbook = excel.Workbooks.Add
            xlWorksheet = xlWorkbook.Sheets.Item(1)
        Catch ex As Exception
            MessageBox.Show("Problem exporting to Excel." & vbCr & ex.Message, "Service Monitor Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            Try
                If Not IsNothing(xlWorkbook) Then
                    xlWorkbook.Close()  'If an error occured we want to close the workbook
                End If
                If Not IsNothing(excel) Then
                    excel.Quit() 'If an error occured we want to close Excel
                End If
            Catch
            End Try
            xlWorksheet = Nothing
            xlWorkbook = Nothing
            excel = Nothing
            RaiseEvent ExportCompleted()
            Exit Sub
        End Try

        Try
            excel.DisplayAlerts = False    'This will prevent any message prompts from Excel (IE.."Do you want to save before closing?")
            excel.Visible = False    'We don't want the app visible while we are populating it.

            For i As Integer = 0 To tvEntries.Nodes.Count - 1
                Dim logTimeCell As Object = xlWorksheet.Range("A" & (i + 1))
                Dim messageCell As Object = xlWorksheet.Range("B" & (i + 1))

                Dim messageParts() As String = tvEntries.Nodes(i).Text.Split("-")

                logTimeCell.Value = messageParts(0).Trim
                messageCell.Value = messageParts(1).Trim

                logTimeCell = Nothing
                messageCell = Nothing

                RaiseEvent ExportUpdated(i)
            Next

            Dim outputRange = xlWorksheet.Range("A1:B" & tvEntries.Nodes.Count)
            outputRange.Columns.AutoFit()
            outputRange = Nothing

            xlWorkbook.SaveAs(FileName)
            xlWorkbook.Close()
            excel.Quit()
        Catch ex As Exception
            MessageBox.Show("While trying to Export to Excel recieved error:" & ex.Message, "Export to Excel Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            Try
                xlWorkbook.Close()  'If an error occured we want to close the workbook
                excel.Quit() 'If an error occured we want to close Excel
            Catch
            End Try
        Finally
            xlWorksheet = Nothing
            xlWorkbook = Nothing
            excel = Nothing
        End Try

        RaiseEvent ExportCompleted()
    End Sub

    Private Sub FilterLogWorker(ByVal state As Object)
        SyncLock tvEntries.GetType
            tvEntries.Invoke(CType(AddressOf LoadFilteredEvents, MethodInvoker))
        End SyncLock
    End Sub

    Private Sub InsertNewEvent(ByVal EventObject As ManagementObject)
        tvEntries.Nodes.Insert(0, BuildLogNodeFromObject(EventObject))
    End Sub

    Private Sub InsertNewEvent(ByVal EventProperty As PropertyData)
        tvEntries.Nodes.Insert(0, BuildLogNodeFromProperty(EventProperty))
    End Sub

    Public Sub LoadEntries()
        ' use a thread from the application's thread pool to load the new working directory
        Threading.ThreadPool.QueueUserWorkItem(AddressOf EventLogWorker)
    End Sub

    Public Sub LoadEntries(ByVal LogEntries As ArrayList)
        _entries = LogEntries
        LoadEntries()
    End Sub

    Private Sub LoadFilteredEvents()
        Dim search As New ManagementObjectSearcher(_scope.Path.ToString, _currentWql.ToString)
        Dim results As ManagementObjectCollection = search.Get
        Dim resultCounter As Integer = 0

        RaiseFilteringStartedEvent(results.Count)

        DisableControls()

        tvEntries.Nodes.Clear()

        For Each result As ManagementObject In results
            AddNewEvent(result)

            resultCounter += 1
            RaiseFilteringUpdatedEvent(resultCounter)
        Next

        results.Dispose()
        search.Dispose()

        EnableControls()
        RaiseFilteringCompletedEvent()
    End Sub

    Private Sub LoadServiceHistory()
        tvEntries.Nodes.Clear()

        For Each entry As ManagementObject In _entries
            AddNewEvent(entry)
        Next

        _entries.Clear()
    End Sub

    Private Sub RaiseFilteringCompletedEvent()
        Dim handler As New RaiseFilteringCompletedEventHandler(AddressOf RaiseFilteringCompletedEvent_Impl)
        Me.Invoke(handler)
    End Sub

    Private Sub RaiseFilteringCompletedEvent_Impl()
        RaiseEvent FilteringCompleted()
    End Sub

    Private Sub RaiseFilteringStartedEvent(ByVal MaxValue As Integer)
        Dim handler As New RaiseFilteringStartedEventHandler(AddressOf RaiseFilteringStartedEvent_Impl)
        Dim args() As Object = {MaxValue}

        Me.Invoke(handler, args)
    End Sub

    Private Sub RaiseFilteringStartedEvent_Impl(ByVal MaxValue As Integer)
        RaiseEvent FilteringStarted(MaxValue)
    End Sub

    Private Sub RaiseFilteringUpdatedEvent(ByVal Index As Integer)
        Dim handler As New RaiseFilteringUpdatedEventHandler(AddressOf RaiseFilteringUpdatedEvent_Impl)
        Dim args() As Object = {Index}

        Me.Invoke(handler, args)
    End Sub

    Private Sub RaiseFilteringUpdatedEvent_Impl(ByVal Index As Integer)
        RaiseEvent FilteringUpdated(Index)
    End Sub

    Private Sub ReceiveNewEvent(ByVal NewEvent As EventArrivedEventArgs)
        If _enabled Then
            InsertNewEvent(NewEvent.NewEvent.Properties("TargetInstance"))
        Else
            _tempEntries.Add(NewEvent.NewEvent.Properties("TargetInstance"))
        End If
    End Sub

    Private Sub RelocateTempEntries()
        For i As Integer = 0 To _tempEntries.Count - 1
            InsertNewEvent(_tempEntries(i))
        Next

        _tempEntries.Clear()
    End Sub

    Private Sub SetCurrentWqlToCurrent()
        _currentWql = New StringBuilder

        With _currentWql
            .Append("SELECT TimeGenerated, Message, RecordNumber, Type FROM Win32_NTLogEvent WHERE LogFile = 'Application' AND SourceName = '")
            .Append(_service.ToString)
            .Append("' AND TimeGenerated > '")
            .Append(Now.Year.ToString("0000"))
            .Append(Now.Month.ToString("00"))
            .Append(Now.Day.ToString("00"))
            .Append("'")
        End With
    End Sub

    Private Sub SetCurrentWqlToFiltered()
        _currentWql = New StringBuilder

        With _currentWql
            .Append("SELECT TimeGenerated, Message, RecordNumber, Type FROM Win32_NTLogEvent WHERE LogFile = 'Application' AND SourceName = '")
            .Append(_service.ToString)
            .Append("' AND TimeGenerated > '")
            .Append(dtpFilter.Value.Year.ToString("0000"))
            .Append(dtpFilter.Value.Month.ToString("00"))
            .Append(dtpFilter.Value.Day.ToString("00"))
            .Append("' AND TimeGenerated < '")

            Dim filterEnd As DateTime = dtpFilter.Value.AddDays(1)
            .Append(filterEnd.Year.ToString("0000"))
            .Append(filterEnd.Month.ToString("00"))
            .Append(filterEnd.Day.ToString("00"))
            .Append("'")
        End With
    End Sub

    Private Sub SetCurrentWqlToSearched()
        _currentWql = New StringBuilder

        With _currentWql
            .Append("SELECT TimeGenerated, Message, RecordNumber, Type FROM Win32_NTLogEvent WHERE LogFile = 'Application' AND SourceName = '")
            .Append(_service.ToString)
            .Append("' AND TimeGenerated > '")
            .Append(_previousFromDate.Year.ToString("0000"))
            .Append(_previousFromDate.Month.ToString("00"))
            .Append(_previousFromDate.Day.ToString("00"))
            .Append("' AND TimeGenerated < '")

            Dim toDate As DateTime = _previousToDate.AddDays(1)
            .Append(toDate.Year.ToString("0000"))
            .Append(toDate.Month.ToString("00"))
            .Append(toDate.Day.ToString("00"))
            .Append("' ")

            Select Case _previousStatus
                Case 1
                    .Append("AND Type = 'Information' ")
                Case 2
                    .Append("AND Type = 'Warning' ")
                Case 3
                    .Append("AND Type = 'Error' ")
            End Select

            .Append("AND Message LIKE '%")
            .Append(_previousMessage.ToString)
            .Append("%'")
        End With
    End Sub

#End Region
#Region "deletegate methods"

    Private Delegate Sub DisableControlsHandler()
    Private Delegate Sub EnableControlsHandler()
    Private Delegate Sub RaiseFilteringCompletedEventHandler()
    Private Delegate Sub RaiseFilteringStartedEventHandler(ByVal MaxValue As Integer)
    Private Delegate Sub RaiseFilteringUpdatedEventHandler(ByVal Index As Integer)
    Private Delegate Sub ReceiveNewEventHandler(ByVal NewEvent As EventArrivedEventArgs)

#End Region
#Region "properties"

    Public Property ComputerName() As String
        Get
            Return _machine.ToString
        End Get
        Set(ByVal value As String)
            _machine = New StringBuilder(value)
        End Set
    End Property

    Public Shadows Property Enabled() As Boolean
        Get
            Return _enabled
        End Get
        Set(ByVal value As Boolean)
            _enabled = value
            dtpFilter.Enabled = value
            btnClear.Enabled = value
            btnExport.Enabled = value
            btnFilter.Enabled = value
            btnSearch.Enabled = value

            If _enabled = False And _tempEntries.Count > 0 Then
                RelocateTempEntries()
            End If
        End Set
    End Property

    Public Property LogEntries() As ArrayList
        Get
            Return _entries
        End Get
        Set(ByVal value As ArrayList)
            _entries = value
        End Set
    End Property

    Public Property ServiceName() As String
        Get
            Return _service.ToString
        End Get
        Set(ByVal value As String)
            _service = New StringBuilder(value)
            Me.Text = value
        End Set
    End Property

#End Region

    Private Sub tmrReconnect_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrReconnect.Tick
        'reconect the log watcher
        _logWatcher.Stop()

        GC.Collect()

        _logWatcher.Start()
    End Sub

End Class

I have a Windows user control that reads events from the application log of a remote server. I can read in the information alright, and it appears to happen very quickly, however the thread hangs up for about 30 seconds afterwards and keeps my application from displaying the log.

I am afraid that this is probably caused by my lack of experience in dealing with threads, but I cannot be certain. I am definitely open to any suggestions with my threading here.

The easiest way to see what I am referring to is when the btnClear_click event handler is called. After jumping through the threading worm hole, it goes to the LoadFilteredEvent method. The results load fairly quickly from the ManagementObjectSearcher, but it hangs up for 30 to 60 seconds on the next statement.

Imports System.Management

Public Class LogMonitor
#Region "attributes"

    Private _currentWql As StringBuilder
    Private _enabled As Boolean
    Private _entries As ArrayList
    Private _logWatcher As ManagementEventWatcher
    Private _machine As StringBuilder
    Private _previousFromDate As DateTime
    Private _previousToDate As DateTime
    Private _previousStatus As Int16
    Private _previousMessage As StringBuilder
    Private _scope As ManagementScope
    Private _service As StringBuilder
    Private _tempEntries As ArrayList

    Public Event ExportCompleted()
    Public Event ExportStarted(ByVal ExportedResultCount As Integer)
    Public Event ExportUpdated(ByVal CurrentEntry As Integer)
    Public Event FilteringCompleted()
    Public Event FilteringStarted(ByVal LogEntryCount As Integer)
    Public Event FilteringUpdated(ByVal CurrentEntry As Integer)

#End Region
#Region "constructor"

    Public Sub New(ByVal ComputerName As String, ByVal ServiceName As String)
        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        _machine = New StringBuilder(ComputerName)
        _service = New StringBuilder(ServiceName)

        Me.Icon = Nothing
        Me.Text = ServiceName

        _enabled = True
        _previousFromDate = Now
        _previousToDate = Now
        _previousStatus = 0
        _previousMessage = New StringBuilder()

        _tempEntries = New ArrayList()

        Dim compPath As String = "\\" & _machine.ToString & "\root\cimv2"
        _scope = New ManagementScope(compPath, New ConnectionOptions())

        _scope.Connect()

        _logWatcher = New ManagementEventWatcher(New EventQuery(BuildWatcherWql()))
        _logWatcher.Scope = _scope
        AddHandler _logWatcher.EventArrived, AddressOf EventAdded

        Dim watcherThread As New Threading.Thread(AddressOf _logWatcher.Start)
        watcherThread.Start()
    End Sub

#End Region
#Region "events"

    Private Sub btnClear_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClear.Click
        dtpFilter.Value = Now.ToShortDateString
        SetCurrentWqlToCurrent()

        _logWatcher.Start()

        ' use a thread from the application's thread pool
        Threading.ThreadPool.QueueUserWorkItem(AddressOf FilterLogWorker)
    End Sub

    Private Sub btnFilter_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFilter.Click
        SetCurrentWqlToFiltered()

        If dtpFilter.Value.Equals(Now.ToShortDateString) Then
            _logWatcher.Start()
        Else
            _logWatcher.Stop()
        End If
        ' use a thread from the application's thread pool to load the new working directory
        Threading.ThreadPool.QueueUserWorkItem(AddressOf FilterLogWorker)
    End Sub

    Private Sub btnSearch_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSearch.Click
        Dim sf As New SearchFields
        sf.FromDate = _previousFromDate
        sf.ToDate = _previousToDate
        sf.EventStatus = _previousStatus
        sf.Message = _previousMessage.ToString

        If sf.ShowDialog = Windows.Forms.DialogResult.OK Then
            _previousFromDate = sf.FromDate
            _previousToDate = sf.ToDate
            _previousStatus = sf.EventStatus
            _previousMessage = New StringBuilder(sf.Message.Trim)

            SetCurrentWqlToSearched()

            _logWatcher.Stop()

            ' use a thread from the application's thread pool to load the new working directory
            Threading.ThreadPool.QueueUserWorkItem(AddressOf FilterLogWorker)
        End If
    End Sub

    Private Sub cmExport_ExportToFile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmExport_ExportToFile.Click
        If sfdExport.ShowDialog = Windows.Forms.DialogResult.OK Then
            ExportEntriesToFile(sfdExport.FileName)
        End If
    End Sub

    Private Sub cmExport_ExportToEmail_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmExport_ExportToEmail.Click
        ExportEntriesToEmail()
    End Sub

    Private Sub cmExport_ExportToExcel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmExport_ExportToExcel.Click
        If sfdExcel.ShowDialog = Windows.Forms.DialogResult.OK Then
            ExportEntriesToExcel(sfdExcel.FileName)
        End If
    End Sub

    Private Sub EventAdded(ByVal sender As Object, ByVal e As EventArrivedEventArgs)
        Dim handler As New ReceiveNewEventHandler(AddressOf ReceiveNewEvent)
        Dim args() As Object = {e}

        Me.Invoke(handler, args)
    End Sub

    Private Sub LogMonitor_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
        _logWatcher.Stop()
        _logWatcher.Dispose()
    End Sub

    Private Sub LogMonitor_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        dtpFilter.Value = Now.ToShortDateString()
    End Sub

    Private Sub tvEntries_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles tvEntries.DoubleClick
        If IsNothing(tvEntries.SelectedNode) = False Then
            Dim id As Long = CLng(tvEntries.SelectedNode.Tag)

            Dim ev As New EventViewer(_machine.ToString, id)
            ev.Show()
        End If
    End Sub

#End Region
#Region "functions"

    Private Sub AddNewEvent(ByVal EventObject As ManagementObject)
        tvEntries.Nodes.Add(BuildLogNodeFromObject(EventObject))
    End Sub

    Private Sub AddNewEvent(ByVal EventProperty As PropertyData)
        tvEntries.Nodes.Add(BuildLogNodeFromProperty(EventProperty))
    End Sub

    Private Function BuildLogNodeFromObject(ByVal EventObject As ManagementObject) As TreeNode
        Dim tempGenTime As String = EventObject.GetPropertyValue("TimeGenerated").ToString()
        Dim eventGenTime As DateTime = New DateTime(CInt(tempGenTime.Substring(0, 4)),
                                                    CInt(tempGenTime.Substring(4, 2)),
                                                    CInt(tempGenTime.Substring(6, 2)),
                                                    CInt(tempGenTime.Substring(8, 2)),
                                                    CInt(tempGenTime.Substring(10, 2)),
                                                    CInt(tempGenTime.Substring(12, 2)))
        Dim eventMessage As String = EventObject.GetPropertyValue("Message").ToString
        Dim newLineIndex As Integer = eventMessage.IndexOf(vbCrLf)

        Dim msg As New StringBuilder
        msg.Append(eventGenTime.ToString("MM/dd/yyyy HH:mm:ss"))
        msg.Append(" - ")
        msg.Append(eventMessage.Substring(0, newLineIndex))
        If eventMessage.Length > newLineIndex + 2 Then msg.Append("(more)")

        Dim myNode As New TreeNode
        myNode.Text = msg.ToString
        myNode.Tag = EventObject.GetPropertyValue("RecordNumber").ToString

        If EventObject.GetPropertyValue("Type").ToString.Equals("Error") Then myNode.ForeColor = Color.Red
        If EventObject.GetPropertyValue("Type").ToString.Equals("Warning") Then myNode.ForeColor = Color.Orange

        Return myNode
    End Function

    Private Function BuildLogNodeFromProperty(ByVal EventProperty As PropertyData) As TreeNode
        Dim mbo As ManagementBaseObject = CType(EventProperty.Value, ManagementBaseObject)
        Dim tempGenTime As String = mbo.Properties("TimeGenerated").Value.ToString()
        Dim eventGenTime As DateTime = New DateTime(CInt(tempGenTime.Substring(0, 4)),
                                                    CInt(tempGenTime.Substring(4, 2)),
                                                    CInt(tempGenTime.Substring(6, 2)),
                                                    CInt(tempGenTime.Substring(8, 2)),
                                                    CInt(tempGenTime.Substring(10, 2)),
                                                    CInt(tempGenTime.Substring(12, 2)))
        Dim eventMessage As String = mbo.Properties("Message").Value.ToString()
        Dim newLineIndex As Integer = eventMessage.IndexOf(vbCrLf)

        Dim msg As New StringBuilder
        msg.Append(eventGenTime.ToString("MM/dd/yyyy HH:mm:ss"))
        msg.Append(" - ")
        msg.Append(eventMessage.Substring(0, newLineIndex))
        If eventMessage.Length > newLineIndex + 2 Then msg.Append("(more)")

        Dim myNode As New TreeNode
        myNode.Text = msg.ToString
        myNode.Tag = mbo.Properties("RecordNumber").Value.ToString

        If mbo.Properties("Type").Value.ToString.Equals("Error") Then myNode.ForeColor = Color.Red
        If mbo.Properties("Type").Value.ToString.Equals("Warning") Then myNode.ForeColor = Color.Orange

        Return myNode
    End Function

    Private Function BuildWatcherWql() As String
        Dim wql As New StringBuilder("SELECT TimeGenerated, Message, RecordNumber, Type FROM __InstanceCreationEvent WHERE TargetInstance ISA  'Win32_NTLogEvent' ")
        wql.Append("AND TargetInstance.LogFile = 'Application' AND TargetInstance.SourceName = '")
        wql.Append(_service.ToString)
        wql.Append("'")

        Return wql.ToString
    End Function

    Private Sub DisableControls()
        Me.Invoke(New DisableControlsHandler(AddressOf DisableControls_Impl))
    End Sub

    Private Sub DisableControls_Impl()
        Enabled = False
    End Sub

    Private Sub EnableControls()
        Me.Invoke(New EnableControlsHandler(AddressOf EnableControls_Impl))
    End Sub

    Private Sub EnableControls_Impl()
        Enabled = True
    End Sub

    Private Sub EventLogWorker(ByVal state As Object)
        SyncLock tvEntries.GetType
            tvEntries.Invoke(CType(AddressOf LoadServiceHistory, MethodInvoker))
        End SyncLock
    End Sub

    Private Sub ExportEntriesToEmail()
        RaiseEvent ExportStarted(tvEntries.Nodes.Count)

        Try
            Dim outlook As Object = CreateObject("Outlook.Application")
            Dim mailMsg As Object
            Const olMailItem = 0

            mailMsg = outlook.CreateItem(olMailItem)

            Dim bodyText As New StringBuilder
            For i As Integer = 0 To tvEntries.Nodes.Count - 1
                bodyText.AppendLine(tvEntries.Nodes(i).Text)
                RaiseEvent ExportUpdated(i)
            Next

            mailMsg.Body = bodyText.ToString
            mailMsg.Subject = Me.Text & " exported results"
            mailMsg.Display()

            mailMsg = Nothing
            outlook = Nothing
        Catch ex As Exception
            MessageBox.Show("Problem exporting to Outlook." & vbCr & ex.Message, "Service Monitor Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try

        RaiseEvent ExportCompleted()
    End Sub

    Private Sub ExportEntriesToFile(ByVal FileName As String)
        RaiseEvent ExportStarted(tvEntries.Nodes.Count)

        Try
            Dim myFile As New IO.FileInfo(FileName)
            Dim myWriter As IO.TextWriter = myFile.CreateText()

            For i As Integer = 0 To tvEntries.Nodes.Count - 1
                myWriter.WriteLine(tvEntries.Nodes(i).Text)
                RaiseEvent ExportUpdated(i)
            Next

            myWriter.Close()
            myWriter.Dispose()
        Catch ex As Exception
            MessageBox.Show("Problem exporting to text file." & vbCr & ex.Message, "Service Monitor Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try

        RaiseEvent ExportCompleted()
    End Sub

    Private Sub ExportEntriesToExcel(ByVal FileName As String)
        RaiseEvent ExportStarted(tvEntries.Nodes.Count)

        Dim excel As Object = Nothing
        Dim xlWorkbook As Object = Nothing
        Dim xlWorksheet As Object = Nothing

        Try
            'Try to Open Excel, Add a workbook and worksheet
            excel = CreateObject("Excel.Application")
            xlWorkbook = excel.Workbooks.Add
            xlWorksheet = xlWorkbook.Sheets.Item(1)
        Catch ex As Exception
            MessageBox.Show("Problem exporting to Excel." & vbCr & ex.Message, "Service Monitor Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            Try
                If Not IsNothing(xlWorkbook) Then
                    xlWorkbook.Close()  'If an error occured we want to close the workbook
                End If
                If Not IsNothing(excel) Then
                    excel.Quit() 'If an error occured we want to close Excel
                End If
            Catch
            End Try
            xlWorksheet = Nothing
            xlWorkbook = Nothing
            excel = Nothing
            RaiseEvent ExportCompleted()
            Exit Sub
        End Try

        Try
            excel.DisplayAlerts = False    'This will prevent any message prompts from Excel (IE.."Do you want to save before closing?")
            excel.Visible = False    'We don't want the app visible while we are populating it.

            For i As Integer = 0 To tvEntries.Nodes.Count - 1
                Dim logTimeCell As Object = xlWorksheet.Range("A" & (i + 1))
                Dim messageCell As Object = xlWorksheet.Range("B" & (i + 1))

                Dim messageParts() As String = tvEntries.Nodes(i).Text.Split("-")

                logTimeCell.Value = messageParts(0).Trim
                messageCell.Value = messageParts(1).Trim

                logTimeCell = Nothing
                messageCell = Nothing

                RaiseEvent ExportUpdated(i)
            Next

            Dim outputRange = xlWorksheet.Range("A1:B" & tvEntries.Nodes.Count)
            outputRange.Columns.AutoFit()
            outputRange = Nothing

            xlWorkbook.SaveAs(FileName)
            xlWorkbook.Close()
            excel.Quit()
        Catch ex As Exception
            MessageBox.Show("While trying to Export to Excel recieved error:" & ex.Message, "Export to Excel Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            Try
                xlWorkbook.Close()  'If an error occured we want to close the workbook
                excel.Quit() 'If an error occured we want to close Excel
            Catch
            End Try
        Finally
            xlWorksheet = Nothing
            xlWorkbook = Nothing
            excel = Nothing
        End Try

        RaiseEvent ExportCompleted()
    End Sub

    Private Sub FilterLogWorker(ByVal state As Object)
        SyncLock tvEntries.GetType
            tvEntries.Invoke(CType(AddressOf LoadFilteredEvents, MethodInvoker))
        End SyncLock
    End Sub

    Private Sub InsertNewEvent(ByVal EventObject As ManagementObject)
        tvEntries.Nodes.Insert(0, BuildLogNodeFromObject(EventObject))
    End Sub

    Private Sub InsertNewEvent(ByVal EventProperty As PropertyData)
        tvEntries.Nodes.Insert(0, BuildLogNodeFromProperty(EventProperty))
    End Sub

    Public Sub LoadEntries()
        ' use a thread from the application's thread pool to load the new working directory
        Threading.ThreadPool.QueueUserWorkItem(AddressOf EventLogWorker)
    End Sub

    Public Sub LoadEntries(ByVal LogEntries As ArrayList)
        _entries = LogEntries
        LoadEntries()
    End Sub

    Private Sub LoadFilteredEvents()
        Dim search As New ManagementObjectSearcher(_scope.Path.ToString, _currentWql.ToString)
        Dim results As ManagementObjectCollection = search.Get
        Dim resultCounter As Integer = 0

        RaiseFilteringStartedEvent(results.Count)

        DisableControls()

        tvEntries.Nodes.Clear()

        For Each result As ManagementObject In results
            AddNewEvent(result)

            resultCounter += 1
            RaiseFilteringUpdatedEvent(resultCounter)
        Next

        results.Dispose()
        search.Dispose()

        EnableControls()
        RaiseFilteringCompletedEvent()
    End Sub

    Private Sub LoadServiceHistory()
        tvEntries.Nodes.Clear()

        For Each entry As ManagementObject In _entries
            AddNewEvent(entry)
        Next

        _entries.Clear()
    End Sub

    Private Sub RaiseFilteringCompletedEvent()
        Dim handler As New RaiseFilteringCompletedEventHandler(AddressOf RaiseFilteringCompletedEvent_Impl)
        Me.Invoke(handler)
    End Sub

    Private Sub RaiseFilteringCompletedEvent_Impl()
        RaiseEvent FilteringCompleted()
    End Sub

    Private Sub RaiseFilteringStartedEvent(ByVal MaxValue As Integer)
        Dim handler As New RaiseFilteringStartedEventHandler(AddressOf RaiseFilteringStartedEvent_Impl)
        Dim args() As Object = {MaxValue}

        Me.Invoke(handler, args)
    End Sub

    Private Sub RaiseFilteringStartedEvent_Impl(ByVal MaxValue As Integer)
        RaiseEvent FilteringStarted(MaxValue)
    End Sub

    Private Sub RaiseFilteringUpdatedEvent(ByVal Index As Integer)
        Dim handler As New RaiseFilteringUpdatedEventHandler(AddressOf RaiseFilteringUpdatedEvent_Impl)
        Dim args() As Object = {Index}

        Me.Invoke(handler, args)
    End Sub

    Private Sub RaiseFilteringUpdatedEvent_Impl(ByVal Index As Integer)
        RaiseEvent FilteringUpdated(Index)
    End Sub

    Private Sub ReceiveNewEvent(ByVal NewEvent As EventArrivedEventArgs)
        If _enabled Then
            InsertNewEvent(NewEvent.NewEvent.Properties("TargetInstance"))
        Else
            _tempEntries.Add(NewEvent.NewEvent.Properties("TargetInstance"))
        End If
    End Sub

    Private Sub RelocateTempEntries()
        For i As Integer = 0 To _tempEntries.Count - 1
            InsertNewEvent(_tempEntries(i))
        Next

        _tempEntries.Clear()
    End Sub

    Private Sub SetCurrentWqlToCurrent()
        _currentWql = New StringBuilder

        With _currentWql
            .Append("SELECT TimeGenerated, Message, RecordNumber, Type FROM Win32_NTLogEvent WHERE LogFile = 'Application' AND SourceName = '")
            .Append(_service.ToString)
            .Append("' AND TimeGenerated > '")
            .Append(Now.Year.ToString("0000"))
            .Append(Now.Month.ToString("00"))
            .Append(Now.Day.ToString("00"))
            .Append("'")
        End With
    End Sub

    Private Sub SetCurrentWqlToFiltered()
        _currentWql = New StringBuilder

        With _currentWql
            .Append("SELECT TimeGenerated, Message, RecordNumber, Type FROM Win32_NTLogEvent WHERE LogFile = 'Application' AND SourceName = '")
            .Append(_service.ToString)
            .Append("' AND TimeGenerated > '")
            .Append(dtpFilter.Value.Year.ToString("0000"))
            .Append(dtpFilter.Value.Month.ToString("00"))
            .Append(dtpFilter.Value.Day.ToString("00"))
            .Append("' AND TimeGenerated < '")

            Dim filterEnd As DateTime = dtpFilter.Value.AddDays(1)
            .Append(filterEnd.Year.ToString("0000"))
            .Append(filterEnd.Month.ToString("00"))
            .Append(filterEnd.Day.ToString("00"))
            .Append("'")
        End With
    End Sub

    Private Sub SetCurrentWqlToSearched()
        _currentWql = New StringBuilder

        With _currentWql
            .Append("SELECT TimeGenerated, Message, RecordNumber, Type FROM Win32_NTLogEvent WHERE LogFile = 'Application' AND SourceName = '")
            .Append(_service.ToString)
            .Append("' AND TimeGenerated > '")
            .Append(_previousFromDate.Year.ToString("0000"))
            .Append(_previousFromDate.Month.ToString("00"))
            .Append(_previousFromDate.Day.ToString("00"))
            .Append("' AND TimeGenerated < '")

            Dim toDate As DateTime = _previousToDate.AddDays(1)
            .Append(toDate.Year.ToString("0000"))
            .Append(toDate.Month.ToString("00"))
            .Append(toDate.Day.ToString("00"))
            .Append("' ")

            Select Case _previousStatus
                Case 1
                    .Append("AND Type = 'Information' ")
                Case 2
                    .Append("AND Type = 'Warning' ")
                Case 3
                    .Append("AND Type = 'Error' ")
            End Select

            .Append("AND Message LIKE '%")
            .Append(_previousMessage.ToString)
            .Append("%'")
        End With
    End Sub

#End Region
#Region "deletegate methods"

    Private Delegate Sub DisableControlsHandler()
    Private Delegate Sub EnableControlsHandler()
    Private Delegate Sub RaiseFilteringCompletedEventHandler()
    Private Delegate Sub RaiseFilteringStartedEventHandler(ByVal MaxValue As Integer)
    Private Delegate Sub RaiseFilteringUpdatedEventHandler(ByVal Index As Integer)
    Private Delegate Sub ReceiveNewEventHandler(ByVal NewEvent As EventArrivedEventArgs)

#End Region
#Region "properties"

    Public Property ComputerName() As String
        Get
            Return _machine.ToString
        End Get
        Set(ByVal value As String)
            _machine = New StringBuilder(value)
        End Set
    End Property

    Public Shadows Property Enabled() As Boolean
        Get
            Return _enabled
        End Get
        Set(ByVal value As Boolean)
            _enabled = value
            dtpFilter.Enabled = value
            btnClear.Enabled = value
            btnExport.Enabled = value
            btnFilter.Enabled = value
            btnSearch.Enabled = value

            If _enabled = False And _tempEntries.Count > 0 Then
                RelocateTempEntries()
            End If
        End Set
    End Property

    Public Property LogEntries() As ArrayList
        Get
            Return _entries
        End Get
        Set(ByVal value As ArrayList)
            _entries = value
        End Set
    End Property

    Public Property ServiceName() As String
        Get
            Return _service.ToString
        End Get
        Set(ByVal value As String)
            _service = New StringBuilder(value)
            Me.Text = value
        End Set
    End Property

#End Region

    Private Sub tmrReconnect_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrReconnect.Tick
        'reconect the log watcher
        _logWatcher.Stop()

        GC.Collect()

        _logWatcher.Start()
    End Sub

End Class

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

染火枫林 2024-08-05 11:10:34

经过大量时间处理该问题后,我发现问题是由于返回大量条目造成的。 我必须将 ManagementObjectSearcher 设置为不立即返回结果。 发生的情况是搜索器对象立即返回,它没有返回所有结果,但是当我去获取结果计数时,它会等到该过程完成。 它实际上并没有加速任何事情,但它确实解释了正在发生的事情。

After a lot of time working on the issue, I found that the problem was due to a large number of entries being returned. I had to set the ManagementObjectSearcher to not return results immediately. What was happening was with the searcher object returning immediately, it had not returned all of the results, but when I went to get the count of the results, it waited until the process was complete. It did not actually speed anything up, but it did explain what was happening.

我只土不豪 2024-08-05 11:10:34

结果加载速度相当快
ManagementObjectSearcher,但它
挂断 30 至 60 秒
下一个声明。

如果您的意思是它挂在 = search.Get 上,那就是实际执行搜索的时间(而不是您创建 ManagementObjectSearcher 时)。

情况就是这样……

当您使用 WHERE 时,WQL 查询可能会非常慢状况。
您应该检查是否是查询本身花费了这么长时间。 在 Windows 附带的 WMI 测试应用程序 wbemtest.exe 中尝试几个不同的查询。

  1. 运行 wbemtest.exe
  2. 'Open Namespace...' to "root\cimv2"
  3. 'Query...' 使用不同的查询,例如
    • 从 Win32_NTLogEvent 选择 * --> 对我来说,返回 35K 条记录大约需要 15 秒

几年前,当我查询大量数据时,我遇到了一个问题,我尝试使用 WHERE 条件。 它完全无法使用。 最后我只是无条件地从 WMI 中请求所有项目,然后通过计算排序并删除不匹配的项目。 它并不“漂亮”(感觉不应该是这样),但它把时间从 20 分钟缩短到 2-3 秒......

The results load fairly quickly from
the ManagementObjectSearcher, but it
hangs up for 30 to 60 seconds on the
next statement.

If you mean it hangs on = search.Get, that's when the search is actually performed (not when you create the ManagementObjectSearcher.

It's that's the case...

WQL queries can be very slow when you use WHERE conditions.
You should check whether it's the query itself that's taking so long. Try out a couple of different queries in the WMI test app that comes with windows, wbemtest.exe.

  1. Run wbemtest.exe
  2. 'Open Namespace...' to "root\cimv2"
  3. 'Query...' with different queries, e.g.
    • Select * from Win32_NTLogEvent --> for me, took about 15 seconds to return 35K records

A few years ago I ran into a problem when I had query for a large amount of data and I had tried to use WHERE conditions. It was completely unusable. In the end I just asked for all items from WMI with no conditions, and then computationally sorted and removed items that didn't match. It wasn't "pretty" (didn't feel like it ought to be that way) but it cut the time from 20 minutes to 2-3 seconds...

玻璃人 2024-08-05 11:10:34

结果加载速度相当快
ManagementObjectSearcher,但它
挂断 30 至 60 秒
下一个声明。

如果您的意思是 For Each result As ManagementObject In results 需要很长时间,那么这里有一些需要注意的问题:

  • 您在结果中获得了多少结果?
  • 您的意思是使用“Invoke”吗? 调用是同步的,即它会等到函数完成后再继续处理。 “BeginInvoke”是异步调用。

The results load fairly quickly from
the ManagementObjectSearcher, but it
hangs up for 30 to 60 seconds on the
next statement.

If you mean it takes a long time on For Each result As ManagementObject In results then here are some questions to look at:

  • How many results are you getting in results?
  • Do you mean to be using "Invoke"? Invoke is synchronous, i.e. it waits until the function is complete before continuing processing. "BeginInvoke" is the asynchronous call.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文