Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ProcessWatcher: Leverage ManagementEventWatcher to Always Know What Is Running on Your System

0.00/5 (No votes)
21 Dec 2015 1  
This little desktop app gives you an easy way to track processes which start and stop even when your computer is locked. Also, easily save data and view in Excel.

Introduction

This little utility will allow you to view all the processes which start and stop on your machine -- even when you've locked the screen. It's easy to use and the code reveals a couple of interesting tricks.

Process Watcher main form (running)

Quick Fix - V2*

Soon after release, I noticed that I forgot to provide a scrollbar on the Multi-line TextBox. It's very simple to change, but a bit annoying. Now, you can leave the application run for a long time and scroll through the long list of items.

Background

I wanted an easy way to track programs (processes) which start and stop on my machine even when I locked it and left for lunch or a meeting. I found this little trick which leverages the WMI (Windows Management Instrumentation) which I often run in a copy of LinqPad (see http://Linqpad.net^ for more). Sometimes, you just want to know what your computer is doing and what processes run which are started by the OS.

Not Perfect, But Extremely Usable

There are a few things to know before I show you the code.

I created this app very quickly to solve a specific problem. That means I've implemented the functionality in a "get 'er done" kind of way. What things might you notice?

  1. TextBox output: I used a simple textbox for the output. It's good enough. I Append() to a StringBuilder and output the string to the TextBox each time a new WMI event fires. If you don't like that, you can always download the code and change it.
  2. Delimited output: I've quickly tab and pipe delimited the text so you can easily import the data into Excel if you like. It's not the most beautiful, but again it works.
  3. SaveFile: The SaveFileDialog is the generic one and I don't set any wildcard or extension or anything. You can save the data in the output very quickly (I use System.IO.File.AppendAllText) and then use the data however you want. It's simple and quick.
  4. OOP Is Alive: One thing I did not skimp on, however, is separating out the functionality so you can easily grab the class and use it in your own application. You'll find the core code in the EventWatcher.cs. Since I am updating the TextBox control on the MainForm, I do require a reference to that form and I pass it in on the constructor -- so it is somewhat tied to that form. But all of the code which does the work of watching processes on your Windows machine will be separated enough that it'll be easy to use the class in your own project if you like.

Now, let's get to it. I'll show you how the little bit of code works.

Using the Code

Main Point of this Utility

The main point of this application is to allow it to run for a long time (1 or 2 days) so you can see the numerous processes which are started by the OS itself -- or other installed software. This can help you find processes you never knew were running before.

Let's take a look at the main worker class (EventWatcher) in the project because it reveals the easy way to watch processes on your computer.

The C# class called ManagementEventWatcher (you'll need a reference to System.Management.dll) provides a nice wrapper to the WMI interface. The one tricky thing about it, however, is that the methods you call start listeners to systems events which are basically threads you'll have to manage.

In the EventWatcher's constructor, the first thing I do is register (save off) the form that I want to update with the data (strings) I get back from the ManagementEventWatcher, which will represent the information about the process which has started or stopped. The constructor looks like the following:

public EventWatcher(MainForm targetForm)
  {
   outputForm = targetForm;
   WatchForProcessStart();
   WatchForProcessEnd();
  }

After I set up the form that will be updated, I make two calls to methods I've written:

  • WatchForProcessStart()
  • WatchForProcessEnd()

Let's look closer at the first one. The second one is exactly the same except for a slight change in the WMI query.

public void WatchForProcessStart()
        {
            string queryString =
                "SELECT TargetInstance" +
                "  FROM __InstanceCreationEvent " +
                "WITHIN  .025 " +
                " WHERE TargetInstance ISA 'Win32_Process' "
                + "   AND TargetInstance.Name like '%'";

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

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

To create a new ManagementEventWatcher, you need to supply a scope and a queryString to its constructor.

You can see that the first two statements set up both of those items.

WMI QueryString

The interesting parts of the queryString are the system object we are selecting from (__InstanceCreationEvent) and the TargetInstance system object which we check to insure is a Win32_Process and then check its Name property. Also, from everything I can tell, the Win32_process really "means any running process on your system" and is somewhat of a misnomer and a throwback to the past. This query will result in showing you the x64 processes running too. If you find out differently, please comment back.

WMI Scope

I basically copied the value that the scope object expects for the local computer. There is a way to pass in a ComputerName to replace the dot so that you can run this query against another computer, but that will also require some security set up and is beyond the scope of this tip.

Using the ManagementEventWatcher

Once you have those items set up, you can instantiate your ManagementEventWatcher object and initialize it for your use.

It's as simple as setting the delegate (callback) method that will get called when the system registers the process start (or stop). You set up the event method by simply pointing it at the method you want to run when the event fires.

The set up looks like the following:

startProcWatcher.EventArrived += ProcessStarted;

After setting that up, we simply call the Start() method and the system will begin notifying us when a process starts on the current computer.

The code that runs when the event fires looks like:

private void ProcessStarted(object sender, EventArrivedEventArgs e)
  {
    ManagementBaseObject targetInstance = 
           (ManagementBaseObject)e.NewEvent.Properties["TargetInstance"].Value;
    string processName = targetInstance.Properties["Name"].Value.ToString();
    string exePath = targetInstance.Properties["ExecutablePath"].Value.ToString();
    string action = "BEGAN";
    outputForm.displayDelegate(String.Format("{0}|\t{1}|\t{2}|\t{3}", 
                    DateTime.Now, action, processName, exePath));
 }

As you can see, we just pull some data out, format a string for our output and then call our displayDelegate() method, which is simply a way to call the method in our MainForm which will show the text in our TextBox.

Small Details for Saving File

I wanted to let you start this up and run it and then save off all the data so I made it so that if you righ-click on the TextBox, then you can choose the Save To File menu item so you can save it to a simple text file which you can open with any editor. You can use Excel and do more analysis or just sorting if you like.

Points of Interest

UI: Enable/Disable Buttons and Background color

One last thing. So you can know whether or not the application is currently polling, I set the background to a light yellow and when it is stopped I set it back to white. I also enable disable the buttons so they can only be used at the correct time and to provide UI feedback about what the app is doing.

Process watcher running with start button disabled.

Extra

Just as I was doing my final tests, before publishing this tip, I noticed that if the query was running and you close the application, without first stopping, then the app would throw an exception. I put a fix in for this which looks like the following -- basically stops the listeners if the user closes the application while they are running.

private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
     {
         if (ew != null)
         {
             ew.StopAllWatchers();
             ew = null;
         }
     }

History

  • Second release 2015-12-21 (later in the day): Noticed that the Multi-line textbox did not have a vertical scroll bar, so I added it so you can scroll through a long list of items after allowing the application to run for a long time
  • First release: 2015-12-21

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here