Windows Shell扩展编程完全指南.docx
- 文档编号:3233380
- 上传时间:2022-11-20
- 格式:DOCX
- 页数:14
- 大小:26.93KB
Windows Shell扩展编程完全指南.docx
《Windows Shell扩展编程完全指南.docx》由会员分享,可在线阅读,更多相关《Windows Shell扩展编程完全指南.docx(14页珍藏版)》请在冰豆网上搜索。
WindowsShell扩展编程完全指南
第一节一步步教你如何编写Shell扩展
所谓的Shell扩展就是能够添加某种功能到WindowsShell的COM对象。
Windows里有着各种各样的扩展,但关于Shell扩展的原理以及如何编写Shell扩展的文档却很少。
如果你想深入地了解Shell各方面的细节,我特别推荐DinoEsposito的著作《VisualC++WindowsShellProgramming》。
但对于那些没有这本书的,或只对Shell扩展本身感兴趣的朋友,我写了这个编程指南希望能够帮助你理解怎样编写Shell扩展。
该指南假设你理解COM和ATL的基本原理及应用。
第一节对Shell扩展进行了概括性的介绍,并给出了一个上下文菜单的扩展以引起你对以后各章的兴趣.
但Shell扩展到底是什么玩意呢?
"Shell扩展"从字面上分两个部分,Shell与Extension。
Shell指WindowsExplorer,而Extension则指由你编写的当某一预先约定好的事件(如在以.doc为后缀的文件图标上单击右键)发生时由Explorer调用执行的代码。
因此一个Shell扩展就是一个为Explorer添加功能的COM对象。
Shell扩展是个进程内服务器(运行在Explorer进程内),它实现了一些接口来处理与Explorer的通信。
ATL在我看来是设计Shell扩展最简单最快捷的方法,如果没有它,你就不得不一遍又一遍地编写繁琐的QueryInterface()及AddRef()代码.
另外,在WindowsNT和2000上调试Shell扩展相对比较容易一些,这我以后会讲到的。
Shell扩展有很多种类型,每种类型都在各自不同的事件发生时被调用运行,但也有一些扩展的类型和调用情形是非常相似的。
类型
何时被调用
应该作些什么
Contextmenu
扩展处理器
用户右键单击文件或文件夹对象时,
或在一个文件夹窗口中的背景处单击右键时(要求shell版本为4.71+)
添加菜单项到上下文菜单中
Propertysheet
扩展处理器
要显示一个文件对象的属性框时
添加定制属性页到属性表中
Draganddrop
扩展处理器
用户用右键拖放文件对象到文件夹窗口或桌面时
添加菜单项到上下文菜单中
Drop扩展处理器
用户拖动Shell对象并将它放到一个文件对象上时
任何想要的操作
QueryInfo扩展处理器(需要shell版本4.71+)
用户将鼠标盘旋于文件或其他Shell对象的图标上时
返回一个浏览器用于显示在提示框中的字符串
现在你可能想知道Shell扩展到底是什么样的.如果你安装了WinZip(有谁没装的吗?
),它就包含了多种的Shell扩展,其中也就有上下文菜单扩展.
下图是WinZip8为压缩文件对象添加的定制菜单项:
WinZip编写了添加菜单项的代码,提供了浏览器状态栏上的菜单项帮助提示,并在用户选择一个菜单命令时执行相应的操作。
WinZip还包括一个拖放目标扩展处理器.该类型与上下文菜单十分类似,但它是在用户用右键拖放文件时被触发的.
下图是WinZip定制的拖放菜单:
Shell扩展的类型很多,而且微软也正不断地在每一新版本的Windows中加入更多的扩展类型.
现在让我们把注意力放在上下文菜单上,因为它们易于编写,效果也很明显(这能马上满足你).
在我们编写代码之前,先说一下一些简化编码及调试工作的技巧.
当shell扩展被Explorer调用后,它会在内存中呆上一段时间,这会使你无法重新编译并生成Shell扩展DLL文件.
要让Explorer更迅速地卸载Shell扩展执行文件,需要创建如下注册表项:
HKLM\Software\Microsoft\Windows\CurrentVersion\Explorer\AlwaysUnloadDLL
并将其值设为"1".对于Win9x,这是你能做的最好的方法。
而在WinNT/2000上,你可以找到如下键:
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer
并创建一个名为DesktopProcess的DWORD值1.这会使桌面和任务栏运行在同一个进程中,而其他每一个Explorer窗口都运行在它自己的每一个进程内.也就是说,你可以在单个的Explorer窗口内进行调试,而后只要你关闭该窗口,你的DLL就会被马上卸载,这就避免了因为DLL正被Windows使用而无法替换更新.而如果不幸出现这种情况,你就不得不注销登录后再重新登录进Windows从而强制卸载使用中的Shell扩展DLL.
我将在稍后解释如何在Win9x中进行调试的细节.
开始编写上下文菜单–它该做些什么?
开头先让我们做简单一些,只弹出一个对话框以表明当前的扩展能够正常地工作.
我们把扩展关联到.TXT文件,因此当用户右键单击文本文件对象时扩展就会被调用.
使用AppWizard开始
好吧,让我们开始吧!
什么?
我还没告诉你怎样使用那些神秘的shell扩展接口?
别着急,我会边进行边解释的。
我觉得先解释一下一个概念再紧接着说明示例代码,对理解例子程序会更简单一些.当然我也可以把所有的东西都先解释完,然后再解释代码,但我觉得这样做不能吸引人的注意力。
不管怎么样,向VC开火,开始!
运行AppWizard,生成一个名为SimpleExt的ATLCOM工程.保留所有默认的设置选项,点击”完成”.
现在我们已经有了一个空的ATL工程,它可以编译并生成一个DLL,但我们还需要添加Shell扩展的COM对象.
在ClassView中,右击SimpleExtclasses条目,选择NewATLObject.
在ATLObjectWizard里,第一页默认已经选择了SimpleObject,所以单击Next即可.
在第二页中,在ShortName文本框里输入SimpleShlExt,点击OK.(其余的文本框会自动填充完.)
这样就创建了一个名为CSimpleShlExt的类,其包含了实现COM对象最基本的代码.我们将在这个类中加入我们自己的代码.
初始化接口
当我们的shell扩展被加载时,Explorer将调用我们所实现的COM对象的QueryInterface()函数以取得一个IShellExtInit接口指针.
该接口仅有一个方法Initialize(),其函数原型为:
HRESULTIShellExtInit:
:
Initialize(LPCITEMIDLISTpidlFolder,LPDATAOBJECTpDataObj,HKEYhProgID);
Explorer使用该方法传递给我们各种各样的信息.
PidlFolder是用户所选择操作的文件所在的文件夹的PIDL变量.(一个PIDL[指向ID列表的指针]是一个数据结构,它唯一地标识了在Shell命名空间的任何对象,一个Shell命名空间中的对象可以是也可以不是真实的文件系统中的对象.)
pDataObj是一个IDataObject接口指针,通过它我们可以获取用户所选择操作的文件名。
hProgID是一个HKEY注册表键变量,可以用它获取我们的DLL的注册数据.
在这个简单的扩展例子中,我们将只使用到pDataObj参数.
要添加这个接口进COM对象,先打开SimpleShlExt.h文件,然后加入下列标红的代码:
#include"shlobj.h"
#include"comdef.h"
classATL_NO_VTABLECSimpleShlExt:
publicCComObjectRootEx,
publicCComCoClass,
publicIDispatchImpl,
publicIShellExtInit
BEGIN_COM_MAP(CSimpleShlExt)
COM_INTERFACE_ENTRY(ISimpleShlExt)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IShellExtInit)
END_COM_MAP()
COM_MAP是ATL实现QueryInterface()机制的宏,它包含的列表告诉ATL其它外部程序用QueryInterface()能从我们的COM对象获取哪些接口.
接着,在类声明里,加入Initialize()的函数原型.
另外我们需要一个变量来保存文件名:
protected:
TCHARm_szFile[MAX_PATH];
public:
//IShellExtInit
STDMETHOD(Initialize)(LPCITEMIDLIST,LPDATAOBJECT,HKEY);
然后,在SimpleShlExt.cpp文件中,加入该函数方法的实现定义:
HRESULTCSimpleShlExt:
:
Initialize(LPCITEMIDLISTpidlFolder,LPDATAOBJECTpDataObj,HKEYhProgID)
我们要做的是取得被右击选择的文件名,再把该文件名显示在弹出消息框中。
可能会有多个文件同时被选择右击,你可以用pDataObj接口指针获取所有的文件名,但现在为简单起见,我们只获取第一个文件名.
文件名的存放格式与你拖放文件到带WS_EX_ACCEPTFILES风格的窗口时使用的文件名格式是一样的。
这就是说我们可以使用同样的API来获取文件名:
DragQueryFile().
首先我们先获取包含在IdataObject中的数据句柄:
{
FORMATETCfmt={CF_HDROP,NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL};
STGMEDIUMstg={TYMED_HGLOBAL};
HDROPhDrop;
//在数据对象内查找CF_HDROP型数据.
if(FAILED(pDataObj->GetData(&fmt,&stg)))
{
//Nope!
Returnan"invalidargument"errorbacktoExplorer.
returnE_INVALIDARG;
}
//获得指向实际数据的指针
hDrop=(HDROP)GlobalLock(stg.hGlobal);
//检查非NULL.
if(NULL==hDrop)
{
returnE_INVALIDARG;
}
请注意错误检查,特别是指针的检查。
由于我们的扩展运行在Explorer进程内,要是我们的代码崩溃了,Explorer也会随之崩溃.在Win9x上,这样的一个崩溃可能导致需要重启系统.
所以,现在我们有了一个HDROP句柄,我们就可以获取我们需要的文件名了:
//有效性检查–
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Windows Shell扩展编程完全指南 Shell 扩展 编程 完全 指南