Getting notified by a Windows Service status change in C# .NET
December 2, 2014 3 Comments
The ManagementEventWatcher object in the System.Management namespace makes it possible to subscribe to events within the WMI – Windows Management Instrumentation – context. A change in the status of a Windows service is such an event and it’s possible to get notified when that happens.
We saw examples of WMI queries on this blog before – check the link below – and the ManagementEventWatcher object also requires an SQL-like query string. Consider the following function:
private static void RunManagementEventWatcherForWindowsServices() { EventQuery eventQuery = new EventQuery(); eventQuery.QueryString = "SELECT * FROM __InstanceModificationEvent within 2 WHERE targetinstance isa 'Win32_Service'"; ManagementEventWatcher demoWatcher = new ManagementEventWatcher(eventQuery); demoWatcher.Options.Timeout = new TimeSpan(1, 0, 0); Console.WriteLine("Perform the appropriate change in a Windows service according to your query"); ManagementBaseObject nextEvent = demoWatcher.WaitForNextEvent(); ManagementBaseObject targetInstance = ((ManagementBaseObject)nextEvent["targetinstance"]); PropertyDataCollection props = targetInstance.Properties; foreach (PropertyData prop in props) { Console.WriteLine("Property name: {0}, property value: {1}", prop.Name, prop.Value); } demoWatcher.Stop(); }
We declare the query within an EventQuery object. Windows services are of type “Win32_Service” hence the “where targetinstance isa ‘Win32_Service'” clause. “within 2” means that we want to be notified 2 seconds after the status change has been detected. A change event is represented by the __InstanceModificationEvent class. There are many similar WMI system classes. A creation event corresponds to the __InstanceCreationEvent class. So the query is simply saying that we want to know of any status change in any Windows service 2 seconds after the change.
The timeout option means that the ManagementEventWatcher object will wait for the specified amount of time for the event to occur. After this a timeout exception will be thrown so you’ll need to handle that.
In order to read the properties of the Windows service we need to go a level down to “targetinstance” and read the properties of that ManagementBaseObject. Otherwise the “nextEvent” object properties are not too informative.
Run this code, open the Windows services window and stop or pause any Windows service. I stopped the Tomcat7 service running on my PC and got the following Console output:
You can of course refine your query using the property names of the target instance. You can always check the property names on MSDN. E.g. if you open the above link to the Win32_Service object then you’ll see that it has a “state” and a “name” property. So in case you’ll want to know that a service name “Tomcat7” was stopped then you can have the following query:
eventQuery.QueryString = "SELECT * FROM __InstanceModificationEvent within 2 WHERE targetinstance isa 'Win32_Service' and targetinstance.state = 'Stopped' and targetinstance.name = 'Tomcat7'";
In this case starting Tomcat7 won’t trigger the watcher. Neither will stopping any other Windows service. The event watcher will only react if a service names “Tomcat7” was stopped, i.e. the “Status” property of the target instance was set to “Stopped”.
You can view all posts related to Diagnostics here.
Koszi Andras, pont erre volt szuksegem!
Igazán nincs mit!
I wrote an application that just polls the status of the services I want to detect using a timer and then updating GUI elements accordingly when something changes (winforms). I thought … there HAS to be a better way! I really just wanted to just subscribe to a system-level event that gets raised when a service changes state (status). SO, I tried using WMI in the fashion described here and in other blogs/posts relating to WMI. When I implemented this methodology, It worked exactly as expect and my application was reporting service state changes just as it was before without the use of timer and my own polling code; So, job well done right? NOOOO, I saw that my application was using WAY more resources in terms of clock cycles AND memory and ‘services.exe’ was hogging up resources like crazy. I ended up abandoning the whole idea of using WMI for this purpose and went back to using the timer and just polling the state of the services I was interested in. I still don’t like it, but I have yet to find a better way and WMI just didn’t work out well for what I’m doing.