Thursday, June 04, 2009

Design For Operations, Part III - MMC Integration

Back in 2006 I started writing about designing applications with IT department in mind. I'm glad to say that my position didn't change since then - I still believe computer software should be friendly to its end users, which are either customers (mobile, desktop and web apps) or IT engineers (web apps and services). Unfortunately, these two groups are not represented equally in the design process: business analyst is a voice of the customer, but who is a voice of IT?

MMC Background
In my previous posts I covered such aspects as event logging, performance counters, and WMI integration. Today I wanted to discuss Microsoft Management Console (MMC) which was originally developed for Windows NT Option Pack. The idea was to create a common interface for managing IIS, Certificate Server, and Transaction Server, so that administrators have fewer tools to learn. This was further extended in the next release, MMC 2.0 (included with Windows XP/Server 2003), when a concept of the snap-in was added. Snap-in was a COM in-process server that MMC would communicate with, thus allowing any third-party application to have a custom management screen within MMC. In order to develop custom snap-ins, you would need to be well-versed in C++ COM development, as there were 30-something interfaces that could be used. Development of snap-ins in managed code was not supported, although there were custom frameworks, for example, an open-source project called MMC.NET.

MMC 3.0, which was shipped with Vista and Server 2008 (but available for download for older platforms), includes a managed layer and thus natively supports snap-in development in any .NET language. Everyone but hard-core C++ programmers would agree that this can be done faster, with fewer lines of code and simplified maintenance. And even they will have to admit that the ability to use WinForms inside MMC is really cool.

Setting Up Solution
In order to develop our custom MMC snap-in using C# 2008, we will create a class library project. However, before you begin, there is one important step: executing %WINDIR%\System32\MMCPerf.exe from the command prompt. This will put MMC assemblies in the GAC and NGEN them. After creating new project, add a reference to Microsoft.ManagementConsole.dll by browsing to the following folder: \Program Files\Reference Assemblies\Microsoft\mmc\v3.0\. Unfortunately, the assembly doesn't appear in the .NET tab of the "Add Reference" dialog.

Writing Code
We will start by adding two classes to the project: one derived from Microsoft.ManagementConsole.SnapInInstaller, will be used to register custom snap-in with MMC, and another, derived from Microsoft.ManagementConsole.SnapIn, will serve as an entry point.

using System.ComponentModel;
using System.Security.Permissions;
using Microsoft.ManagementConsole;

[assembly: PermissionSetAttribute(SecurityAction.RequestMinimum, Unrestricted = true)]

namespace Microsoft.ManagementConsole.Samples
{
[RunInstaller(true)]
public class InstallUtilSupport : SnapInInstaller
{
}

[SnapInSettings("{9627F1F3-A6D2-4cf8-90A2-10F85A7A4EE7}",
DisplayName = "- Sample SnapIn",
Vendor = "My Company",
Description = "Shows FormView")]
public class SelectionFormViewSnapIn : SnapIn
{
}
}
Note the attribute that decorates SelectionFormViewSnapIn class. All snap-ins are defined in the  Registry, so we have to provide a GUID, and also specify metadata which will be displayed in the catalog. We can leave the body of the installer empty, but SnapIn class requires a constructor.

public SelectionFormViewSnapIn()
{
// Create the root node.
this.RootNode = new ScopeNode();
this.RootNode.DisplayName = "Selection (FormView) Sample";

// Create a form view for the root node.
FormViewDescription fvd = new FormViewDescription();
fvd.DisplayName = "Users (FormView)";
fvd.ViewType = typeof(FormView);
fvd.ControlType = typeof(SelectionControl);

// Attach the view to the root node.
this.RootNode.ViewDescriptions.Add(fvd);
this.RootNode.ViewDescriptions.DefaultIndex = 0;
}
In the constructor, we are effectively defining the root node of the snap-in. In this example, we will be using a WinForms user control called SelectionControl. This is a regular UserControl that implements a special interface Microsoft.ManagementConsole.IFormViewControl, which really only has a single method: void Initialize(FormView view). This is where we would put our initialization logic.

Deployment
After successful build of the solution, we will end up with a single DLL. Deploying it is very straightforward: all you need to do is execute InstallUtil.exe against it. Assuming you didn't skip the first step (running MMCPerf.exe), you should see no errors. Start MMC and choose "Add/Remove Snap-in" from the File menu, then click the "Add" button. You should see your custom snap-in appear in the list.