用ATL编写MMC Snapin的Sample

Windows SDK笔记(七):创建MDI窗口    一、概述MDI窗口包含一个框架窗口和若干子窗口。实际上,框架窗口本身是一个普通主窗口,不过它的客户去被一个特殊窗口覆盖。这个特殊窗口是系统预定义的“窗口类”,类名称为:"MDICLIENT"。它负责各个MDI子窗口的管理。 二、窗口建立1.注册一个MDI框架窗口类,提供MDI框架窗口消息处理函数MDI框架窗口消息处理函数中,将未处理消息交由DefFrameProc处理//MDI框 阅读详情

 


MMC相关的编程接口
MMC 实现了下面的接口:
IColumnData (new in MMC 1.2)
IConsole2
IConsoleNameSpace2
IConsoleVerb
IContextMenuCallback
IContextMenuProvider
IControlbar
IDisplayHelp
IHeaderCtrl2 (new in MMC 1.2)
IImageList
IMenuButton
IPropertySheetCallback
IPropertySheetProvider
IRequiredExtensions
IResultData
IToolbar
Snap-ins 实现了下面的接口:
IComponent
IComponentData
IEnumTASK
IExtendContextMenu
IExtendControlbar
IExtendPropertySheet2
IExtendTaskPad
IRequiredExtensions
IResultDataCompare
IResultDataCompareEx (new in MMC 1.2)
IResultOwnerData
ISnapinAbout
ISnapinHelp2

IComponent接口表示了右边的结果栏(Result pane)里的对象,MMC需要和结果栏里的对象通信时使用这个接口;
IComponentData接口表示了左边的目录栏(scopet pane)里的对象(这些对象可以称之为节点),MMC需要和目录栏里的对象通信时使用这个接口;
IExtendContextMenu接口,无论用户用鼠标右键点击了左边的节点(scope pane item)还是右边的项(result pane item),MMC都会弹出一个默认的关联菜单,这时MMC会使用这个接口询问该对象(Item),是否需要添加自己的菜单项。
IExtendControlbar和IExtendPropertySheet2也是类似的道理。
ISnapinAbout实现了一个关于对话框的接口,MMC通过这个接口了解Snapin的版本、描述信息、提供者信息、对话框图标,并且特别重要的是,MMC通过这个接口得到了Snapin的所有结点、项的默认图标,要修改根结点的图标也可以通过这个函数GetStaticFolderImage来向MMC提供。

详尽的描述请参考Platform SDK。

Snapin不需要实现全部接口,Sample仅实现了其中的:
IComponent
IComponentData
IExtendContextMenu
IExtendControlbar
IExtendPropertySheet2
ISnapinAbout
MMC的ATL实现支持类简介
Sample的模型图
模型图 ATL MMC Snapin.gif
ATL实现了几乎全部的接口,提供了默认的处理代码。ATL Wizzard生成的代码提供了基本的编程框架,Snapin的特性实现依赖于对CmySnapinData的某些函数的重载来修改默认行为。
上图中,CMySnapinComponent的基类IExtendContextMenuImpl,IExtendContextPropertySheet,也同CMySnapin的一样,依赖于对CMySnapinData的几个同名函数的调用,只是因为线条太乱才没有画出。
Snapin DLL Sample的代码生成Step by Step
1,    新建ATL工程,如果需要使用MFC,可以使用Wizzard选项支持MFC工程命名test6;
2,    “New ATL Object”,选择“MMC Snapin”;
3,    命名“MySnapin”,并在第二个属性页“MMC Snapin”上,选择IextendContextMenu,IextendControlbar,IextendPropertySheet,IsnapinAbout;并且去掉对持久性的支持;
4,    确定后,ATL Wizzard为我们生成了CMySnapin, CCMySnapinComponent, CMySnapinData,CMySnapinAbout, CMySnapinPage;
5,    编译;然后运行mmc.exe,添加一个管理单元“MySnapin”,另存为MySnapin.msc;
代码简介
CMySnapin实现了IComponentData,IExtendContextMenu,,IExtendPropertySheet三个接口。CMySnapinComponent实现了IComponent,IExtendContextMenu,IExtendControlbar,IExtendPropertySheet 四个接口,CMySnapinAbout则实现了ISnapinAbout接口。
DLL向外部暴露了CMySnapin和CMySnapinAbout两个对象。这样MMC就可以找到ISnapinAbout和IComponentData,IExtendContextMenu,,IExtendPropertySheet三个接口,然后MMC通过IComponentData的CreateComponent方法创建了CMySnapinComponent对象,从而又提供了CMySnapinComponent的IComponent,IExtendContextMenu,IExtendControlbar,IExtendPropertySheet 四个接口。
从图中可以看到,ATL的接口实现类实现了部分方法的默认行为,然后把几个重要方法如Notify等传递到CMySnapinData对象的同名函数,让其继续处理。
CMySnapinData从CSnapinItemImpl继承,CSnapinItemImpl实现了CSnapinItem接口,该接口定义了Item对象(左边的节点(scope pane item)还有右边的项(result pane item))的所有行为。
CMySnapin在构造函数里创建了CMySnapinData作为根结点。一个Item的所有行为都可以通过重载某些方法来修改默认行为。比如在根结点下面添加几个子节点,可以在重载的Notify方法中处理MMCN_EXPAND消息等等。
MSDN中的MMC Snap-In Wizard
MMC Snap-In Wizard讲了MMC Snap-In FAQ:
1.    How Do I Add a Toolbar Resource to the Snap-In Object?
2.    How Do I Add Menu Items, Control Bar Buttons, and a Property Sheet to the Snap-In Object?
3.    How Do I Enumerate the Child Items of the Snap-In Object?
4.    How Do I Add Custom Item Types to the Snap-In Object?
以上内容请自行参考msdn,按照以上的方法,可以做出一个完整功能的Snapin了。但是,非常遗憾的是,ATL Wizzard提供的无论是菜单、工具栏还是属性页都是所有的Item公用的,无论是Scope Item还是Result Item。特别是在有多个不同种类的节点的时候,这样几乎是不合适宜的。
按需定制的Item实现QA
如何生成子节点(Scope Item)?
    在按照以上步骤生成代码框架以后,运行MySnapin.msc可以看到只有一个根结点,名字是MySnapin。修改这个根结点的名字,只需要修改MySnapin.cpp文件中
const OLECHAR* CMySnapinData::m_SZDISPLAY_NAME = OLESTR("MySnapin");
这一行即可。
    前面讲过ATL把Item抽象成CSnapinItem接口,CSnapinItemImpl类实现了这个接口的大部分默认行为,因此,所有的Item都应该从这个类继承。考虑到CMySnapinData作为我们的根结点,ATL已经为我们生成了一些代码,从CMySnapinData继承是更好的选择。(能够重用的代码其实只有CMySnapinData构造函数中的初始化代码,不过从CMySnapinData继承的最大好处是可以将公共的实现放在CMySnapinData类中,而不需要每个Item类都实现一份相同的代码。),本文将从CMySnapinData类继承,也由于CMySnapinData将作为基类实现,因此,我们需要另外做一个根结点。
    接下来我们将生成三个一级子节点,分别为类似“服务”、“事件查看器”、“帐户管理”,然后在“事件查看器”和“帐户管理”中再生成二级子节点,基本上包含了定制菜单、属性页、工具栏等。
    分别从CMySnapinData继承,生成CItemRoot, CServicesContainer, CEventsContainer, CAccountsContainer。注意,在MySnapin.h文件中加入一行 #include "test6.h"。
    在CMySnapin的构造函数里,我们把根结点改为CItemRoot。
    在CItemRoot类中,重载Notify方法,增加代码处理MMCN_EXPAND,这个消息给了我们添加子节点(Scope Item)的机会。
    case MMCN_EXPAND:
        {
            CComQIPtr<IConsoleNameSpace, &IID_IConsoleNameSpace>
spConsoleNameSpace(spConsole);
            
            m_pServicesContainer->m_scopeDataItem.mask |= SDI_PARENT;
            m_pServicesContainer->m_scopeDataItem.relativeID = param;
            spConsoleNameSpace->InsertItem(&m_pServicesContainer->m_scopeDataItem);

            m_pEventsContainer->m_scopeDataItem.mask |= SDI_PARENT;
            m_pEventsContainer->m_scopeDataItem.relativeID = param;
            spConsoleNameSpace->InsertItem(&m_pEventsContainer->m_scopeDataItem);

            m_pAccountsContainer->m_scopeDataItem.mask |= SDI_PARENT;
            m_pAccountsContainer->m_scopeDataItem.relativeID = param;
            spConsoleNameSpace->InsertItem(&m_pAccountsContainer->m_scopeDataItem);
            
            hr = S_OK;
        }
        break;
如何生成结果栏的项(Result Item)
    从CMySnapinData继承,生成CEventEntry类,表示一个事件内容。在CEvent类中修改Notify方法的MMCN_SHOW消息,这个消息给了我们添加Result Item的机会。
如何修改子节点的名字?
    每一个结点都从CMySnapinData继承,其父类CSnapinItemImpl有一个成员变量CComBSTR m_bstrDisplayName。
MMC调用IComponentData或者IComponent 的GetDisplayInfo来获得显示信息,包括结点名字,GetDisplayInfo把调用传递到GetScopePaneInfo或者GetResultPaneInfo函数,GetScopePaneInfo和GetResultPaneInfo函数默认返回m_bstrDisplayName。
因此只要在构造函数里修改m_bstrDisplayName的值即可达到目的。
如何修改子节点的图标?
    在CMySnapinData中实现Notify方法的MMCN_ADD_IMAGES消息,这这里我们把所有的图标全部加载。这样其他的Item类就不需要再实现这部分代码了,只要把Notify中没有处理的消息让CMySnapinData的Notify方法处理一下即可。
    对于每个Snapin都有一个IImageList接口可供使用,MMC利用这个图标列表来保存所有需要用到的图标,以后每个Item只需要指出它的图标在图标列表的索引即可:
m_scopeDataItem.nImage = 2;
m_scopeDataItem.nOpenImage = 2;
    但是Scope栏中的图标却不是通过MMCN_ADD_IMAGES消息来加载的,而必须在CMySnapin类的Initialize方法中首先加载所有必要的图标。
    还有,以上的方法对根结点的图标都没有作用。根结点的图标的修改必须通过修改CMySnapinAbout类GetStaticFolderImage方法才可以。也可以顺便为About对话框添加一个ICON。    
如何修改子节点在结果栏中的默认显示?
    Scope Item在Result pane中默认仅仅显示一个名称。比如,在选中“MySnapin”时,默认行为是在Result pane中显示一级子节点。下面我们让“事件查看器”显示更详尽的信息。
    在CEventsContainer的Notify方法中修改MMCN_SHOW消息:
case MMCN_SHOW:
        {
            CComQIPtr<IResultData, &IID_IResultData> spResultData(spConsole);
            
            spHeader->InsertColumn(0, L"日志", LVCFMT_LEFT, 100);
            spHeader->InsertColumn(1, L"描述", LVCFMT_LEFT, 200);

            hr = S_OK;
        }
        break;
    然后在CEvent中重载GetResultPaneColInfo方法,提供每一列的显示字符串。
    由于GetResultPaneColInfo是非虚函数,因此我们还得在CEvent重载GetResultPaneInfo函数。或者修改CMySnapinData的GetResultPaneColInfo函数为虚函数,那么就可以不用再重载GetResultPaneInfo了。
如何给某一个子节点添加自己独特的菜单?
    由于从CSnapinItemImpl以模版方式实现,因此从CMySnapinData继承的Item类,将需要重载相应的处理函数,而不能最大限度地重用CSnapinItemImpl的实现。
    所以,我们让CService等几个需要更多功能的类从CSnapinItemImpl<CService>继承。

给“服务”项目添加“启动”、“停止”菜单。
1,    在菜单资源中添加菜单IDR_MYSNAPIN_MENU1,添加菜单项“启动”、“停止”到第一个下拉菜单中,如果需要在其他菜单项上,也可以添加到其他的下拉菜单中;
2,    使用宏SNAPINMENUID(IDR_MYSNAPIN_MENU1)来告诉ATL菜单资源的ID;
3,    使用宏
BEGIN_SNAPINCOMMAND_MAP(CService, FALSE)
            SNAPINCOMMAND_ENTRY(IDM_START, OnStart)
            SNAPINCOMMAND_ENTRY(IDM_STOP, OnStop)
    END_SNAPINCOMMAND_MAP()
    来接收命令消息。
4,    并使用
HRESULT OnStart(bool& bHandled, CSnapInObjectRootBase* pObj);
    HRESULT OnStop(bool& bHandled, CSnapInObjectRootBase* pObj);
来处理消息。
5,    如有必要,重载UpdateMenuState函数修改菜单状态;
如何给某一个子节点添加自己独特的工具栏?
给“服务”项目添加“启动”、“停止”工具栏按钮。
1,    资源中添加工具栏,添加按钮“启动”、“停止”;
2,    使用宏
BEGIN_SNAPINTOOLBARID_MAP(CService)
            SNAPINTOOLBARID_ENTRY(IDR_TOOLBAR1)
    END_SNAPINTOOLBARID_MAP()
    来接收命令消息。
3,    如有必要,重载UpdateToolbarButton函数修改按钮状态;
4,    如有必要,在处理消息后,可以通过IToolbar接口修改工具栏按钮状态;
如何给某一个子节点添加自己独特的属性页?
给“帐户”添加属性页。
1,    在CAccount类中重载Notify方法。
2,    在Notify方法中处理MMCN_SELECT消息:
CComPtr<IConsoleVerb> spConsoleVerb;
            if(spConsole->QueryConsoleVerb(&spConsoleVerb) != S_OK)
            {
                ATLTRACE("==>Query ConsoleVerb faild./n");
                return S_FALSE;
            }
            else
            {
                spConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED,
TRUE);
                hr = S_OK;
        }
3,    重载CreatePropertyPages、QueryPagesFor方法,创建属性页,可以使用ATL Wizzard为我们生成的CMySnapinPage,也可以自行定制一个类似的类。
4,    如有必要,可以在属性页的OnApply函数中发出属性改变通知CAccout;
5,    CAccout相应地更新自己的显示。
注意点:
SCOPEDATAITEM/RESULTDATAITEM 结构的lParam,ATL特殊用法
    lParam在ATL中有特殊意义,IComponentImpl和IComponentDataImpl的GetDisplayInfo函数都假设SCOPEDATAITEM/RESULTDATAITEM 结构的lParam就是CSnapInItem对象,因此,CMySnapinData的构造函数中有m_scopeDataItem.lParam = (LPARAM) this;和m_resultDataItem.lParam = (LPARAM) this;
    因此,如果我们的Item类不从CMySnapinData继承的话,那么也要同样做这些工作。
QueryPagesFor方法
    如果Snapin支持属性页,那么必须在Root结点上提供一个QureyPagesFor的方法来支持,否则无法通过MMC控制台“增加”这个管理结点。

ATLSNAP.H // This is a part of the Active Template Library. // Copyright (C) 1996-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Active Temp 阅读详情

相关推荐

MMC Snap In应用程序开发

MMC Snap In Development Starting Guide 目录 MMC Technology Summary Keywords MMC Programming Elements In this topic How to test the MMC program MMC Basic Class MMC Sample Code 抱歉:由于本人的英文能...

weixin_30332705的博客 319

解禁注册表,启用MMC

       公司租用了远端主机(系统为WIN2003+SP2),需要设定组策略进行管制,在设定当中,先后把命令提示符、注册表、桌面、资源管理器等禁用,因一时大意,竟把MMC平台也设为禁用。退出系统后重新登陆,想再次进入组策略编辑器,才发生MMC不能使用了,唯一庆幸的是“开始=》运行”还未设为禁用,但在“运行”中输入“CMD”或“REGEDIT”,系统提示“命令提示符已被管理员禁用”等。试了N种方

ggw128的专栏 3275

用C# 创建 MMC Snapin

下载示例 - 102 Kb 绪论The article/code snippet helps in creation of MMC Snapin using C#. 背景The framework for building management consoles for Windows NT/2000 is developed by Jim. Jim is the author for ironr

江湖·郎中·路 1820

ATL开发复合控件

 转载:http://www.vckbase.com/index.php/wv/1110 本文讲述了如何用ATL建立复合控件,以及如何响应连接点事件。考虑到代码很简单,程序中没有加注释,如有不清楚请参看MSDN,代码仓促中完成,不免有疏漏,见谅。 声明:本文仅适合初级中的初级读者。 步骤一:建立ATL项目,取名为AtlSample 步骤二:选择默认选项,点击F

myiszjf的专栏 955

如何使用Microsoft Management Console编写Snap-in(一)

1. 安装WindowsXP-KB907265-x86-ENU.exe,安装之后会在"C:\Windows\System32\"目录下多出两个文件:microsoft.managementconsole.dll。4. 在编译目录运行installutil TestMMC3.dll命令,如果没有将mmcfxcommon.dll加入GAC,就需要将TestMMC3.dll放到"C:\Windows\System32\"中。如果你要使用.NET 1.1编写对于MMC2的Snap-in,可以参考MMC.NET。

biyusr的专栏 1028

ATL编写MMC SnapinSample 

关键字 MMC Snapin ATL原作者姓名 Fang 读者评分 15 评分次数 4 正文关键字:MMC Snapin ATL作者:Fang(fangguicheng@21cn.com)用ATL编写MMC SnapinSampleMMC相关的编程接口MMC 实现了下面的接口:IColumnData (new in MMC 1.2) IConsole2 IConsoleNameSpace2 IC

江湖·郎中·路 1350

Mmc编程

SV的界面使用到mmc(Microsoft Management Console) Mmc编程中:通过调用启动*.mmc文件,插件以dll文件形式存在(这里是在代码的lib库中),通过编程编译形成dll文件(这里是:lib/jcenv/libjcenvJPN) MmcMMC为插件提供通用的宿主环境,这些插件可以是由微软或第三方软件供应商提供的。插件提供实际的管理行为,MMC自身并不提供任何管...

weixin_30651273的博客 543

mmc管理控制台是做什么的!?

看看这个网站吧 很全的 http://www.microsoft.com/technet/prodtechnol/windowsserver2003/zh-chs/library/ServerHelp/cd4d1a55-f5f9-4257-9a7b-b43f1737fd80.mspx?mfr=true 使用 MMC 控制台 可能需要使用预配置的 MMC 控制台(一般称为“保存的控制台”,这些控制台

ptrunner的专栏 9910

Windows SDK笔记(一):Windows程序基本结构

  一、概述Windows程序具有相对固定的结构,对编写者而言,不需要书写整个过程,大部分过程由系统完成。程序中只要按一定的格式填写系统留给客户的那一小部分。所需要完成的有:窗口类的定义、窗口的建立、消息函数的书写、消息循环。 二、消息处理函数Windows程序是事件驱动的,对于一个窗口,它的大部分例行维护是由系统维护的。没个窗口都有一个消息处理函数。在消息处理函数中,对传入的消息进

flashsj的专栏 1855

Windows SDK笔记(五):非模式对话框

   一、概述使用DialgBox建立的对话框是“模式对话框”,只有关闭对话框后,程序的其他窗口才能进行操作。与此相对应,存在“非模式对话框”,对话框建立后,并不强制要求用户立即反应,而是与其他窗口同时接受用户操作。 二、建立非模式对话框使用CreateDialg建立。可以在WinMain中建立主窗口后建立,对话框句柄保存备用。hDlgModeless = CreateDialog (

flashsj的专栏 1646

COM技术初探(一)

   一、COM是一个更好的C++1、COM 是什么Don Box 说"COM IS LOVE"。COM 的全称是 Component Object Model 组件对象模型。 2、从 C++ 到 DLL 再到 COM2.1 C++如某一软件厂商发布一个类库(CMath四则运算),此时类库的可执行代码将成为客户应用中不可分割的一部分。假设此类库的所产生的机器码在目标可执行文件中占有4MB的

flashsj的专栏 1627

MFC类库之根基-CObject浅析

          CObject是大部分的MFC类的基类 为了完成MFC类的判断、动态生成、序列化等特殊功能,CObject中添加了特定的处理。 为了进一步增强对MFC类对象的理解,在此对CObject源码及相关宏定义进行分析。 (所附代码并非原始代码,为说明问题而作了删减。) 主要介绍了以下几方面内容: 一.CObject简要声明 class CObject{public:

flashsj的专栏 1515

Windows SDK笔记(二):在窗口上建立控件

 控件是子窗口,它们是系统已经定义好的窗口类,因此不需要注册、也不需要写消息处理函数。在主窗口得到WM_CREATE消息时,建立子窗口即可。 二、实例 //参数:窗口句柄,消息,消息参数,消息参数LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ //处理感兴趣的消息

flashsj的专栏 1466

COM技术初探(二)

  三、纯手工创建一个COM组件1、从建工程到实现注册在这一过程中我们将完成三个步骤:创建dll的入口函数,定义接口文件,实现注册功能1.1创建一个类型为win32 dll工程创建一个名为MathCOM的win32 dll工程。在向导的第二步选择"A smiple dll project"选项。当然如果你选择一个空的工程,那你自己完成DllMain定义吧。1.2 定义接口文件生成一个名为Mat

flashsj的专栏 1411

Windows SDK笔记(六):使用对话框资源建立窗口

  一、概述在Charles Petzold的书中,介绍了一种直接利用对话框资源建立主窗口的方法。使用这种方法,可以方便的在主窗口中安排子控件,而代码的其他部分跟用普通窗口时一样。我们知道,对话框是系统预先定义的“窗口类”,它有自己的窗口处理函数,我们自己写的对话框消息处理函数并不是真正的窗口消息处理函数。但我们可以在对话框模板脚本中,指定这个对话框使用我们自己定义的窗口类,而不是系统的对

flashsj的专栏 1359

Windows SDK笔记(四):模式对话框

  一、概述对话框是一种特殊的窗口,它依据对话框模板资源而建立。它与一般的窗口有些不同,很多过程由系统完成了,虽然用户还是要提供一个消息处理函数,但在此消息处理函数中,不需要将不关心的消息交由缺省消息处理函数。实际上,调用缺省处理的过程又系统完成。 二、对话框消息处理函数对话框也需要用户提供一个消息处理函数,但这个处理函数没有普通窗口的消息处理函数"权利大"。对话框是一种系统定义的“窗口类

flashsj的专栏 1318
下一篇: 一个程序员的成长的六个阶段
flashsj
博客等级 码龄25年 1粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值