Adding About Information
Adding the Items
Adding Property pages
Adding Connect to Server dialog
Adding ActiveX control
This article tries to show how to implement
basic MMC Snap-in features using ATL and gives you a starting
point. The MMC Snap-in is a COM in-process server DLL. MMC stands for
Microsoft Management Console and is designed to simplify and unify the different
tasks and GUI elements for the end user. Some of the examples that use MMC
as a hosting environment include Event Viewer, NT Services configuration GUI,
Indexing Service, Win2k Disk Defragmenter, Device Manager, and many
others. You can view the list on your machine by running mmc.exe and
choosing menu Console | Add/Remove Snap-in | Add. The MMC framework
provides no management by itself, but only unified graphical interface for
hosting snap-ins. MMC is not a solution for everything. It's just
another option that you have. It's up to you to see the applicability of
MMC to your particular needs. This article only describes Primary Snap-Ins
MMC GUI has several elements to it.
- Scope Panes - Console Tree which is normally on the left pane.
Starts with a Static node which can have children.
- Result Panes - List View, Taskpad View, ActiveX control, and Web Page
normally on the right pane. Usually appears when user selects a node
from Console tree.
- Context menus - Popup menu when user right clicks Scope Pane or Result
- Toolbars and menus
- Property Sheets - When user chooses Properties for scope or result pane
items, MMC allows developer to add property pages.
Key Required Interfaces:
Note: The following links point to MSDN pages that have UML diagrams and explain
in details the communication between MMC and your Snap-In. Even though it's
based on the C++ samples that they provide, it can still be followed easily.
The only help I found on the subject at the time was MSDN. I strongly suggest
learning MMC Snap-Ins framework through the various C++ Samples and Diagrams at
Snap-ins Discussion (MSDN).
Create a new
ATL COM AppWizard project for in-process COM server. Insert New ATL Object | MMC
Snap-in. For the name put Simple. For MMC Snap-in property page leave the
defaults and choose
All Snap-ins get installed under
HKEY_LOCAL_MACHINE\Software\Microsoft\MMC\SnapIns reg key.
The following values are valid under this key:
- NameString - Displayed during Add/Remove Snap-in Dialog. If not
specified, Snap-in appears without name.
- About - CLSID of the about object. Used during Add/Remove Snap-in
to provide the version and copyright info as well as the Snap-in icon.
If not specified, no about information will be available to end user and
default icon for the Snap-in will be used, which is generic folder icon.
- StandAlone - The key indicates that this is a Primary
Snap-in; that is, it can be used stand alone and doesn't extend any other
- NodeTypes - Contains values that represent Snap-ins nodes.
You should list your nodes here only if you want them to be extended by other
Extension Snap-ins. The wizard adds our static node here, it
assumes that we will allow Extension Snap-ins to be written for it.
Let's start with the simple part of MMC, the
interface. This interface is responsible for providing the copyright and
version info, etc. to the user. The info is only visible when the Snap-in
is being inserted through Add/Remove Snap-ins dialog:
It is implemented in a separate COM class for efficiency since it's role as
you can see is very minimal. It has very trivial methods. Adding
About Information (MSDN)
This is implemented by
IComponentDataImpl in ATL. The
IComponentData is associated with the Scope pane (left pane/the tree
nodes). MMC calls the
IComponentDataImpl::CreateComponent, which will
create an instance of
IComponentImpl or more specifically ATL will create
CSimpleComponent class, which was passed as 2nd template argument to
IComponentDataImpl.MMC will associate it with this
IComponentDataImpl::Initialize method, which is called
by MMC, caches the private IConsole(2) and it you can also cache the
IConsoleNamespace(2). The constructor of
CSimple creates a new main
- CSimple - IComponentData. (Scope Pane/Left
pane/The tree nodes/The folders)
- CSimpleComponent- IComponent. (Result
- CSimpleData - It's base class CSnapInItemImpl hasa method
CSnapInItemImpl::GetDataObject to provide the IDataObject pointer. It
creates an instance of CSnapInDataObjectImpl, which inherits from
IDataObject.MMC uses IDataObject as means of transferring data between
MMC and Snap-in. It uses predefined clipboard formats for that.
The names used by ATL wizard aresomewhat confusing. I
always mix up which one inherits from
IComponentData and which
oneprovides implementation for
IDataObject. IComponentData (MSDN)
CComponentData and Displaying the Snap-in Root Node (MSDN)
This is implemented by
IComponentImpl in ATL. The
associated with the Result Pane (right pane). It also has Initialize
method and gets passed its own private
IConsole pointer by MMC, which is also
IComponentImpl. It also sets the header, but the docs say that "The
IConsole2::SetHeader method is obsolete in MMC version 1.2 and
CComponent and Expanding the Snap-in Root Node (MSDN)
This is implemented by
ATL. We don't come in contact with it directly.ATL handles it.
It gets created when MMC calls
QueryDataObject, which calls
Data Objects and MMC (MSDN)
This can be used by
IComponent derived classes to provide persistence
support. You can for example save the computer name, IP address, folder
names, services, etc...
and IExtendControlbar can be used to extend the popup
menu, property pages, and add control bars for
ISnapinHelp(2) is used to inform MMC that we
support help. Snap-ins are strongly encouraged to provide
IDisplayHelp can be used to support context sensitive
help by responding to MMCN_CONTEXTHELP messages from MMC.
The best thing to do is to rename the
CStaticNode. I think it
makes it clearer, but I left it as is. To simplify our life a little we need to
create a base classfor the nodes. This class will provide all the
default initialization and functions that don't need to be repeated in all our
node classes. I've added a
CBaseNodeItem, which inherits from
CSnapInItemImpl and provides simple initialization. If you look at
CBaseNodeItem class you'll see that it does some pretty generic stuff in the
GetResultPaneInfo, and Notify that are shared
among most items. The Notify method is the method responsible for handling
various MMC messages and is the primary way of getting notifications from MMC.
The obvious advantage of course is for Notify method to be in thebase
class. All we have to do is call the appropriate virtual function for each
message and the rightfunction for our nodes will be called. So
nowany new Scope Node or Result Itemwill inherit from
Any new Scope Node or Result Itemwill inherit from
items in MMC are represented by the
To add the items to the Result Pane:
- Derive another
CBaseNodeItem which will represent result items. Define the
clipboard vars. I set the GUID to
- MMCN_SHOW - respond to this message from MMC in
Notify. We simply call virtual
OnShow function. Insert the
GetResultViewType - set the params depending on what you need. Listview,
Taskpad or ActiveX ctrl.
GetResultPaneInfo - calls virtual
GetResultPaneColInfo to get the list
To add items to the Scope Pane:
- Derive another class from
CBaseNode which will represent scope items.
Define the clipboard vars.
- Createa member of your new classin parent node class.
- MMCN_EXPAND - handle this message from MMC. We simply
call our virtual
- Define the clipboard format values (
Create a simple html help project with HTML help wizard. Handle the
MMCN_CONTEXTHELP. This will enable the F1 context sensitive help. Inherit the
IComponentData derived class from ISnapinHelp2. Provide implementation for
GetHelpTopic (tell it the directory of your help file). Look at the help on ShowTopic
for the format on how to specify help topics. Now each Node in the Scope
Pane and each item in the Result Pane can have it's own help file entry.
The help file will be merged with MMC's help file. So you can add your own
headings and stuff. Implementing
MMC 1.2 has
MessageView OCX control that can be used to provide some useful
info to the user.
You create it similar to creating ActiveX.
GetResultViewType and provide the
CLSID_MessageView. During the
QueryResultView to get access to
IMessageView interface and manipulate it.
MMC Message OCX Control (MSDN)
To provide the property page:
- derive a class from
QueryPagesFor for your Scope Pane or Result Pane Item
CreatePropertyPages for your Scope Pane or Result Pane Item
- Enable the
MMC_VERB_PROPERTIES verb. I did it in
- Save a pointer to parent class to exchange the data if needed
- You can use the
PropertyChangeNotify function of your property page class
which will translate to
You have to override the
Notify function of
IComponentDataImpl derived class and provide the
lpDataObject == NULL case and handle the
(Side Note: There are different predefined MMC verbs that
can be used such as
MMC Standard Verbs (MSDN))
If you want to display Property Page and not use the MMC's Properties menu,
you have to do so using the
IPropertySheetProvider. Look under the Adding Wizard
section later for details. Adding
Property Pages (MSDN)
Adding menu is easy with ATL. Just add a menu resource with 4 popup
Each popup menu on the menu represent
specific place on the MMC popup menu. Adding menu entry under Top will create a
top level menu, Task - under
AllTasks, New - under New, and
View - under View. To add the menu all you actually do is use
SNAPINMENUID ATL macro for each node or result item that you want to have
menu commands. You handle messages using
END_SNAPINCOMMAND_MAP. What you get is the pointer
CSnapInObjectRootBase. You cast it to the
derived class by looking at the m_nType (Scope or Result). Adding
Context Menu Items (MSDN)
Add a menu entry under All Tasks for invoking
the wizard. Then Add a function such as
InvokeWizzard so it is accessible to you
when you need it. It can be used for Result and Scope items based on the m_nType. All we get with the menu command is
CSnapInObjectRoot, Notice that ATL
uses the m_nType variable in
CSnapInObjectRoot. So we know that
IComponentDataImpl derived class has type 1 and
IComponentImpl has type
2.To display wizards we have to directly use the
Look under the Using
IPropertySheetProvider Directlyon the MSDN.
Property Pages and Wizard Pages (MSDN)
Add a toolbar resource with 16x16 buttons. Add the entry inside the
END_SNAPINTOOLBARID_MAP block. Handle the
commands from toolbar under
You can manipulate the toolbar. Notice that
m_toolbarMap. Call the lookup method on it passing the toolbar id as
key. It will return
IToolbar pointer. Now call
SetButtonState on it. You
can also use the
GetToolbarInfo function to get the
CSnapInToolbarInfo and then
iterate through all toolbars of the class if needed. More details at Adding
if needed.You can save nodes and items, computernames and reload it
next time. Snap-in
Persistence Model (MSDN)
The main static node has to respond to
QueryPagesFor and check the type to be
CCT_SNAPIN_MANAGER. Implement the
CreatePropertyPages. So now when MMC
adds your Snap-in, you'll bee able to present a choose computer dialog.
The dialog layout is basically standard for most components.
Adding ActiveX isn't hard either. Derive another
class and implement the
GetResultViewType. MMC will call this
function. One of the params is ppViewType, which should be set to
CLSID of the control you want to display. You can cache or recreate
the control each time the item is selected through the pViewOptions param. You
GetResultViewType returns MMC will send a MMCN_INITOCX notify to the
Snap-in. One of the params will be the pointer to
IUnknown. You can also
obtain the pointer through
IConsole2::QueryResultView when you receive the
MMCN_SHOW notification from MMC. You can set up your sink to receive
events if needed. The control most likely has to support
I'm not sure and didn't test it.
Custom OCX Controls: Implementation Details (MSDN)
There are two different taskpads. Snap-in taskpad and Console taskpad.
The latter one is available with version 1.2 and ismuch easier because MMC
takes care of managing and creating the taskpad. To add the Console
taskpad do the following select and then right click the node. Choose
New Taskpad View:
You can play with different options to change
how taskpad looks, etc...
If you want to do it manually (Snap-in
taskpad)or have to support 1.1 then read this:Using
Taskpads (MSDN) and Using
Taskpads: Implementation Details. Of course you'll have much more
control over the taskpad if you choose to use the Snap-in taskpad.
Custom Web Pages(MSDN)
Some Useful links
Breakpoints Not Hit in ATL MMC Snap-in (MSDN)
Management Console (MSDN)
Sample Snap-ins (MSDN)
Saved Console Files (MSDN)
Designing TView, a System Information Viewer MMC Snap-in
C++ Developer: January 1999 - Writing MMC Snapins is a Snap with ATL 3.0