分类:
2008-10-13 16:42:56
Windows 2000 UI 新特点之一:信息条提示(Infotip)
原文参见:
编译/
类型 | 类型说明 | 适用于 | 版本 | 有关的接口 | 描述 |
Context Menu | 上下文菜单 | 文件类和外壳对象 | Windows 9x | IContextMenu、IContextMenu2、IContextMenu3
|
允许在外壳对象的上下文菜单中增加新的才单项 |
Right drag and drop | 右拖拽 | 文件类和外壳对象 | Windows 9x | IContextMenu、IContextMenu2、IContextMenu3 | 允许在右拖拽后出现的上下文菜单中增加新的才单项 |
Drawing shell Icons | 绘制外壳图标 | 文件类和外壳对象 | Windows 9x | IExtractIcon | 对于一个文件类来说,可以选择文件在运行时应该显示那个图标 |
Property Sheet | 属性页 | 文件类和外壳对象 | Windows 9x | IShellPropSheetExt | 向文件类属性对话框中加入另外的属性表页。也适用于控制面板应用 |
Left drag and drop | 左拖拽 | 文件类和外壳对象 | Windows 9x | IDropTarget | 决定在外壳内用鼠标左键拖拽一个对象到另一个对象上时做什么 |
Clipboard | 剪贴板 | 文件类和外壳对象 | Windows 9x | IDataObject | 定义如何将对象拷贝到剪贴板以及如何从剪贴板吸取对象 |
File Hook | 文件钩 | Windows 9x | ICopyHook | 控制整个外壳内的任何文件操作。您可以允许或拒绝这些对文件的操作,但不会通知您成功或失败 | |
Program Execution | 外壳执行程序 | 资源管理器 | 桌面更新 | IShellExecuteHook | 拦截(钩)外壳内任何程序的执行 |
Infotip | 信息条提示 | 文件类和外壳对象 | 桌面更新 | IQueryInfo | 当鼠标移到某个文件类型文档上时显示简短文本信息 |
Column | 栏目 | 文件夹 | Windows 2000 | IColumnProvider | 在资源管理器“查看”菜单的“详细资料”视图中增加新的栏目 |
Icon Overlay | 图标覆盖 | 资源管理器 | Windows 2000 | IShellIconOverlay | 用定制的图像覆盖图标 |
Search | 搜索 | 资源管理器 | Windows 2000 | IContextMenu | 在“开始”菜单的“搜索”菜单项中增加新的搜索入口 |
Cleanup | 清除 | 清除管理器 | Windows 2000 | IEmptyVolumeCache2 | 向清除管理器中增加新的入口来恢复磁盘空间 |
例如,给定某一类文件,外壳扩展允许您添加新的项目到上下文菜单或插入一个附加的属性页到标准属性对话框。虽然可以用任何支持COM组件的工具编写外壳扩展代码,但大多数外壳扩展都是在ATL框架中用C++编写的。
如果您使用VB来做同样的事情会有一些困难,因为您找不到专门的向导或者可以直接使用的设计器来帮助您编写支持特定COM接口的组件。您不得不写一个类型库来描述接口,然后在工程中引用这个类型库并使用实现关键字来声明只对此接口的支持。在VB6.0的光盘中可以找到一个用VB编写的外壳扩展例子。
外壳扩展常常与文档类有关,也就是说外壳扩展的功能只适用于具有某些扩展名的文件。更详细的信息可以参考MSDN库和有关Windows外壳编程的书籍。
有许多用户界面特点已在桌面更新(Desktop Update)中引入----Windows 9x和Windows
NT4.0中有各自的外壳扩展。桌面更新是随IE4.0和Windows 98 一同而来。但应注意桌面更新不是IE5.0的一部分。所以如果您想在NT4.0上安装,需要先安装IE4.0,必须选中桌面更新选项,IE5.0将更新NT4.0和Windows
95现存的设置,否则将不会安装桌面更新。
编写信息条提示(Infotip)外壳扩展
一个典型的外壳扩展应用是帮助用户对文档进行分类。以BMP文件为例,当从文件列表中选中BMP文件时,桌面更新(外壳版本4.72+)会以小图方式提供这个BMP文件的预览,但是它不提供BMP文件的大小及颜色信息。如果您对系统外壳稍加扩展就可以使您的应用程序对BMP文件作更细致的处理,这将大大方便用户的使用。
第一个想到的方案便是为BMP文件添加新的属性页。实际上,这不是最好的方法,因为用户要单击右键,选中“属性”菜单项,再选择正确的标签读取信息。为了达到同样的目的,最佳方法是使用新的信息条提示(Infotips)特性。
信息提示的作用是当鼠标移到某种类型的文件上时,让工具提示(tooltip)控件显示一个简短的文本,这个文本片段提供了关于特定文件的属性细节信息。对于Excel和Word文档,信息提示特性是自动使能的。它显示文档的标题、作者和主题。信息条提示特性是针对特殊类型文件的外壳扩展,其注册方案也很独特。信息条提示扩展接收对当前选中文件的引用,然后作处理以便抽取需要的信息。
图二 BMP文件的 Infotip
图二显示了一个BMP文件的信息提示扩展,为了建立这个扩展,您需要创建一个进程内的服务器,实现IQueryInfo和IPersistFile接口。IQueryInfo用来给外壳提供运行时的 文本。IPersistFile由资源管理器使用,让扩展知道当前鼠标指针指向的文件。本文的例子代码定义了一对从上述两个接口派生的最小限度的ATL基类(IQueryInfoImpl.h 和IPersistFileImpl.h),可以使用它们来建立更专业的类。在源代码中您还能看到嵌入到这个外壳的其它相关类的声明。下面是ATL基类定义:
实现对位图文件的信息提示条(BMP Infotip) // IPersistFileImpl.h #includePersistFile的Load方法将文件名存储在m_szFile成员变量中,这个方法在初始化过程期间被资源管理器隐含调用。IqueryInfo只包含两个函数,其中GetInfoFlags目前还不被支持并且必须返回E_NOTIMPL。实际上,一旦您实现了IQueryInfoImpl.h 和IPersistFileImpl.h提供的最小限度的派生类,写一个信息条提示扩展是很容易的,先建立一个新的ATL进程内对象并实现IQueryInfo::GetInfoTip方法:class ATL_NO_VTABLE IPersistFileImpl : public IPersistFile{ public: TCHAR m_szFile[MAX_PATH]; // IUnknown STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) = 0; _ATL_DEBUG_ADDREF_RELEASE_IMPL(IPersistFileImpl) // IPersistFile STDMETHOD(Load)(LPCOLESTR wszFile, DWORD dwMode){ USES_CONVERSION; _tcscpy(m_szFile, OLE2T((WCHAR*)wszFile)); return S_OK; }; STDMETHOD(GetClassID)(LPCLSID){ return E_NOTIMPL; } STDMETHOD(IsDirty)(VOID){ return E_NOTIMPL; } STDMETHOD(Save)(LPCOLESTR, BOOL){ return E_NOTIMPL; } STDMETHOD(SaveCompleted)(LPCOLESTR){ return E_NOTIMPL; } STDMETHOD(GetCurFile)(LPOLESTR FAR*){ return E_NOTIMPL; } }; // IQueryInfoImpl.h #include #include class ATL_NO_VTABLE IQueryInfoImpl : public IQueryInfo{ public: // IUnknown STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) = 0; _ATL_DEBUG_ADDREF_RELEASE_IMPL(IQueryInfoImpl) // IQueryInfo::GetInfoTip STDMETHOD(GetInfoTip)(DWORD dwFlags, LPWSTR *ppwszTip){ wcscpy(*ppwszTip, L"InfoTip"); return S_OK; } // IQueryInfo::GetInfoFlags STDMETHOD(GetInfoFlags)(LPDWORD pdwFlags){ *pdwFlags = 0; return E_NOTIMPL; } }; // BmpTip.h : Declaration of the CBmpTip coclass #ifndef __BMPTIP_H_ #define __BMPTIP_H_ #include "resource.h" // main symbols #include "comdef.h" // GUIDs #include "IPersistFileImpl.h" // IPersistFile #include "IQueryInfoImpl.h" // IQueryInfo // CBmpTip class ATL_NO_VTABLE CBmpTip : public CComObjectRootEx , public CComCoClass , public IQueryInfoImpl, public IPersistFileImpl, public IDispatchImpl { public: CBmpTip(){ HRESULT hr; hr = SHGetMalloc(&m_pAlloc); if (FAILED(hr)) m_pAlloc = NULL; } ~CBmpTip(){ m_pAlloc->Release(); } DECLARE_REGISTRY_RESOURCEID(IDR_BMPTIP) DECLARE_PROTECT_FINAL_CONSTRUCT() BEGIN_COM_MAP(CBmpTip) COM_INTERFACE_ENTRY(IBmpTip) COM_INTERFACE_ENTRY(IQueryInfo) COM_INTERFACE_ENTRY(IPersistFile) COM_INTERFACE_ENTRY(IDispatch) END_COM_MAP() // IQueryInfo public: STDMETHOD(GetInfoTip)(DWORD, LPWSTR*); private: STDMETHOD(GetBitmapInfo)(CComBSTR*); LPMALLOC m_pAlloc; }; #endif //__BMPTIP_H_
HRESULT CBmpTip::GetInfoTip(DWORD dwFlags, LPWSTR* ppwszTip)参数dwFlags目前不使用,ppwszTip是一个指向Unicode串缓冲的指针,用来返回运行时关于文件的文本。要注意ppwszTip缓冲必须使用标准的外壳内存分配器起来为它分配内存。这个缓冲由应用程序负责分配内存,由外壳来释放分配的内存。为了保证所发生的一切都是线程安全的,请使用SHGetMalloc来获得外壳内存分配器(一个IMalloc对象)的指针。然后,使用IMalloc的Alloc方法分配需要的内存并以Unicode方式存储信息条提示文本。
CComBSTR bstrInfo; GetBitmapInfo((CComBSTR *)&bstrInfo); *ppwszTip = (WCHAR*) m_pAlloc->Alloc( (bstrInfo.Length() +1) * sizeof(WCHAR) ); if (*ppwszTip) wcscpy(*ppwszTip, (WCHAR*)(BSTR)bstrInfo);GetBitmapInfo是一个内部成员,它只是准备一个串来存放图像的大小和颜色。为了得到这个信息,这个函数打开BMP文件并读取bitmap文件的头。
HKCR这个键的缺省值必须是实现COM对象的CLISID。这个地方的CLSID是IqueryInfo接口的IID,而不是BMP文件的文件类。这就是为什么信息条提示扩展以非标准方式进行注册的原因。另一方面,这个注册方案适用于任何一个处理BMP文件的注册应用程序。实际上,处理某个文件类的应用将自身注册为缺省处理程序的话,它也能改变类名,也能使所有的注册扩展无效。如果MS Paint是缺省处理程序的话,用于BMP文件的类名就是PaintPicture。如果使用另一个程序编辑浏览bitmaps,用于BMP文件的类名可能就不是PaintPicture。
\.bmp \shellex \{00021500-0000-0000-C000-000000000046}
HKLM \SOFTWARE \Microsoft \Windows \CurrentVersion \Shell Extensions \Approved在这个键下,用外壳扩展的CLSID名字创建一个新串值并给出一个描述文本。
图四 DLL 和 EXE 文件的 Infotip
Visual Studio 6.0 中有一个很好的工具: Dependency Walker,这个工具也有与信息条提示一样的功能。不同是这个工具是一个独立的可执行程序,你必须得从上下文菜单来运行。
如果您只想知道某个可执行文件依赖的主动态链接库列表,使用本文的外壳扩展就足够了。为了获得静态链接库的列表,本文的代码中使用了ImageHLP
API,关于这个API,我将在另文中说明。此外,代码还使用了BindImageEx来请求每个输入函数的有效地址。为此,BindImageEx邦定可执行文件图像并为每一个输入库和函数调用回调函数。您要做的全部工作是写一个回调函数将模块名简单地连结为一个串。
从属列表很有用,但它显示的可能不是每次当您的鼠标移到某个DLL或EXE文件上时您想要的信息。如果能用一个逻辑变量来控制信息条提示特性的使能和取消那不是更好吗?为了实现这个功能,既可以利用注册表,也可以用INI文件来存储这个控制变量的值,但有一个问题是:如何改变存储在注册表或INI文件中的这个值?使用注册表编辑器或者写字板当然可以,但那未免土了点。如果外壳扩展是应用的一部分,那么为应用程序做一个参数选项对话框应该是最好的解决办法。
--------------------next---------------------