Search code examples
vb.netprocessmultiple-processes

How to create a function that can wait for multiple processes to exit?


I am creating a windows service that will write all the start time and exit time for specific process that I wanted to monitor. The problem is when I am trying to monitor the process to wait for exit, I have no idea on how to wait multiple process to exit. Below are my code for writing the start time of the process.

Try
    Using regkey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey("SOFTWARE\MonitoringApplication\Login", RegistryKeyPermissionCheck.Default)
        childrenID = regkey.GetValue("Login User").ToString
    End Using
    If childrenID.Equals("admin") Then
    Else
        Dim connection As New SqlConnection("Server=DESKTOP-FTJ3EOA\SQLEXPRESS;Initial Catalog=MonitorDB;User ID = admin; Password = admin")
        Dim command As New SqlCommand("SELECT  App.ApplicationName FROM App INNER JOIN ChildrenApplication ON App.ApplicationID = ChildrenApplication.ApplicationID WHERE ChildrenID = @a", connection)
        command.Parameters.Add("@a", SqlDbType.VarChar).Value = childrenID
        Dim adapter As New SqlDataAdapter(command)
        Dim table As New DataTable()
        adapter.Fill(table)

        Using sw As StreamWriter = New StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "\MonitoringApplication.txt", True)

            For Each row As DataRow In table.Rows
                p = Process.GetProcessesByName(row.Item(0))
                Using myprocess = New Process
                    If p.Count > 0 Then
                        myprocess.StartInfo.FileName = row.Item(0)
                        myprocess.EnableRaisingEvents = True
                        sw.WriteLine(row.Item(0) + "running")

                    End If
                End Using
            Next row
        End Using

        Const SLEEP_AMOUNT As Integer = 100
        Do While Not eventHandled
            elapsedTime += SLEEP_AMOUNT
            If elapsedTime > 30000 Then
                Exit Do
            End If
            Thread.Sleep(SLEEP_AMOUNT)
        Loop
    End If
Catch ex As Exception
    Using sw As StreamWriter = New StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "\MonitoringApplication.txt", True)
        sw.WriteLine(ex)
    End Using
End Try

Private Sub myProcess_Exited(ByVal sender As Object, ByVal e As System.EventArgs) Handles myProcess.Exited
    eventHandled = True
    Using sw As StreamWriter = New StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "\MonitoringApplication.txt", True)
        sw.WriteLine("Exited")
    End Using
End Sub

Is there any ways to monitor multiple process to exit? Thanks in advance.


Solution

  • You're now using Process.GetProcessesByName() to retrieve an array of running processes, if any.
    You can use the returned array of processes and subscribe to the Exited event of each one to log the exit time of any of the processes in the array.

    Setting EnableRaisingEvent is necessary to raise the Exited event, but you also need to subscribe to event, using AddHandler along with the address of a method or a Lambda:

    AddHandler [Process].Exited, AddressOf [Handler]
    ' or 
    AddHandler [Process].Exited, Sub() [Lambda]
    

    This method accepts a process name and the path to a file where to store the name of the process and its exit time when the Exited event is raised.

    If your current loop:

    For Each row As DataRow In table.Rows
        '(...)
    Next
    

    You can insert a call to this method:

    For Each row As DataRow In table.Rows
        SubscribeProcExit(row.Item(0), Path.Combine(Application.StartupPath, "MonitoringApplication.txt"))
    Next
    

    If the log file doesn't exit, it will be created and a new line is added each time one of the Processes exits, logging the Process.ProcessName and Process.ExitTime.
    Note that row.Item(0) must contain the friendly name of the Process. For example, notepad.exe must be referenced as just "notepad".

    Private Sub SubscribeProcExit(processName As String, fileName As String)
        Dim processes As Process() = Process.GetProcessesByName(processName)
        If processes.Length = 0 Then Return
        For Each p As Process In processes
            p.EnableRaisingEvents = True
            AddHandler p.Exited,
                Sub()
                    Using sw As StreamWriter = File.AppendText(fileName)
                        sw.WriteLine($"Process: {p?.ProcessName}, Exit Time: {p?.ExitTime}")
                        p?.Dispose()
                    End Using
                End Sub
        Next
    End Sub