.NET Events for Process executable start
Asked Answered
P

3

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?

Polysyndeton answered 11/5, 2009 at 15:23 Comment(0)
B
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.

Babysitter answered 13/5, 2009 at 13:28 Comment(10)
This code could be refactored, but I have left it verbose to hopefully aid understandingBabysitter
actually this code looks well. But it does not work for me. I am missing any point? win7 , net 2.o project.Apanage
is this possible for compact framework? same i want to do for windows mobile 6.5 .Swats
Hey, my ManagementBaseObject object returned has all the properties set to null except for "Handle."Abernathy
How can i get notification for all new processes and not only notepad?Leveller
@Leveller 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' ";Babysitter
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 slowLeveller
@Leveller 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.Babysitter
@Babysitter 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.Socalled
I need to subscribe to multiple specific processes.Socalled
S
1

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

Shealy answered 12/5, 2009 at 12:3 Comment(1)
@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.Shealy
D
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);
            }
        }
    }
}
Damnify answered 6/6, 2016 at 17:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.