Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Developing MMC Snap-ins

0.00/5 (No votes)
16 Jul 2002 1  
Developing an MMC administrative utility

Introduction

Microsoft first introduced MMC Version 1.0 with WinNT 4.0 Option Pack for WinNT Server. They followed that with MMC 1.1 that came with SQL7 and MMC 1.2 which came with Win2K. The ATL Object Wizard of Visual C6 provided a control that would allow you to build MMC tools. However, for some reason, this utility got lost along the path and so, when Microsoft introduced its latest version of MMC, users were advised not to use the ATL wizard anymore.

So, what should you do? Well, Microsoft provides a very comprehensive package as part of its November of 2001 SDK update which gives you sufficient details to get started developing an MMC snap-in. Nonetheless, programming an MMC snap-in is quite a handful, as there are no wizards helping you out with any part of it. So, in this article, I will give you a few hints that I learned while dealing with the beast. I should mention that this article is just a starter, as for whatever reason MS has made a science out of MMCs and Snap-ins.

Basic Terminology

MMC

 the client that you start by running mmc.exe

Snap-ins

 the server that you load by using ADD\Remove snap-in.

Scope Pane

 This is the left hand side pane.

Results Pane

 This is the right hand side pane.

Console Tree

 This is the left hand side tree that is used to navigate.

Nodes

 Nodes represent individual items on the left hand side.

In this demo, I have included the code for a basic MMC that connects to a SQL Server database and shows the result on the right hand side. I have also added context menu functionality on the right hand side. This demo is built on the basis of some of the code that Microsoft has provided in their SDK.

Setup:

  1. Make sure you install Microsoft November 2001 SDK on your machine. Once you have done that, make sure you add the SDK's "include" folder and the "lib" folder under "Tools" --> "Options" --> "Directories".
  2. In order to build this project or any MMC related projects, you have to link to "mmc.lib" and also "comctl32.lib". Also, inlcude "mmc.h" in your project.
  3. To debug, make sure the executable for debug sessions is set to MMC.exe. Also, remember that we are not using MFC.

The MS files:

An MMC Snap-in is a COM in-process server. When you run mmc.exe, what you get is the mmc client. When you add a snap-in, you are working with the server DLL.

By definition, a COM in-process server is a DLL that houses COM-based components. It executes in the context of the calling process.

General Overview of Snapins

To be classified as a snap-in, the COM server DLL must implement the following three MMC specific interfaces:

  1. IComponentData
  2. IComponent
  3. ISnapinAbout

In addition, the snap-in must implement the following COM specific interfaces and functions:

  1. IClassFactory
  2. IDataObject
  3. DLLRegisterServer
  4. DLLUnregisterServer
  5. DLLGetClassObject
  6. DLLCanUnloadNow

Once the snap-in is registered, you should see the following entries in the registry:

  1. One entry in HKEY_CLASSES_ROOT_CLSID
  2. One entry under HKEY_LOCAL_MACHINE\Software\Microsoft\MMC\Snapins

You should also see the snap-in in the list of snap-ins when you start MMC and select to "Add/Remove Snapin..".

General Decription

The starting point of the application is in BaseSnap.cpp. The entry-point into the in-process servers is always the "DllGetClassObject". This entry point is used so that client programs can obtain their class factory interfaces. In this case, it takes three parameters, a REFCLSID which is the reference to the CLSID of the specific component, a REFIID which is a reference to an IID for the spceific interface to be returned from the created COM Object and a void pointer which will point to the requested interface.

When you try to load the snap-in, MMC starts out as any COM client would, by calling the CoCreateInstance to get the IUnknown interface of the snap-in. This action calls the DLLGetclassObject. So, if you want to get a feel for how everything works together, stick a breakpoint here and carry on.

If you look through the code, you notice that DLLGetClassObject essentially creates the Class Factory and returns an IClassInterface to COM. When COM calls IClassInterface::CreateInstance, two objects are created, one representing the IComponentData interface and the other representing the IAbout interface.

    CClassFactory *pFactory = NULL;
    
    // make the factory passing in the creation function for the type of object they want

    if (rclsid == CLSID_CComponentData)
        pFactory = new CClassFactory(CClassFactory::COMPONENT);
    else if (rclsid == CLSID_CSnapinAbout)
        pFactory = new CClassFactory(CClassFactory::ABOUT);

    if (NULL == pFactory)
        return E_OUTOFMEMORY;
    
    HRESULT hr = pFactory->QueryInterface(riid, ppvObj);

Now let's look at the other components of this project. As you can see, we create a CComponentData object which represents the left hand side of the snap-in. Looking at the constructor of the CComponentData class, you notice that it creates a CStaticNode object. This will represent the "root node" of the snap-in and is assigned to m_pStaticNode variable. If you look underneath the CStaticNode class, you notice that this is where the underlying folders are created. For instance, in the case of this example, we have one underlying folder which is represented by the CReport class:

CStaticNode::CStaticNode()
{

	children[0] = new CReport;

}
When you try to expand the root node, MMC calls the "CreateComponent" method on the CComponentData class which in turn instantiates a CComponent object. The CComponent object represents the right hand side of the snap-in. Once the CComponent object has been created, four different message are sent:

MMCN_EXPAND
MMCN_ADD_IMAGES
MMCN_SHOW
MMCN_SELECT

Something that should be noted is that every node both on the result pane and scope pane are represented by unique identifiers as shown at the beginning of many of the files:

const GUID CPath::thisGuid = { 0x2974380D, 0x4C4B, 0x11d2, 
                             { 0x89, 0xD8, 0x0, 0x0, 0x21, 0x47, 0x31, 0x28 } }; 

The final phase of the process involves populating the result pane. MMC first calls GetResultsView on the CComponent object and obtains the result view type. In the case of our example, the type is the default. MMC, then sends a MMCN_ADD_IMAGES to add images and MMCN_SHOW to set focus to the result pane. At this point, it's time for the Report object to act. If you notice, the right hand side of our project is represented by Report and ReportContent. The Report object creates the header columns and fills up the rows. When a user clicks on the result pane and tries to start a context menu, the ReportContent event handlers are called upon. With this example, you have a simple snap-in with ContextMenu and database support and this should be enough to get you started with your MMC journey.

Additional supplements

I have included a set of database classes for the application. It's a simple ADO class which is later used to access the database. You should pay special attention to the CreateRecordset and SetDSN functions in there. The CreateRecordset takes three parameters. The first one of course is the query statement while the second is a database number. This database number is used to determine which DSN to use. In my case, my DBClass was working with multiple databases, so I needed this feature. The last parameter is a flag which indicates what type of query to make: a direct select or a table query (i.e. return a whole table). So, modify these according to your needs.

Also there is this one bit of SQL that you should run to create the sample table. You can then manually add some data to the table.

CREATE TABLE [Sample] (
	[SampleID] [int] IDENTITY (1, 1) NOT NULL ,
	[Name] [varchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL 
) ON [PRIMARY]

If you have questions regarding MMC, I would say the best place to go to is the google MMC group or get a copy of November of 2001 Platform SDK. Hope this will help you find your way around.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here