Platform SDK: Management Console

Extending a Primary Snap-in's Namespace

This section discusses the steps necessary for an extension snap-in to extend the namespace of a primary snap-in. For general information about working with extension snap-ins, see "Working with Extension Snap-ins."

A primary snap-in registers the extendable node types it adds to its namespace. An extension snap-in can extend the namespace of a primary snap-in's node type by adding the appropriate registration code and then implementing the IComponentData interface.

When the user selects a scope item in a primary snap-in that is extended by a namespace extension, MMC requests the extension's IComponentData interface and calls IComponentData::Initialize to initialize the extension's IComponentData object (unless it is already initialized). Like a primary snap-in, a namespace extension can add scope items and enumerate the result pane of any items it adds. When the user selects a scope or result item that a namespace extension has added, MMC uses the extension's IComponentData or IComponent implementation to notify the extension of notification messages and to request data objects.

A namespace extension owns any scope or result items that it adds. Therefore, it can extend its own items by adding context menu items, property pages, toolbars, and other features, just like any other snap-in.

Also, any scope or result items added by a namespace extension can also be extended by other extension snap-ins. The namespace extension then behaves like a primary snap-in, so it must register the node type GUIDs of its extendable node types and publish any clipboard formats that other extension snap-ins require for extracting context information.

It is important to note that MMC cocreates one instance of a namespace extension for each primary snap-in instance that it extends. This namespace extension instance extends all nodes of the appropriate node type that appear under that instance of the primary snap-in.

To extend a primary snap-in's namespace

In the following procedure, note that {CLSID}, {snapinCLSID}, and {nodetypeGUID} all denote string representations of the specified CLSIDs and GUIDs. The strings must begin with an open brace ({) and end with a close brace (}).

  1. The CLSID of each snap-in (extension or stand-alone) must be registered under the HKEY_CLASSES_ROOT\CLSID key in the {CLSID} subkey as an in-process server DLL. The snap-in must also register a threading model for the snap-in CLSID. An apartment threading model is recommended..

    For details about the HKEY_CLASSES_ROOT\CLSID key, see the CLSID Key topic in the Microsoft® Platform SDK. For example code, see "Registering and Unregistering a Snap-in."

  2. All snap-ins must be registered under the HKEY_LOCAL_MACHINE\Software\Microsoft\MMC\SnapIns key in the {snapinCLSID} key. Also, if the namespace extension adds scope or result items that can be extended by other extension snap-ins, add the node type GUIDs of the extendable node types under the HKEY_LOCAL_MACHINE\Software\Microsoft\MMC\SnapIns\{snapinCLSID}\NodeTypes key.

    For details about the SnapIns key, see "Registering and Unregistering a Snap-in."

  3. Register the CLSID of the extension snap-in under the HKEY_LOCAL_MACHINE\Software\Microsoft\MMC\NodeTypes\{nodetypeGUID}\Extensions\Namespace subkey, where nodetypeGUID is the GUID of the node type whose namespace is being extended. For details about the NodeTypes key, see "Registration Requirements for Extension Snap-ins."
  4. Implement the IComponentData interface as you would for adding scope items to the scope pane of a primary snap-in. See "Working with the Scope Pane: Implementation Details" for instructions.
  5. The namespace extension's IComponentData::Notify method will receive an MMCN_EXPAND notification message the first time the user selects a primary snap-in's scope item that is extended by the namespace extension. For the namespace extension to know that it is being asked to add its own items underneath the primary snap-in's scope item, you will need to implement a mechanism for seeing if the currently selected scope item belongs to the primary snap-in or the namespace extension. See the Sample Code section for a sample implementation.
  6. If any of the scope items added by the namespace extension also have result pane views, you will need to implement the IComponent interface as well. See "Using Different Result Pane View Types" for information about the various view types available.
  7. Also implement the IDataObject interface. MMC will request data objects from the extension snap-in when one of the scope or result items it adds is selected by the user.
  8. If the namespace extension extends its own items by adding context menu items, toolbars, menu buttons, or property pages, implement the required interfaces. See "Working with Toolbars and Menu Buttons" and "Adding Property Pages and Wizard Pages" for details.

Sample Code

The code samples in this section cover two issues:

All code samples are taken from the documentation of the NameExt sample that accompanies the MMC SDK.

Note that all sample code assumes Unicode compilation.

Namespace Extension Registration Code

The following is a sample registry entry for the NodeTypes key for a node type with a Namespace extension.

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MMC\NodeTypes\
   {2974380F-4C4B-11d2-89D8-000021473128}\
      Extensions\
         Namespace
            {64026453-6A22-11d3-9154-00C04F65B3F9}  = 
            REG_SZ "Namespace Extension to the Sky-based Vehicle node"

The nodetypeGUID is the value of the node type GUID of the "Sky-based Vehicle" scope item; this item is added to the scope pane of many of the C++ sample snap-ins that accompany the MMC SDK, for example, the Extens sample.

The value under the Namespace key represents the CLSID of the NameExt sample. The NameExt sample extends scope items of node type nodetypeGUID in the Extens sample.

In the NameExt sample, the RegisterSnapin function called by the extension snap-in's DllRegisterServer function contains the code for adding the extension's CLSID to the NodeTypes key for a node type that is being extended. This code is very similar to that in the CMenuExt sample and is documented in "Registration Requirements for Extension Snap-ins."

The only difference between the implementation of the RegisterSnapin function in the CMenuExt and NameExt samples is in the switch statement found in the function:

        switch (pNodeExtension->eType)
        {
        case NameSpaceExtension:
            _tcscat(szKeyBuf, _T("\\Extensions\\Namespace"));
            break;
        default:
            break;
        }

As you can see, the switch statement in the NameExt sample has been modified to only consider the case where the extension type can be NameSpaceExtension. Recall that pNodeExtension points to the _NodeExtensions array that lists all the node types that the extension snap-in extends:

EXTENDER_NODE _NodeExtensions[] =
{
    {NameSpaceExtension,
       {0x2974380f, 0x4c4b, 0x11d2, { 0x89, 0xd8, 0x0, 0x0, 0x21,
        0x47, 0x31, 0x28 } },
       {0x64026453, 0x6a22, 0x11d3, {0x91, 0x54, 0x0, 0xc0, 0x4f, 
        0x65, 0xb3, 0xf9} },
       _T("Namespace Extension to the Sky-based Vehicle node")},
    {DummyExtension,
       NULL,
       NULL,
       NULL}
}

The NameExt sample is only a namespace extension, so the _NodeExtensions array only has one element (of type EXTENDER_NODE structure).

IComponentData::Notify Implementation

The NameExt sample uses the data object passed into IComponentData::Notify to determine the node type GUID of the currently selected scope item. If this value matches the node type GUID of the scope item that the NameExt sample extends, then the extension snap-in adds its own items as child items of the selected scope item. If the value doesn't match, the extension is being asked to add child items to one of its own scope items.

The following code sample taken from the NameExt sample uses this technique. Note that CComponentData implements the IComponentData interface.

HRESULT CComponentData::Notify(
                      /* [in] */ LPDATAOBJECT lpDataObject,
                      /* [in] */ MMC_NOTIFY_TYPE event,
                      /* [in] */ LPARAM arg,
                      /* [in] */ LPARAM param)
{

    HRESULT hr = S_FALSE;
    
    if (NULL == lpDataObject)
        return hr;

    switch (event)
    {
    case MMCN_EXPAND:

        GUID myGuid;
        GUID* pGUID= &myGuid;
         // extract GUID of the the currently selected node type from
         // the data object
        hr = ExtractObjectTypeGUID(lpDataObject, pGUID);
        _ASSERT( S_OK == hr );    

        /* compare node type GUIDs of currently selected node and the
           node type we want to extend. If they are are equal,
           currently selected node is the type we want to extend, so
           we add our items underneath it. */

if (IsEqualGUID(*pGUID, getPrimaryNodeType()))
            OnExpand(m_ipConsoleNameSpace, m_ipConsole,
        (HSCOPEITEM)param);

        else
        // currently selected node is one of ours instead
        {
            CDelegationBase *base = GetOurDataObject(lpDataObject)->
                                    GetBaseNodeObject();
            hr = base->OnExpand(m_ipConsoleNameSpace, m_ipConsole,
                                (HSCOPEITEM)param);
        }

        break;
    }
    return hr;
}

The ExtractObjectTypeGUID function returns the node type GUID of the currently selected scope item. The getPrimaryNodeType function returns the GUID of the node type that the extension snap-in extends. If the values returned by the two functions match, the scope item belongs to a primary snap-in. The extension snap-in then adds its own items underneath it.

If the node type GUIDs differ, the currently selected scope item belongs to the extension snap-in.

See Also

Working with Extension Snap-ins