Developing MMC Snap-Ins using ATL

Introduction
Creating a Simple MMC Snap-In with ATL
Adding About Information
Adding the Items
Adding Help
Adding
MessageView

Adding Property
pages

Adding Menu
Adding Wizard
Adding Toolbar
Adding
Persistence

Adding Connect to Server
dialog

Adding ActiveX
control

Adding Taskpads
Adding WebPage

Introduction

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 (Non Extension).

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 Pane.

  • Toolbars and menus
  • Property Sheets – When user chooses Properties for
    scope or result pane items, MMC allows developer to add property pages.

  • Wizards
  • Taskpads


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 Sample Snap-ins Discussion (MSDN).

Creating a Simple MMC Snap-In with ATL

(Tools used: Microsoft. Platform SDK for Whistler Beta 1 and
VC++ 6.0(SP4) under Windows 2000)

    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 IExtendContextMenu,
IExtendPropertySheet, and IExtendControlBar.

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 Snap-ins.

  • 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.

ISnapInAbout

    Let’s start with the simple part of MMC, the ISnapinAbout
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)






IComponentData

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 our CSimpleComponent class,
which was passed as 2nd template argument to IComponentDataImpl. MMC
will associate it with this IComponentData. The 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
static Node.


  • CSimple – IComponentData. (Scope Pane/Left pane/The tree nodes/The folders)

  • CSimpleComponent – IComponent. (Result Pane/Right
    pane/Listview..etc)

  • CSimpleData It’s base
    class  CSnapInItemImpl has a 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
are somewhat confusing.

I always mix up which one
inherits from IComponentData and which one provides implementation for
IDataObject. IComponentData
(MSDN)

Initializing
CComponentData and Displaying the Snap-in Root Node
(MSDN)


IComponent is implemented by
IComponentImpl in ATL.  The IComponentImpl is 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 cached by IComponentImpl.
It also sets the header, but the docs say that “The IConsole2::SetHeader method is
obsolete in MMC version 1.2 and later.”  IComponent
(MSDN)
Creating
CComponent and Expanding the Snap-in Root Node
(MSDN)


IDataObject
is implemented by CSnapInDataObjectImpl in ATL. We don’t come in
contact with it directly.  ATL handles it.  It gets created when
MMC calls QueryDataObject, which calls GetDataObject.. etc
Data
Objects and MMC
(MSDN)



IPersistStreamInit can be used by
IComponentData and IComponent derived classes to provide persistence
support.  You can for example save the computer name, IP address, folder
names, services, etc…


 IExtendContextMenu, IExtendPropertySheet(2), and
IExtendControlbar
can be used to extend the popup menu, property pages,
and add control bars for Snap-ins.
ISnapinHelp(2) is used to
inform MMC that we support help.  Snap-ins are strongly encouraged to
provide help
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 CSimpleData to 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 class for 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 constructor, GetScopePaneInfo, 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 the base class.  All we have to do is
call the appropriate virtual function for each message and the right function for
our nodes will be called. So now any new Scope Node or Result
Item will inherit from CBaseNodeItem.


Adding the Items


Any new Scope Node or Result Item will inherit
from CBaseNodeItem. The items in MMC are represented by the SCOPEDATAITEM and RESULTDATAITEM structures.

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 GUID_NULL.
  • MMCN_SHOW – respond to this message from MMC in
    Notify.  We simply call virtual OnShow function. Insert the columns/items.
  • GetResultViewType – set the params depending on what
    you need. Listview, Taskpad or ActiveX ctrl.

  • GetResultPaneInfo – calls virtual GetResultPaneColInfo to get the list
    item.

To add items to the Scope Pane:



  • Derive another class from CBaseNode which will represent scope items. Define
    the clipboard vars.
  • Create a member of your new class in parent
    node class.
  • MMCN_EXPAND – handle this message from MMC. We simply
    call our virtual OnExpand.
  • Define the clipboard format values (m_NODETYPE, m_SZNODETYPE,
    m_SZDISPLAY_NAME, m_SNAPIN_CLASSID, CSomeNodeGUID_NODETYPE)

Adding Help


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
Help
(MSDN)

Adding
MessageView


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. Just implement the GetResultViewType and provide the
CLSID_MessageView.  During the OnShow use QueryResultView to get access to
the IMessageView interface and manipulate it.


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


Adding menu is easy with ATL.  Just add a menu
resource with 4 popup menus.
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
All  Tasks, New – under New, and
View – under View. To add the menu all you actually do is use
the SNAPINMENUID ATL macro for each node or result item that you want to have
menu commands.  You handle messages using
BEGIN_SNAPINCOMMAND_MAP/END_SNAPINCOMMAND_MAP.  What you get is the pointer
to CSnapInObjectRootBase.  You cast it to the IComponent or IComponentData
derived class by looking
at the m_nType (Scope or Result). Adding
Context Menu Items
(MSDN)

Adding
Wizard


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 IPropertySheetProvider.
Look under the Using
IPropertySheetProvider Directly
 on the MSDN.


 


Implement the IPersistStreamInit for IComponentImpl and/or
IComponentDataImpl if needed. You can save nodes and items, computer names and
reload it next time. Snap-in
Persistence Model
(MSDN)

Adding Connect to Server
dialog when the Snap-in
is Added


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
control


Adding ActiveX isn’t hard either.  Derive
another CBaseNodeItem class and implement the GetResultViewType.  MMC
will call this function.  One of the params is ppViewType, which
should be set to the 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 can use
MMC_VIEW_OPTIONS_CREATENEW/MMC_VIEW_OPTIONS_NONE. 
After 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 IDispatch, but I’m
not sure and didn’t test it.

Adding WebPage


Look at Using
Custom Web Pages
 (MSDN)

Some Useful links


BUG:
Breakpoints Not Hit in ATL MMC Snap-in (MSDN)

Microsoft Management Console (MSDN)

MMC
C++ Sample Snap-ins (MSDN)


Distributing
Saved Console Files (MSDN)


MMC:
Designing TView, a System Information Viewer MMC Snap-in


Visual
C++ Developer: January 1999 – Writing MMC Snapins is a Snap with ATL
3.0


Simple MMC
SnapIn

Downloads

Download demo – 32 Kb

More by Author

Must Read