Question

I've writte this simple algorithm to stop a complete process tree from vb.net:

Private Sub TerminateProcessTree2(P As Process)
    Dim Tree = GenerateProcessTree(P)
    For Each childproc As Process In Tree
        Try
            If childproc.HasExited = False Then childproc.Kill()
        Catch ex As Exception
            AddError("Could not delete process " & childproc.ProcessName & ". " & ex.Message)
        End Try
    Next
    Dim pName As String = "<unknown>"
    Try
        If P IsNot Nothing Then
            pName = P.ProcessName
            If P.HasExited = False Then P.Kill()
        End If
    Catch ex As Exception
        AddError("Error killing process " & pName & ". " & ex.Message)
    End Try

End Sub

Function GenerateProcessTree(p As Process) As Collections.Generic.HashSet(Of Process)
    Dim hash As New Collections.Generic.HashSet(Of Process)
    GenerateProcessTreeNode(p, hash)
    Return hash
End Function

Private Sub GenerateProcessTreeNode(parent As Process, hash As Collections.Generic.HashSet(Of Process))
    Dim searcher As New ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" & parent.Id)
    Dim moc As ManagementObjectCollection = searcher.[Get]()
    For Each mo As ManagementObject In moc
        Dim i As Integer = CInt(mo("ProcessID"))
        Dim childP As Process
        Try
            childP = Process.GetProcessById(i)
            If childP IsNot Nothing AndAlso hash.Contains(childP) = False Then
                hash.Add(childP)
                GenerateProcessTreeNode(childP, hash)
            End If
        Catch ex As Exception
            AddError("Could not get process ID for " & mo.ToString)
            Continue For
        End Try
    Next
End Sub

But, some of my program users are telling me that, every once in a while (like one or two percent of the times), this algorithm closes ALL processes, and not only child process from the given process. How can this be possible? and does anything need to be fixed from the algorithm? I suppose there are easiest ways to do this, but I want to know why this one fails.

Was it helpful?

Solution

Your code works as expected and is correct. IMO the problem occurs because of the WMI property ParentProcessId. MSDN says:

ParentProcessId

Data type: uint32
Access type: Read-only

Unique identifier of the process that creates a process. 
Process identifier numbers are reused, so they only identify
a process for the lifetime of that process. It is possible that
the process identified by ParentProcessId is terminated, so 
ParentProcessId may not refer to a running process. It is also 
possible that ParentProcessId incorrectly refers to a process 
that reuses a process identifier. You can use the CreationDate 
property to determine whether the specified parent was created
after the process represented by this Win32_Process instance 
was created.

I assume, that your HashSet holds at some point ProcessId's that where replaced by the system with new processes and the new processes and not child processes anymore but are still in the collection and are terminated when fetched from the list.

You could extensively log every call of the process.Kill() (name, process id, timestamp, and so on) and then try to track the problem using the log.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top