f there were an election for the most underrated .NET framework technology, I’d vote for WMI. ADO.NET and Web services seem to get all the marketing attention, and technical publications can’t get enough Reflection. But WMI exposes an entire universe of system information, and here?s the best part: it?s not even a .NET technology.
What’s WMI Again?
WMI (Windows Management Instrumentation) is Microsoft’s implementation of the Web-based Enterprise Management (WBEM) initiative, an industry-wide standard for programmatically querying and manipulating all kinds of system functionality. Using WMI through .NET, you can programmatically shut down a server, or examine its hardware, or iterate through its running processes.
But one of the best things about WMI is the event model. You can register to be notified of just about anything happening on your local machine, or even a remote one: changes to registry keys, disk activity, and?the focus of this article?processor utilization.
|Figure 1. The SlowTextBox: This image shows the SlowTextBox in the process of initialization.
The Sample Project: Introducing WIC
To show you how to subscribe to WMI events through .NET, this sample project (WMIEvents.zip) kicks off a time-consuming operation on a new thread. Pretty standard stuff, really, but the difference here is that the operation starts only if there’s enough spare processing power to make it worthwhile. It’s a lot like spinning off a low-priority thread for background processing, but this approach gives the programmer far more control over the circumstances.
To simulate a time-consuming task, I built a class called SlowTextBox. Just like it sounds, the control inherits from System.Windows.Forms.TextBox, but this particular implementation has to be initialized for a fixed period of time prior to use. The idea is to simulate some kind of long operation?like getting lots data from a database or talking to a Web service. Once the SlowTextBox is initialized, it works just like a standard TextBox.
Listing 1 shows the complete code for the SlowTextBox.
The project contains three tabs, each with its own instance of SlowTextBox, and each with its own initialization philosophy. The first two approaches should look familiar. The “Na?ve” tab just initializes on startup. In this case, “na?ve” just means the simplest possible approach of initializing at application startup; it doesn’t imply any kind of value judgment. The next tab is called JIT?for “Just In Time.” This approach puts off initialization until the user actually clicks the tab.
Not until the final tab do you need WMI. The idea here is that many applications?GUI applications, especially?spend most of their time just waiting for user input, so why not use that time for background processing? That way, the application looks faster to the user. I call the approach “When It’s Convenient,” or WIC. The following table outlines the thee approaches.
Table 1 The three approaches to initialization.
Initializes on application startup.
Critical or very fast operations.
Initializes when the resource is actually needed.
Non-critical and potentially time-consuming operations.
Initializes when the system load gets low.
Non-critical operations that can run on a separate thread.
|Figure 2. New Items: After installing the WMI extensions for Visual Studio, you’ll notice new items in the server explorer.
Writing the Query
Implementing WIC means subscribing to a WMI event. The first step is to learn some WMI Query Language (WQL) a syntax based on Structured Query Language (SQL). First, I’ll show you how to write a query by hand, and then clue you in to an easier method.
Here’s the simple WQL event query used in the sample project:
string queryString = @"SELECT * FROM __InstanceOperationEventWITHIN 1WHERE TargetInstance ISA 'Win32_Processor'AND TargetInstance.LoadPercentage > 15";
The English-language translation goes like this: “Check the Win32_Processor LoadPercentage every second, and let me know when it falls below 15%.” The following table summarizes the WQL used above.
Table 2: Introduction to WQL.
Spells out the information you want back from your event.? Just like standard SQL, the * is a wildcard meaning ?give me everything you have.?
Specifies the type of event to listen for?creation, modification, or deletion.__InstanceOperationEvent is the most general, firing when any one of the three events occurs.
Defines the polling interval, in seconds.? As always, there?s a tradeoff: you can improve performance with a longer interval, but the event will fire less frequently.
Identifies both the statistics to query, and the criteria to look for.
|Figure 3. Subscribing to WMI Events: You can subscribe to WMI events through Visual Studio, but watch out: they steal focus from the code window.
All of this should seem a little cryptic. Where did that ‘Win32_Processor’ come from? How can you find out what properties it exposes? Of course it’s all documented by the platform SDK here, but there’s another way that’s easier than pouring through the documentation.
Over a year ago, to little fanfare, Microsoft released a set of extensions for working with WMI in Visual Studio’s Server Explorer. The extensions, available here, make it easier to build queries and to explore the WMI classes. Once the tools are installed, you should see two additional nodes on your Server Explorer: Management Events and Management Classes.
|Figure 4. The Query Builder: Use the query builder to explore the vast WMI universe.
The WMI Extensions are pretty nice for a couple of reasons. First, you can register for notifications within the VisualStudio application. It’s great for diagnostic purposes, and to get an idea of how often the event fires without stepping into the debugger.
Even better, the WMI Extensions can function as a WQL query builder. Using these tools, you can choose your events and criteria visually, and then paste the text into your code when you?re satisfied. To build the same query the easy way, follow these steps:
- Right click the “Management Events” node, and choose “Add Event Query.”
- Open Root CIMV2, and locate the “Processors” node.
- Choose a polling interval.
- Click on the “Advanced” button. Here you can specify criteria for your where clause, and you can see the query that’s being written for you. It should be exactly the same as the query above.
Putting It All Together
Whether you piece it together by hand, or cheat with the WMI tools, writing the WQL query is 90 percent of the work involved with subscribing to an event. To use your query, just construct an instance of the ManagementEventWatcher class with the query text as an argument. Finally, subscribe to the event called EventArrived, like this:
idleWatcher = new ManagementEventWatcher(queryString);idleWatcher.EventArrived += new EventArrivedEventHandler(OnIdle);idleWatcher.Start();
The instances of ManagementEventWatcher are often called “temporary event consumers” because they last for (at most) the lifetime of the application. For a more permanent notification, you can set up an alert through the Windows Performance Monitor (perfmon.exe). Listing 2 shows the complete code for the ProcessorIdleWatcher.
Wrapping It Up
Next year’s release of Visual Studio 2005 will include so many changes that I’m hesitant about investing too much time learning unfamiliar areas of .NET 1.1. The good news is that time spent learning WMI won’t be wasted because the technology is standardized, widely used, and independent of its .NET implementation. The wrapper classes may change, but WMI isn’t going away.
Of course, WMI has much a much broader set of applications than just background processing. You can listen for new USB devices or runaway processes. But whatever events your application needs to know about, the subscription process is exactly the same.