views:

365

answers:

3

I have some services that an application needs running in order for some of the app's features to work. I would like to enable the option to only start the external Windows services to initialize after the application is launched. (as opposed to having them start automatically with the machine and take up memory when the application is not needed)

I do not have access to the exe's code to implement this, so ideally I would like to write a C# .Net Windows service that would monitor when an exe is launched.

What I've found so far is the System.IO.FileSystemEventHandler. This component only handles changed, created, deleted, and renamed event types. I don't expect that a file system component would be the ideal place to find what I'm looking for, but don't know where else to go.

Maybe I'm not searching with the right keywords, but I have not yet found anything extremely helpful on Google or here on stackoverflow.com.

The solution would be required to run on XP, Vista, and Win 7 when it comes...

Thanks in advance for any pointers.

+3  A: 

you have 3 options here:

The reliable/intrusive one, set up a hook in unmanaged code that communicates back to your C# app whenever an app is launched. This is hard to get right and involves loading an extra DLL with each process. (Alternatively you could set up a driver, which is even harder to write)

The less reliable way, list all the processes (using the System.Diagnostics.Process class) on a regular basis (say every 10-30 secs) to see if the app is launched.

It also may be possible to watch the Win32_Process, InstanceCreationEvent WMI event from managed code. Not sure how reliable this is, but I suspect it would be better than polling processes.

Sam Saffron
+5  A: 

From this article, you can use WMI (the System.Management namespace) in your service to watch for process start events.

 void WaitForProcess()
{
    ManagementEventWatcher startWatch = new ManagementEventWatcher(
      new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace"));
    startWatch.EventArrived
                        += new EventArrivedEventHandler(startWatch_EventArrived);
    startWatch.Start();

    ManagementEventWatcher stopWatch = new ManagementEventWatcher(
      new WqlEventQuery("SELECT * FROM Win32_ProcessStopTrace"));
    stopWatch.EventArrived
                        += new EventArrivedEventHandler(stopWatch_EventArrived);
    stopWatch.Start();
}

  static void stopWatch_EventArrived(object sender, EventArrivedEventArgs e) {
    stopWatch.Stop();
    Console.WriteLine("Process stopped: {0}"
                      , e.NewEvent.Properties["ProcessName"].Value);
  }

  static void startWatch_EventArrived(object sender, EventArrivedEventArgs e) {
    startWatch.Stop();
    Console.WriteLine("Process started: {0}"
                      , e.NewEvent.Properties["ProcessName"].Value);
  }
}

WMI allows for fairly sophisticated queries; you can modify the queries here to trigger your event handler only when your watched app launches, or on other criteria. Here's a quick introduction, from a C# perspective.

Michael Petrotta
Excellent answer. solved my problem.
Stimul8d
Excellent, very useful. Cheers!
tjjjohnson
Having some trouble executing this code on windows 7. I get an "access denied" error when calling startWatch.Start(). Has anyone found a workaroun for that?
tjjjohnson
@ tjjjohnson: Without looking into it, I suspect Windows 7 requires that watch to be run from an elevated process. Try using "Run as Administrator".
Michael Petrotta
A: 

Monitor if the process is running - one service must be running to do this though.

If you really don't want to consume any ressources - write a simple service in plain C. Service application written without MFC/ATL can consume as low as 300-400 kb memory and virutally no CPU cycles. When the process you are interested in starts you can spawn your C# services.

devdimi