Harlinn.CIMTool-2013-03-30-01-noexe.zip

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.

Introduction

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:

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:

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:

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:

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:

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.

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.

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

History

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.

Comments and Discussions

This is a very impressive tool and a very good article, well explained and motivated. The whole approach the idea of creation of such tool looks very fruitful and innovating. Everything (or at least a lot) is put together. The tool is very interesting to drill down and investigate the WMI, should be very useful, too. The UI is also quite impressive, with distinct elegant style (maybe looking a bit grim). All the UI elements produce a great impression of completeness and are feature rich. I do understand that it's done thanks to a number of 3rd-party tools, but it's put together nicely.

Unfortunately, some problems spoils the general good impression. After some thinking, I voted 4.

First of all, the build shows 169 warnings. To me, this is a big problem. By letting at least some warnings, you effectively disable the powerful mechanism of warnings at all, because with all those warnings you probably have nothing to do but ignoring them.

Generally, I see a problem with having all the 3rd-party tools in binary form. I think it's important to have all in source, but building all in one step is also important. I'm not 100% sure about the best approach, but I personally keep all 3rd-party codes on source and support them in the Revisions Control System with my code, separated. Probably you could do that, or provide some mechanism for getting all 3rd-party library source codes from original sources quickly, as some build step (which is easy to integrate in MSBuild project files).

I also see some problem in UI part. The use of WPF Property Grid is great, but your style makes it difficult to tell read-only properties from read/write. I found some inconsistency in context menu. Some items are shown but do nothing. This is not how it should work: if nothing is going to happen, the items should be hidden/disabled. In particular, this big tree calls for search facility, which is not seemingly available. There is the menu item "Query" but it probably does nothing. Please tell me if I'm missing something.

One more advice on the build: In my solutions, I always modify output directories of all projects so they would merge all output in one directory (more exactly, in two or more, per configuration), using relative path names like "../../bin.Debug", ../../bin.Release". It helps to avoid all those multiple copies of output files and is what is really needed.

Despite of all these problems, this is a great work, which just need some extra work.

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.

Thank you for answering to those concerns. As to "Query" which does nothing: I can find out first case when it does not work and report it back, but the whole idea is: if the menu item is shown and enabled, it should do something.

Unfortunately, it failed to build from Harlinn.CIMTool-2013-02-25-01-noexe.zip:

"Error 181 The tag 'TextEditor' does not exist in XML namespace 'clr-namespace:ICSharpCode.AvalonEdit;assembly=ICSharpCode.AvalonEdit'. Line 10 Position 10.";
"Error 182 The type reference cannot find a public type named 'VertexControl'. Line 15 Position 63.";
"Error 183 The tag 'DockingManager' does not exist in XML namespace 'http://avalondock.codeplex.com'. Line 44 Position 10.".

Harlinn.CIMTool-2013-02-25-01-noexe.zip is a CodeProject generated file, it contains the source code, but none if the libraries - which are stripped away by CP. It's useful when you already have the required packages installed on your machine, or want to download them yourself.

You should have no problems if you download 'Harlinn.CIMTool-2013-02-25-01.zip', which contains the required assemblies.

I was actually not fishing for an up-vote, just wanted to let you know . In the General Discussion forums (like The Lounge), they have disabled down-voting. These votes are actually tricky to do on touch devices (at least on my phone), because the whole mouse hover thing requires you to think in alternative ways.

Anyway, let's move along. I don't want this thread to take the focus away from Espen's excellent article.

Soren Madsen

"When you don't know what you're doing it's best to do it quickly" - Jase #DuckDynasty

In my free time, I've been writing my own WMI browser, so I have an idea where you're coming from. If you don't get much feedback, I can only assume it's because most people aren't all that familiar with WMI, and are simply not aware just how much good information it contains.

One thing I've never really dug into is showing class relationships (hierarchies, inheritance, etc), the extended system properties, these sort of things. I've hardly touched my app in the last 18 months, but seeing this makes me want to get back into it. At least now I'd have something to compare with--CIM Studio is anything but user-friendly.