Resolved Problem with System.Diagnostics.Process.GetProcesses

usminion

Member
Joined
Jul 19, 2009
Messages
11
Programming Experience
5-10
I am fairly new to VB.NET (but have vast professional experience with several other languages) and am completely new to these forums (so please don't burn me if I posted in the wrong place). I have run into a rather odd quirk with System.Diagnostics.Process.GetProcesses. I have a sample application (source posted below) that checks all running processes every second for changes (created and destroyed) and tells the user what has changed, if anything, in the last second. The sample runs for anywhere between 29-72 seconds before issuing an array out of bounds error. It appears that the Windows system processes, SearchProtocolHost.exe and SearchFilterHost.exe explicitly, disappear from the list causing my application to throw the aforementioned exception. Specifically the exception I am receiving is as follows:

Unhandled Exception: System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.

I have noted in comments where the exception is thrown in the code below. If any of you would be willing to try this sample on your PC's or could suggest potential issues with my sample that could cause this problem I would be very appreciative.

My sample code:
VB.NET:
Imports System
Imports System.Diagnostics
Imports System.ComponentModel
Imports System.Management
Imports Microsoft.Win32
Imports System.Collections
Imports System.Collections.Generic
Imports System.Threading

Namespace ProcessMonitor
    Class ProcessMonitor
        Shared bFinished As Boolean = False
        Dim dictRunning As Dictionary(Of String, Integer) = New Dictionary(Of String, Integer)

        Shared Sub GetInput()
            While Not bFinished
                Console.ReadKey(True)
                bFinished = True
            End While
        End Sub

        Sub BindToRunningProcesses()
            Dim procInfo As Process
            Dim currProc As KeyValuePair(Of String, Integer)
            Dim listRemove As List(Of String) = New List(Of String)
            Dim listReset As List(Of String) = New List(Of String)
            Dim arrProc As Process()
            Dim times As Integer

            ' Loop until key pressed
            While Not bFinished
                arrProc = Process.GetProcesses()

                ' Loop through all of the known processes
                For Each procInfo In arrProc
                    Try
                        If Not Me.dictRunning.ContainsKey(procInfo.MainModule.ModuleName) Then
                            Console.WriteLine("Started: " & procInfo.MainModule.ModuleName)
                            Me.dictRunning.Add(procInfo.MainModule.ModuleName, 1)
                        Else
                            Me.dictRunning(procInfo.MainModule.ModuleName) = 1
                        End If
                    Catch ex As Exception
                        ' Ignore Exceptions
                        'Console.WriteLine("Exception (" & procInfo.ProcessName + "): " & ex.Message)
                    End Try
                Next

                Dim count As Integer = Me.dictRunning.Count
                For i As Integer = 0 To (count - 1)
                    ' The following line is where the exception is thrown
                    currProc = Me.dictRunning.ElementAt(i)
                    If currProc.Value = 0 Then
                        Console.WriteLine("Stopped: " & currProc.Key)
                        Me.dictRunning.Remove(currProc.Key)
                        count = count - 1
                    Else
                        Me.dictRunning(currProc.Key) = 0
                    End If
                Next

                times = times + 1
                Console.WriteLine(times)
                Thread.Sleep(1000)
            End While
        End Sub 'BindToRunningProcesses

        Shared Sub Main()
            Dim myProcess As New ProcessMonitor()
            Dim T As Thread = New Thread(AddressOf GetInput)

            T.Start()
            myProcess.BindToRunningProcesses()
        End Sub 'Main 
    End Class
End Namespace

Edit:
I am running VB.NET 2008 Express Edition (Framework v3.5) on Vista Home Premium with SP1
 
Last edited:
Solved!

I found the problem... I guess I made incorrect assumptions about the For statement. It seems that VB.NET was storing the return value of Me.dictRunning.Count in a temporary local variable rather than re-evaluating it each time (possibly to enhance performance). The solution was to manage a count manually as you can see in the code posted below.

VB.NET:
Imports System
Imports System.Diagnostics
Imports System.ComponentModel
Imports System.Management
Imports Microsoft.Win32
Imports System.Collections
Imports System.Collections.Generic
Imports System.Threading
Imports System.Reflection

Namespace ProcessMonitor
    Class ProcessMonitor
        Shared bFinished As Boolean = False
        Dim dictRunning As Dictionary(Of String, Integer) = New Dictionary(Of String, Integer)

        Shared Sub GetInput()
            While Not bFinished
                Console.ReadKey(True)
                bFinished = True
            End While
        End Sub

        Sub BindToRunningProcesses()
            Dim procInfo As Process
            Dim currProc As KeyValuePair(Of String, Integer)
            Dim listRemove As List(Of String) = New List(Of String)
            Dim listReset As List(Of String) = New List(Of String)
            Dim arrProc As Process()
            Dim times As Integer

            ' Loop until key pressed
            While Not bFinished
                arrProc = Process.GetProcesses()

                ' Loop through all of the known processes
                For Each procInfo In arrProc
                    Try
                        If Not Me.dictRunning.ContainsKey(procInfo.MainModule.ModuleName) Then
                            Console.WriteLine("Started: " & procInfo.MainModule.ModuleName)
                            Me.dictRunning.Add(procInfo.MainModule.ModuleName, 1)
                        Else
                            Me.dictRunning(procInfo.MainModule.ModuleName) = 1
                        End If
                    Catch ex As Exception
                        ' Ignore Exceptions
                        'Console.WriteLine("Exception (" & procInfo.ProcessName + "): " & ex.Message)
                    End Try
                Next

                ' We need to maintain the count manually since
                ' dictRunning.Count is only evaluated in the first
                ' iteration
                Dim count As Integer = Me.dictRunning.Count
                For i As Integer = 0 To (count - 1)
                    Try
                        currProc = Me.dictRunning.ElementAt(i)
                        If currProc.Value = 0 Then
                            Console.WriteLine("Stopped: " & currProc.Key)
                            Me.dictRunning.Remove(currProc.Key)
                            count = count - 1
                        Else
                            Me.dictRunning(currProc.Key) = 0
                        End If
                    Catch ex As Exception
                        ' Ignore Exceptions
                        'Console.WriteLine("Exception (" & procInfo.ProcessName + "): " & ex.Message)
                    End Try
                Next

                times = times + 1
                Console.WriteLine(times)
                Thread.Sleep(1000)
            End While
        End Sub 'BindToRunningProcesses

        Shared Sub Main()
            Dim myProcess As New ProcessMonitor()
            Dim T As Thread = New Thread(AddressOf GetInput)

            T.Start()
            myProcess.BindToRunningProcesses()
        End Sub 'Main 
    End Class
End Namespace
 
Back
Top