Platform SDK: Management Console |
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 (}).
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."
For details about the SnapIns key, see "Registering and Unregistering a Snap-in."
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.
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).
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.