Windows Shell扩展(Shell Extensions)指南 联系客服

发布时间 : 星期日 文章Windows Shell扩展(Shell Extensions)指南更新完毕开始阅读ad740101bd64783e09122bfb

Windows Shell扩展(Shell Extensions)指南

文章概要: ? Shell扩展一种com对象可以为window浏览器提供各种扩展的功能。Windows中有多种的扩展类型,但是对应的文档的介绍却很少。完成的Shell扩展方法可以查阅 Visual C++ Windows Shell Programming(ISBN 1861001843),如果你没有阅读过这本书而希望做相关的扩展这篇文档将可以帮到你,希望使你可以了解扩展shell的方法。 Shell扩展一种com对象可以为window浏览器提供各种扩展的功能。Windows中有多种的扩展类型,但是对应的文档的介绍却很少。完成的Shell扩展方法可以查阅Visual C++ Windows Shell Programming(ISBN 1861001843),如果你没有阅读过这本书而希望做相关的扩展这篇文档将可以帮到你,希望使你可以了解扩展shell的方法。 阅读本文档需要对Com有所了解,如果你还不清楚,可以观看VCKBase的Com视频教程。 本系列我将会分为几块来进行讲解,第一部分我将会介绍什么是Shell扩展(Shell Extensions),并实现一个简单的扩展系统右键菜单的例子。 Shell Extension包含两个部分,Shell指的是Windows文件浏览器,extension指的是在文件浏览器上进行功能的扩展,比如右键打开一个word文档。因此Shell扩展动态库实际就是一个为文件浏览器提供额外功能的Com库。 一个扩展动态库实现了与文件浏览器的通讯接口并提供了进程内的服务。ATL是进行扩展最简单的工具。 Shell扩展的种类如下。 类型 内容 可扩展实现功能 1

内容菜单 属性页 拖拽 展 文件浏览器的右键菜单 右键属性也进行扩在右键菜单中增加新的功能呢 类似WinRar中属性页查看压缩比例 拖拽和释放文件 鼠标悬浮的提示文本 修改拖拽的行为 查询 定制提示文本的内容 最常见的右键菜单的扩展时如HaoZip WinRar这样的软件在右键中自定义增加的选项了。 此外提供了拖拽的右键扩展 IShellExtInit接口只有一个方法Initialize(),函数原型是 2

1.HRESULT IShellExtInit::Initialize ( LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEYhProgID )

文件浏览器进程使用这个方法给我们提供信息,pidlFolder是一个PIDL对象,指向操作文件的目录。pDataObj是一个IDataObject接口指针,我们可以获取文件的名称,hProgID是一个HKEY,用于我们访问包含我们dll信息的注册表。

首页我们修改我们COM对象的头文件,SimpleShellExt.h,修改集成关系

1.class ATL_NO_VTABLE

CSimpleShlExt : public CComObjectRootEx, public CComCoClass, publicISimpleShlExt, public IShellExtInit

COM_MAP宏告诉ATL我们的com对象可以得到哪种接口,接着我们添加IShellExtInit的接口Initialize(),并增加一个变量用来存储文件名称

1.protected: TCHAR m_szFile[MAX_PATH]; public: // IShellExtInit STDMETHODIMP Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY);

在SimpleShellExt.cpp中我们增加Initialize的实现

这里我们做的工作是在右键的时候获取文件的名称,并通过一个MessageBox进行弹出。

我们通过pDataObj对象得到这些文件,这里简单演示获取一个文件的方法

与处理Windows的拖拽文件的方式类似我们使用DragQueryFile来获取文件

1.HRESULT CSimpleShlExt::Initialize(...){FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };STGMEDIUM stg = { TYMED_HGLOBAL };HDROP hDrop; // Look for CF_HDROP data in the data object. If there // is no such data, return an error back to Explorer. if

( FAILED( pDataObj->GetData ( &fmt, &stg ) )) return E_INVALIDARG; // Get a pointer to the actual data. hDrop = (HDROP) GlobalLock ( stg.hGlobal ); // Make sure it worked. if ( NULL == hDrop ) return E_INVALIDARGUINT uNumFiles = DragQueryFile ( hDrop, 0xFFFFFFFF, NULL, 0 );HRESULT hr = S_OK;

3

if ( 0 == uNumFiles ) { GlobalUnlock ( stg.hGlobal ); ReleaseStgMedium ( &stg ); return E_INVALIDARG; } // Get the name of the first file and store it in our // member variable m_szFile. if ( 0 == DragQueryFile ( hDrop, 0, m_szFile, MAX_PATH ) ) hr = E_INVALIDARG; GlobalUnlock ( stg.hGlobal ); ReleaseStgMedium ( &stg ); return hr;}

需要注意的是我们没有做任何的异常检查,出现任何的异常后会导致文件浏览进程的崩溃。

接着我们通过扩展接口IContextMenu,是的我们可以扩展菜单项目 接着我们增加IContextMenu接口的支持

1.class ATL_NO_VTABLE

CSimpleShlExt : public CComObjectRootEx, public CComCoClass, publicIShellExtInit, public IContextMenu{ BEGIN_COM_MAP(CSimpleShlExt)

COM_INTERFACE_ENTRY(IShellExtInit) COM_INTERFACE_ENTRY(IContextMenu) END_COM_MAP(

增加IContextMenu的接口

1.public: // IContextMenu STDMETHODIMP GetCommandString(UINT, UINT, UINT*, LPSTR, UINT); STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO); STDMETHODIMP QueryContextMenu(HMENU, UINT, UINT, UINT, UINT);

在QueryContextMenu中我们可以修改菜单项目

1.HRESULT IContextMenu::QueryContextMenu

( HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd,UINT uidLastCmd, UINT uFlags );

Hmenu指向当前内容菜单的句柄,uMenuIndex是我们可以增加项目的起始索引。 UidFirstCmd和uidLastCmd是菜单id范围值 uFlags标示菜单产生的原因

在实现方法中我们向菜单插入了一个新的菜单项目

1.HRESULT CSimpleShlExt::QueryContextMenu

( HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd,UINT uidLastCmd, UINT uFlags ){ // If the flags include CMF_DEFAULTONLY then we shouldn't do

4