0

I am using ManagementEventWatcher to get message when process start and stop. I am successfully getting message when word process start it displays me File name and datetime. I have an issue in stopping process.

Public Class Form1
    Dim list As New List(Of String)
    Dim list1 As New List(Of String)
    Private processStartEvent As ManagementEventWatcher = New ManagementEventWatcher("SELECT * FROM Win32_ProcessStartTrace")
    Private processStopEvent As ManagementEventWatcher = New ManagementEventWatcher("SELECT * FROM Win32_ProcessStopTrace")

    Public Sub New()
        InitializeComponent()
        AddHandler processStartEvent.EventArrived, New EventArrivedEventHandler(AddressOf processStartEvent_EventArrived)
        processStartEvent.Start()
        AddHandler processStopEvent.EventArrived, New EventArrivedEventHandler(AddressOf processStopEvent_EventArrived)
        processStopEvent.Start()
    End Sub

    Private Sub processStartEvent_EventArrived(ByVal sender As Object, ByVal e As EventArrivedEventArgs)
        Dim allProcesses = Process.GetProcesses().Where(Function(p) p.ProcessName.Contains("WINWORD"))
        Dim windowTitles = ChildWindowManager.GetChildWindowTitles(allProcesses.First().Id)
        For Each title In windowTitles
            If (title.Contains("- Word")) Then
                If Not (title.Contains("Opening - Word")) Then
                    If Not list.Contains(title) Then
                        list.Add(title)
                        MessageBox.Show("+ Process Started. File Name: " & String.Join(",", list.Item(list.Count - 1)) & " | Date & Time: " & System.DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss") & vbNewLine & vbNewLine)
                    End If
                End If
            End If
        Next
    End Sub

    Private Sub processStopEvent_EventArrived(ByVal sender As Object, ByVal e As EventArrivedEventArgs)

    End Sub
End Class

Class ChildWindowManager
    Delegate Function EnumThreadDelegate(ByVal hWnd As IntPtr, ByVal lParam As IntPtr) As Boolean

    <DllImport("user32.dll")>
    Private Shared Function EnumThreadWindows(ByVal dwThreadId As Integer, ByVal lpfn As EnumThreadDelegate, ByVal lParam As IntPtr) As Boolean
    End Function

    <DllImport("user32.dll")>
    Public Shared Function GetWindowText(ByVal hwnd As Integer, ByVal lpString As System.Text.StringBuilder, ByVal cch As Integer) As Integer
    End Function

    <DllImport("user32.dll")>
    Private Shared Function GetWindowTextLength(ByVal hwnd As IntPtr) As Integer
    End Function

    Private Shared Function EnumerateProcessWindowHandles(ByVal processId As Integer) As List(Of IntPtr)
        Dim windowHandles = New List(Of IntPtr)()

        For Each thread As ProcessThread In Process.GetProcessById(processId).Threads
            EnumThreadWindows(thread.Id, Function(hWnd, lParam)
                                             windowHandles.Add(hWnd)
                                             Return True
                                         End Function, IntPtr.Zero)
        Next
        Return windowHandles
    End Function

    Private Shared Function GetWindowTitle(ByVal hWnd As IntPtr) As String
        Dim length As Integer = GetWindowTextLength(hWnd)
        If length = 0 Then Return Nothing

        Dim titleStringBuilder As New System.Text.StringBuilder("", length)

        GetWindowText(hWnd, titleStringBuilder, titleStringBuilder.Capacity + 1)
        Return titleStringBuilder.ToString()
    End Function

    Public Shared Function GetChildWindowTitles(processId As Integer) As List(Of String)
        Dim windowTitles As New List(Of String)

        For Each Handle In EnumerateProcessWindowHandles(processId)
            Dim windowText = GetWindowTitle(Handle)
            If windowText <> Nothing Then
                windowTitles.Add(windowText)
            End If
        Next

        Return windowTitles
    End Function
End Class
theduck
  • 2,589
  • 13
  • 17
  • 23
  • What's the issue you are having? Does it not call the handler? – theduck Nov 27 '19 at 10:48
  • How to get notification or Messagebox when process will stop. – Muhammad Umer Nawaz Nov 27 '19 at 10:53
  • So does you `processStopEvent_EventArrived` sub ever get called? – theduck Nov 27 '19 at 11:00
  • Private Sub processStopEvent_EventArrived(ByVal sender As Object, ByVal e As EventArrivedEventArgs) Dim processName As String = e.NewEvent.Properties("ProcessName").Value.ToString Dim processID As String = Convert.ToInt32(e.NewEvent.Properties("ProcessID").Value).ToString If (processName = "WINWORD.EXE") Then list1.Add(processID) list1.Add(processName) FileIO.WriteToFile("- Process stopped. Name: " & list1(1).ToArray & " | ID: " & list1(0).ToArray) End If End Sub – Muhammad Umer Nawaz Nov 27 '19 at 11:19
  • the above code i am using for stopping process – Muhammad Umer Nawaz Nov 27 '19 at 11:21
  • Your code works for me. When I close Word done it calls the correct handler and I can see the `processName` contains `WINWORD.EXE`. Can you explain in a bit more detail where you are having problems? Does the handler get called? – theduck Nov 27 '19 at 12:04
  • if you will open multiple word applications at a time it will automatically stop process – Muhammad Umer Nawaz Nov 28 '19 at 12:28
  • OK. The problem with multiple documents is that Word is a single process. When you open a 2nd document it doesn't create a new Word process - it just creates a new child window in the existing Word process. I don't believe at any time you will have any more than one Word process no matter how many documents you have open. There is no trigger (that I know of) that will tell you when a document/child window is closed. The only way to achieve that would be to enumerate them on a timer. – theduck Nov 28 '19 at 19:47

0 Answers0