Click here to Skip to main content
14,116,173 members
Click here to Skip to main content
Add your own
alternative version


24 bookmarked
Posted 21 Feb 2013
Licenced CPOL

CIMTool for Windows Management Instrumentation - Part 3

, 30 Mar 2013
Rate this:
Please Sign up or sign in to vote.
A first take on code generation for WMI, and a bit of magic for the WPF DataGrid

Build instructions

This file includes the required assemblies, so building from the source should be as easy as opening the project in Visual Studio 2012 and hitting F5.

This file requires that you have the following installed on your computer:

Graph#, AvalonEdit and AvalonDock are available through the nuget package manager, so you may install them using nuget, while the source for the WPF Property Grid is included with the download.


The Common Information Model (CIM) Metamodel, is based on the Unified Modeling Language: Superstructure specification[^]. CIM schemas represent object-oriented models that can be used to represent the resources of a managed system, including their attributes, behaviors, and relationships. The CIM Metamodel includes expressions for common elements that must be clearly presented to management applications.

The CIM Schema published by DMTF[^] is an example of a particular schema that conforms to the CIM Metamodel. The model abstracts and describes a "managed environment" using an object oriented paradigm. The CIM object schema addresses systems, devices, application deployment and the physical environment. Windows Management Instrumentation (WMI) is an implementation, with a supporting infrastructure, of the Common Information Model.

CIMTool was created to provide an effective tool for understanding and browsing the information available through the Windows Management Instrumentation API.

So far CIMTool has turned out to be a useful utility, but there are still essential features that are missing, first among them a decent code generator. While .Net ships with the mgmtclassgen tool, the generated output doesn’t reflect the object oriented nature of CIM and Windows Management Instrumentation.

This is the third article about CIMTool, an alternative to Microsoft’s WMI CIM Studio:

WMI provides a rich set of meta-data that describes the available classes, and how they are related to each other by inheritance, containment and reference. As a developer you would naturally expect that a code generator would reflect this in it’s output, but surprisingly it turns out that the mgmtclassgen tool flattens the inheritance tree, and merges everything into a single class. This is perhaps fine if a single class is all you’re going to work with, but once you start working with several classes, the overhead becomes tremendous.

Take Win32_BaseService which has two descendants: Win32_Service and Win32_SystemDriver. When you use the classes generated by mgmtclassgen you will not be able to something like this:

void HandleBaseService(Win32_BaseService theBaseService)
  if(theBaseService is Win32_Service)
    Win32_Service theService = (Win32_Service)theBaseService;

This is because the classes generated by mgmtclassgen are not related to each other; they are each derived directly from System.ComponentModel.Component.

Below you have the class browser for CIMTool and WMI CIM Studio side by side:


While WMI CIM Studio can, obviously, be used to learn a lot about WMI; using it gets tedious when you don’t know the inheritance hierarchy of a class, such as Win32_Service, and it’s impossible to view meta-data and object data at the same time – which is why CIMTool was born.

Win32_BaseService has a property called AcceptPause:

By looking at the properties for the property definition we learn that AcceptPause is a boolean property, and that it's neither an array nor a key. I could admittedly have learned that from the Win32_BaseService documentation[^], but then I'd have to trust the documentation - which isn't allways accurate.

Take the ServiceType property of the Win32_BaseService; according to the documentation it's an unsigned byte, but that turns out to be wrong, it's a string:

This property also have a ValueMap, but no Values - which is mildly surprising, and not what I would have expected after reading the documentation[^].

So, if you want to write a code generator for WMI, you need to be prepared to handle a few surprises.

The CodeDom

The CodeDOM is an integral part of the .Net framework where it’s used to represent source code documents in a language-independent manner. The CodeDOM is an object graphs that can be used to generate source code and compiled assemblies. The System.CodeDom namespaces contains nearly 90 classes and enums that are supposed to represent the syntax of a typical programming language such as C# and Visual Basic.

Since the code generator inside mgmtclassgen was built using the capabilities of the classes in the System.CodeDom namespace, I thought it would be practical to implement the code generation for CIMTool using the CodeDom.

So, to generate the code required for a property with a setter and a getter:

public int SslFlags
    return this.GetInt32("SslFlags");
    this.Write("SslFlags", value);

You have to write something like this:

CodeMemberProperty property = new CodeMemberProperty();
property.Name = Name;
property.Type = new CodeTypeReference(GetPropertyType());
property.Attributes = MemberAttributes.Public | MemberAttributes.Final;

if (PropertyData.Read)
    property.GetStatements.Add(new CodeMethodReturnStatement(
        new CodeMethodInvokeExpression(
        new CodeMethodReferenceExpression(
            new CodeThisReferenceExpression(), GetGetterFunctionName()),
                new CodePrimitiveExpression(Key))));


if (PropertyData.Write)
        new CodeMethodInvokeExpression(
        new CodeMethodReferenceExpression(
            new CodeThisReferenceExpression(), GetSetterFunctionName()),
                new CodePrimitiveExpression(Key), new CodeVariableReferenceExpression("value")));

Which, if nothing else, clearly illustrates the value of the services provided by the C# compiler.

I think Ray Gilbert got it right in his article CodeDom Assistant[^] - It's like cutting the grass with a pair of scissors or unloading a truck load of sand with a spoon. It's long winded, it can be done, but it is tedious.

Before we can generate any code we need to have some idea about the structure of the elements we want to generate code for:

When you select generate code from the popup menu:

We end up executing the GenerateCodeMenuItem_Click method:

private void GenerateCodeMenuItem_Click(object sender, RoutedEventArgs e)
    ManagementScopeWrapper theManagementScope = null;
    if (Data.SelectedItem is ClassNode)
        ClassNode classNode = (ClassNode)Data.SelectedItem;
        theManagementScope = classNode.Parent.ManagementScope;
    else if (Data.SelectedItem is ClassesNode)
        ClassesNode classesNode = (ClassesNode)Data.SelectedItem;
        theManagementScope = classesNode.ManagementScope;
    else if (Data.SelectedItem is NamespaceNode)
        NamespaceNode namespaceNode = (NamespaceNode)Data.SelectedItem;
        theManagementScope = namespaceNode.ManagementScope;

The first thing that happens is that the program locates the WMI namespace, which is also called a management scope.

if (theManagementScope != null)

    GeneratorOptions generatorOptions = new GeneratorOptions();
    generatorOptions.RootManagementNamespace = "Harlinn.CIMTool.Generated.Mgmt";
    generatorOptions.ManagementNamespace = theManagementScope.Name;
    generatorOptions.ManagementPrefix = "IIs";
    generatorOptions.RootSerializationNamespace = "Harlinn.CIMTool.Generated.Mgmt." +
    generatorOptions.SerializationNamespace = "Types";
    generatorOptions.SerializationPrefix = "IIsS";

If the program is able to locate a scope, it will use that inforamtion to populate a GeneratorOptions object with a set of default values

GeneratorOptionsWindow generatorOptionsWindow = new GeneratorOptionsWindow();
generatorOptionsWindow.DataContext = generatorOptions;

bool? result = generatorOptionsWindow.ShowDialog();

These options are then passed to a GeneratorOptionsWindow window, which allows you to alter the default to something more appropriate for your project.

if (true == result)

    CodeProvider codeProvider = new CodeProvider(CodeLanguage.CSharp, generatorOptions);
    using (codeProvider)

        Namespace nameSpace = new Namespace(codeProvider, theManagementScope);

Namespace represents the management scope containing the WMI classes we're going to generate C# code for.


The GenerateManagementCode() method populates the CodeDom, and once we have a populated CodeDom we're ready to generate the code.

System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
using (memoryStream)
    System.IO.TextWriter textWriter = new System.IO.StreamWriter(memoryStream);
    using (textWriter)
        System.CodeDom.Compiler.CodeGeneratorOptions codeGeneratorOptions =
                           new System.CodeDom.Compiler.CodeGeneratorOptions();
        codeGeneratorOptions.BracingStyle = "C";
                      textWriter, codeGeneratorOptions);
GenerateCodeFromNamespace writes the C# code to the TextWriter, and all that's left is to load it into the editor:
                        LayoutDocument layoutDocument = new LayoutDocument();
                        layoutDocument.Title = "Scope: " + theManagementScope.Name;
                        EditorControl editorControl = new EditorControl();
                        memoryStream.Seek(0, System.IO.SeekOrigin.Begin);
                        editorControl.VerticalAlignment = 
                        editorControl.HorizontalAlignment = 

                        layoutDocument.Content = editorControl;


Apart from giving birds view of the procedure behind the code generation in CIMTool, the above code shows a simple and efficient way to dynamically add a WPF UserControl as a ‘document’ in AvalonDock.

How to create DataGrid columns dynamically

Speaking of UserControl’s, let’s have a look at the QueryControl.xaml file:

<UserControl x:Class="Harlinn.CIMTool.Wpf.Controls.QueryControl"






             d:DesignHeight="300" d:DesignWidth="500">
    <Grid >
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        <Grid Grid.Row="0">
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            <Grid HorizontalAlignment="Stretch">
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="Auto"/>
                <TextBlock Grid.Column="0" Margin="5" >Scope</TextBlock>
                <TextBox Grid.Column="1" Margin="5" 

                         Text="{Binding Mode=OneWay, Path=Scope.Name}"></TextBox>
                <Button Grid.Column="2" 




            <TextBox Grid.Row="1" 

                     FontFamily="Lucida Console" 



                     Text="{Binding Path=QueryString}" />
        <GridSplitter Grid.Row="0" 

                      ResizeDirection="Rows" Height="4" 


        <Grid Grid.Row="1">
            <DataGrid x:Name="dataGrid"></DataGrid>

What I want you to note is the declaration of the DataGrid, no column definitions, and no bindings – and we definitely want to display some data:

What if I could show you how to populate the DataGrid using one, just one, line of code? Using a mechanism that has been a part of Windows Presentation Foundation since its initial release? Well, here goes:

dataGrid.ItemsSource = new BindingListCollectionView(objectCollection);

BindingListCollectionView is the gem that perhaps got lost. Personally I think the designers of WPF intended us to use classes implementing the System.ComponentModel.ICollectionView as the primary data source for collections - not ObservableCollection, at least not directly. Apparently many developers have skipped reading up on this and the other classes found in the System.Windows.Data namespace. I say apparently because a quick google for BindingListCollectionView gave me 7700 hits, while a search for ObservableCollection gave me 335000 hits.

The documentation for CollectionView says:

In WPF applications, all collections have an associated default collection view. Rather than working with the collection directly, the binding engine always accesses the collection through the associated view. To get the default view, use the CollectionViewSource.GetDefaultView method. CollectionView is the default view for collections that implement only IEnumerable. ListCollectionView is the default view for collections that implement IList. BindingListCollectionView is the default view for collections that implement IBindingListView or IBindingList.

What's missing here is that BindingListCollectionView also provides additional handling for classes that implement the ITypedList[^] interface. As far as I've been able to determine BindingListCollectionView provides full support for the standard mechanisms that facilitates rappid application development in Windows Forms applications, including ICustomTypeDescriptor[^]. This turns BindingListCollectionView into an extremely powerful and flexible class.

About the generated code

The code generated for a given WMI class, will typically look something like this:

public class IIsHandlersSection : IIsConfigurationSectionWithCollection

Since the WMI class HandlersSection is derived from a WMI class called ConfigurationSectionWithCollection, the code generator generates code that reflects this.

The code generator creates a class factory for the classes in a WMI namespace, in this case IIsWebAdministrationClassFactory class. This design ensures that an object of the correct class is created for a given instance of a WMI class, even when creating objects for a collection of potential base classes.

public BindingListEx<IIsHandlerAction> Handlers
        System.Management.ManagementObject[] managementObjects = GetObjects("Handlers");
        BindingListEx<IIsHandlerAction> elements = new BindingListEx<IIsHandlerAction>();
        foreach (System.Management.ManagementObject managementObject in managementObjects)
            IIsHandlerAction element = (IIsHandlerAction)
                 IIsWebAdministrationClassFactory.CreateObject(managementObject, false);
        return elements;

The constructor takes an instance of an existing System.Management.ManagementObject object, and an optional boolean value which is used to specify that when Dispose is called on the object, it should dispose the System.Management.ManagementObject object.

public IIsHandlersSection(ManagementObject theManagementObject) :

public IIsHandlersSection(ManagementObject theManagementObject, bool disposeManagementObject) :
    base(theManagementObject, disposeManagementObject)

Access to the properties of the WMI object is done in the usual manner:

    public System.Nullable<int> AccessPolicy
            return this.GetNullableInt32("AccessPolicy");
            this.WriteNullable("AccessPolicy", value);

When possible, the code genrator creates enums integer properties with Values and ValueMap qualifiers:

public enum IIsSCIMErrorPerceivedSeverityValues
    Unknown = 0,
    Other = 1,
    Information = 2,
    DegradedOrWarning = 3,
    Minor = 4,
    Major = 5,
    Critical = 6,
    FatalOrNonRecoverable = 7,

When generating code for the WebAdministration namespace the generator creates a file containing 23457 lines of C# code - so COMTool can potentially do a lot of work for you.

There is still a lot of work to be done, but I think that CIMTool is moving in the right direction.

D3.js crash course - Part2[^] shows one way to use the generated code.

By the way, a bit of positive feedback would certainly be both motivating and appreciated, there is no need to be shy about it


  • 21. of February, 2013 - Initial posting.

  • 22. of February, 2013 - User interface Improvements.

    Improved view of class properties:

    Improved view of property properties:


  • 23. of February, 2013 - A few bugfixes - I've mostly tested the code generator against the WebAdministration namespace, and several bugs surfaced when I tried generating code for the CIMV2 namespace. The code generated for the the CIMV2 namespace will now compile.

  • 25. of February, 2013 - Added namespace visualization

  • 2. of March, 2013 - improved property name generation, added generation of serializable objects representing data retrieved from WMI.

  • 14. of March, 2013 - Changed the color for property names in the property grid to white, as this is much more readable.

  • 14. of March, 2013 - Enabling and disabling items on the context menu depending on the node type.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Espen Harlinn
Architect Powel AS
Norway Norway
Chief Architect - Powel AS.

Specializing in integrated operations and high performance computing solutions.

I’ve been fooling around with computers since the early eighties, I’ve even done work on CP/M and MP/M.

Wrote my first “real” program on a BBC micro model B based on a series in a magazine at that time. It was fun and I got hooked on this thing called programming ...

A few Highlights:

  • High performance application server development
  • Model Driven Architecture and Code generators
  • Real-Time Distributed Solutions
  • C, C++, C#, Java, TSQL, PL/SQL, Delphi, ActionScript, Perl, Rexx
  • Microsoft SQL Server, Oracle RDBMS, IBM DB2, PostGreSQL
  • AMQP, Apache qpid, RabbitMQ, Microsoft Message Queuing, IBM WebSphereMQ, Oracle TuxidoMQ
  • Oracle WebLogic, IBM WebSphere
  • Corba, COM, DCE, WCF
  • AspenTech InfoPlus.21(IP21), OsiSoft PI

More information about what I do for a living can be found at: or LinkedIn

You can contact me at

You may also be interested in...

Comments and Discussions

QuestionVoted 4, with short review Pin
Sergey Alexandrovich Kryukov29-Mar-13 8:27
memberSergey Alexandrovich Kryukov29-Mar-13 8:27 
AnswerRe: Voted 4, with short review Pin
Espen Harlinn29-Mar-13 13:44
mentorEspen Harlinn29-Mar-13 13:44 
Sergey Alexandrovich Kryukov wrote:
First of all, the build shows 169 warnings

As far as I know they are all related to the WPF Property grid[^] - so they only show up when you do your first build. I included the source code for this project because it's not easily accissible using NuGet.

Sergey Alexandrovich Kryukov wrote:

Generally, I see a problem with having all the 3rd-party tools in binary form.

I provided links to the open source projects, and this way you can get the source code and use nuget to install the latest version into the project. This seems to be what most people expect as nuget is gaining in popularity.

Sergey Alexandrovich Kryukov wrote:
There is the menu item "Query" but it probably does nothing.

Select a class in the treeview and then execute query - it should open a query window with a select statement for that class.

Sergey Alexandrovich Kryukov wrote:
Thank you very much for sharing.

Thanks for the review Big Grin | :-D
Espen Harlinn
Principal Architect, Software - Goodtech Projects & Services AS

Projects promoting programming in "natural language" are intrinsically doomed to fail. Edsger W.Dijkstra

GeneralRe: Voted 4, with short review Pin
Sergey Alexandrovich Kryukov29-Mar-13 14:20
memberSergey Alexandrovich Kryukov29-Mar-13 14:20 
GeneralRe: Voted 4, with short review Pin
Espen Harlinn30-Mar-13 2:37
mentorEspen Harlinn30-Mar-13 2:37 
GeneralRe: Voted 4, with short review Pin
Sergey Alexandrovich Kryukov30-Mar-13 15:12
memberSergey Alexandrovich Kryukov30-Mar-13 15:12 
QuestionFailed to build Pin
Sergey Alexandrovich Kryukov26-Feb-13 16:37
memberSergey Alexandrovich Kryukov26-Feb-13 16:37 
AnswerRe: Failed to build Pin
Espen Harlinn26-Feb-13 23:23
mentorEspen Harlinn26-Feb-13 23:23 
GeneralRe: Failed to build Pin
Sergey Alexandrovich Kryukov27-Feb-13 4:53
memberSergey Alexandrovich Kryukov27-Feb-13 4:53 
GeneralRe: Failed to build Pin
Espen Harlinn27-Feb-13 5:14
mentorEspen Harlinn27-Feb-13 5:14 
GeneralRe: Failed to build Pin
Sergey Alexandrovich Kryukov27-Feb-13 5:20
memberSergey Alexandrovich Kryukov27-Feb-13 5:20 
GeneralRe: Failed to build Pin
Espen Harlinn27-Feb-13 8:38
mentorEspen Harlinn27-Feb-13 8:38 
AnswerRe: Failed to build Pin
Espen Harlinn12-Mar-13 12:38
mentorEspen Harlinn12-Mar-13 12:38 
GeneralRe: Failed to build Pin
Sergey Alexandrovich Kryukov12-Mar-13 12:40
memberSergey Alexandrovich Kryukov12-Mar-13 12:40 
GeneralRe: Failed to build Pin
SoMad15-Mar-13 20:04
protectorSoMad15-Mar-13 20:04 
GeneralRe: Failed to build Pin
Sergey Alexandrovich Kryukov15-Mar-13 20:13
memberSergey Alexandrovich Kryukov15-Mar-13 20:13 
GeneralRe: Failed to build Pin
SoMad15-Mar-13 20:25
protectorSoMad15-Mar-13 20:25 
GeneralRe: Failed to build Pin
Sergey Alexandrovich Kryukov15-Mar-13 20:36
memberSergey Alexandrovich Kryukov15-Mar-13 20:36 
GeneralMy vote of 5 Pin
Kanasz Robert24-Feb-13 21:29
memberKanasz Robert24-Feb-13 21:29 
GeneralRe: My vote of 5 Pin
Espen Harlinn25-Feb-13 1:34
mentorEspen Harlinn25-Feb-13 1:34 
GeneralMy vote of 5 Pin
dandy7222-Feb-13 8:06
memberdandy7222-Feb-13 8:06 
GeneralRe: My vote of 5 Pin
Espen Harlinn22-Feb-13 13:43
mentorEspen Harlinn22-Feb-13 13:43 
GeneralRe: My vote of 5 Pin
dandy7222-Feb-13 17:14
memberdandy7222-Feb-13 17:14 
GeneralRe: My vote of 5 Pin
Espen Harlinn23-Feb-13 1:15
mentorEspen Harlinn23-Feb-13 1:15 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web05 | 2.8.190518.1 | Last Updated 30 Mar 2013
Article Copyright 2013 by Espen Harlinn
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid