19

Is there any way to register for an event that fires when an executable of a particular filename starts? I know it's easy enough to get an event when a process exits, by getting the process handle and registering for the exited event. But how can you be notified when a process, that isn't already running, starts...without polling all the running processes?

Adam Haile
  • 30,705
  • 58
  • 191
  • 286

3 Answers3

32

You could use the following:

    private ManagementEventWatcher WatchForProcessStart(string processName)
    {
        string queryString =
            "SELECT TargetInstance" +
            "  FROM __InstanceCreationEvent " +
            "WITHIN  10 " +
            " WHERE TargetInstance ISA 'Win32_Process' " +
            "   AND TargetInstance.Name = '" + processName + "'";

        // The dot in the scope means use the current machine
        string scope = @"\\.\root\CIMV2";

        // Create a watcher and listen for events
        ManagementEventWatcher watcher = new ManagementEventWatcher(scope, queryString);
        watcher.EventArrived += ProcessStarted;
        watcher.Start();
        return watcher;
    }

    private ManagementEventWatcher WatchForProcessEnd(string processName)
    {
        string queryString =
            "SELECT TargetInstance" +
            "  FROM __InstanceDeletionEvent " +
            "WITHIN  10 " +
            " WHERE TargetInstance ISA 'Win32_Process' " +
            "   AND TargetInstance.Name = '" + processName + "'";

        // The dot in the scope means use the current machine
        string scope = @"\\.\root\CIMV2";

        // Create a watcher and listen for events
        ManagementEventWatcher watcher = new ManagementEventWatcher(scope, queryString);
        watcher.EventArrived += ProcessEnded;
        watcher.Start();
        return watcher;
    }

    private void ProcessEnded(object sender, EventArrivedEventArgs e)
    {
        ManagementBaseObject targetInstance = (ManagementBaseObject) e.NewEvent.Properties["TargetInstance"].Value;
        string processName = targetInstance.Properties["Name"].Value.ToString();
        Console.WriteLine(String.Format("{0} process ended", processName));
    }

    private void ProcessStarted(object sender, EventArrivedEventArgs e)
    {
        ManagementBaseObject targetInstance = (ManagementBaseObject)e.NewEvent.Properties["TargetInstance"].Value;
        string processName = targetInstance.Properties["Name"].Value.ToString();
        Console.WriteLine(String.Format("{0} process started", processName));
    }

You would then call either WatchForProcessStart and/or WatchForProcessEnd passing in your process name (eg "notepad.exe").

The ManagementEventWatcher object is returned from the two Watch* methods as it implements IDisposable and so you should call Dispose on these objects when you have finished with them to prevent issues.

You could also change the polling value in the queries if you need the event to be raised more quickly after the process has started. To do this change the line "WITHIN 10" to be WITHIN something less than 10.

Clive
  • 3,470
  • 1
  • 20
  • 9
  • This code could be refactored, but I have left it verbose to hopefully aid understanding – Clive May 13 '09 at 15:42
  • actually this code looks well. But it does not work for me. I am missing any point? win7 , net 2.o project. – Yaya Sep 11 '11 at 11:16
  • is this possible for compact framework? same i want to do for windows mobile 6.5 . – akrant_iOSDeveloper Sep 19 '11 at 05:29
  • Hey, my ManagementBaseObject object returned has all the properties set to null except for "Handle." – chaz May 14 '13 at 04:26
  • How can i get notification for all new processes and not only notepad? – Hossein Jan 02 '14 at 04:16
  • 1
    @Hossein you should be able to edit the WatchForProcessStart method. Remove the processName argument and then change the queryString string to: `"SELECT TargetInstance.Name FROM __InstanceCreationEvent WITHIN 10 WHERE TargetInstance ISA 'Win32_Process' ";` – Clive Jan 03 '14 at 13:19
  • Thanks alot :-), By the way if I set that 10 to 1 does it mean it will pool every 1 millisecond? I noticed there is a lag in getting the info using wmi, i wonder if thats a c#/.net issue or wmi itself is slow – Hossein Jan 03 '14 at 15:28
  • @Hossein I believe the value is in seconds, not milliseconds. Not sure there is a way to get the code to be super (sub-second) responsive. – Clive Jan 26 '14 at 17:13
  • @Clive in my use case, I am subscribing to too many processes, throwing a `System.Management.ManagementException: Quota violation`. How would I modify this query to subscribe to multiple processes with a single query? My thought for a solution to this issue is to subscribe to the event for all desired processes with a single query, and then filter by process name myself from my code. – Mat Jones Jan 10 '17 at 15:11
  • I need to subscribe to multiple **specific** processes. – Mat Jones Jan 10 '17 at 15:50
1

Here is code.

Notice that you have to start Visual Studio like Administrator in order to execute this code.

using System;
using System.Management;

namespace AppLaunchDetector
{
    class Program
    {
        static void Main(string[] args)
        {           
            ManagementEventWatcher w = null;
            WqlEventQuery q;
            try
            {
                q = new WqlEventQuery();
                q.EventClassName = "Win32_ProcessStartTrace";
                w = new ManagementEventWatcher(q);
                w.EventArrived += new EventArrivedEventHandler(ProcessStartEventArrived);
                w.Start();
                Console.ReadLine(); // block main thread for test purposes
            }
            catch (Exception ex)
            {

            }
            finally
            {
                w.Stop();
            }
        }

        static void ProcessStartEventArrived(object sender, EventArrivedEventArgs e)
        {
            foreach (PropertyData pd in e.NewEvent.Properties)
            {
                Console.WriteLine("\n============================= =========");
                Console.WriteLine("{0},{1},{2}", pd.Name, pd.Type, pd.Value);
            }
        }
    }
}
NoWar
  • 36,338
  • 80
  • 323
  • 498
1

WMI can create events when processes are created. You could then filter these events.

Richard
  • 106,783
  • 21
  • 203
  • 265
  • @Adam: I was expecting that comment. Unfortunately it has been a while since I worked with WMI events (years), and not with .NET so I would have to learn how to do it myself ... and don't have time at this moment. – Richard May 12 '09 at 16:52