初始化 Shell 扩展处理程序
Shell 扩展处理程序对象的大部分实现由其类型决定。 但是,存在一些常见元素。 本主题讨论由所有 Shell 扩展处理程序共享的实现的那些方面。
所有 Shell 扩展处理程序都是进程内组件对象模型 (COM) 对象。 必须为其分配 GUID 并按照注册 Shell 扩展处理程序中所述进行注册。 它们作为 DLL 实现,必须导出以下标准函数:
- DllMain。 DLL 的标准入口点。
- DllGetClassObject。 公开对象的类工厂。
- DllCanUnloadNow。 COM 调用此函数以确定对象是否为任何客户端提供服务。 否则,系统可以卸载 DLL 并释放关联的内存。
与所有 COM 对象一样,Shell 扩展处理程序必须实现 IUnknown 接口和 类工厂。 大多数还必须在 Windows XP 或更早版本中实现 IPersistFile 或 IShellExtInit 接口。 这些内容被 Windows Vista 中的 IInitializeWithStream、 IInitializeWithItem 和 IInitializeWithFile 所取代。 Shell 使用这些接口来初始化处理程序。
IPersistFile 接口必须通过以下方式实现:
- 图标处理程序
- 数据处理程序
- 删除处理程序
IShellExtInit 接口必须由以下项实现:
- 快捷菜单处理程序
- 拖放处理程序
- 属性表处理程序
本主题的其余部分将讨论以下主题:
实现 IPersistFile
IPersistFile 接口旨在允许从磁盘文件加载或保存到对象。 除了 IUnknown 之外,它还具有六种方法(其自己的五种方法)以及它从 IPersist 继承的 GetClassID 方法。 使用 Shell 扩展时, IPersist 仅用于初始化 Shell 扩展处理程序对象。 由于通常不需要从磁盘读取或写入磁盘,因此只有 GetClassID 和 Load 方法需要非ken 实现。
Shell 首先调用 GetClassID ,函数 (扩展处理程序对象的 CLSID) 返回类标识符。 然后,Shell 调用 Load 并传入两个值。 第一个 是 pszFile,是一个 Unicode 字符串,其中包含 Shell 要操作的文件或文件夹的名称。 第二个是 dwMode,它指示文件访问模式。 由于通常不需要访问文件, 因此 dwMode 通常为零。 方法根据需要存储这些值,供以后参考。
以下代码片段演示了典型的 Shell 扩展处理程序如何实现 GetClassID 和 Load 方法。 它旨在处理 ANSI 或 Unicode。 CLSID_SampleExtHandler是扩展处理程序对象的 GUID,CSampleShellExtension 是用于实现接口的类的名称。 m_szFileName和m_dwMode变量是专用变量,用于存储文件的名称和访问标志。
class CSampleShellExtension : public IPersistFile
{
// Method declarations not included
private:
WCHAR m_szFileName[MAX_PATH]; // The file name
DWORD m_dwMode; // The file access mode
}
IFACEMETHODIMP CSampleShellExtension::GetClassID(__out CLSID *pCLSID)
{
*pCLSID = CLSID_SampleExtHandler;
}
IFACEMETHODIMP CSampleShellExtension::Load(PCWSTR pszFile, DWORD dwMode)
{
m_dwMode = dwMode;
return StringCchCopy(m_szFileName, ARRAYSIZE(m_szFileName), pszFile);
}
// The implementation sample is continued in the next section.
实现 IShellExtInit
除了 IUnknown 之外,IShellExtInit 接口只有一种方法 IShellExtInit::Initialize。 方法具有三个参数,Shell 可以使用这些参数传递各种类型的信息。 传入的值取决于处理程序的类型,有些值可以设置为 NULL。
- pidlFolder 保存指向 PIDL) (项标识符列表的文件夹指针。 这是绝对 PIDL。 对于属性表扩展,此值为 NULL。 对于快捷菜单扩展,它是包含显示其快捷菜单的项的文件夹的 PIDL。 对于非默认拖放处理程序,它是目标文件夹的 PIDL。
- pDataObject 保存指向数据对象的 IDataObject 接口的指针。 数据对象保存 CF_HDROP格式的 一个或多个文件名。
- hRegKey 保存文件对象或文件夹类型的注册表项。
IShellExtInit::Initialize 方法根据需要存储文件名、IDataObject 指针和注册表项,以供以后使用。 以下代码片段演示 了 IShellExtInit::Initialize 的实现。 为简单起见,此示例假定数据对象仅包含单个文件。 通常,数据对象可能包含多个文件,其中每个文件都需要提取。
// This code continues the CSampleShellExtension sample shown in the
// "Implementing IPersistFile" section above.
class CSampleShellExtension : public IShellExtInit
{
// Method declarations not included
private:
// IDList of the folder for extensions invoked on the folder, such as
// background context menu handlers or nondefault drag-and-drop handlers.
PIDLIST_ABSOLUTE m_pidlFolder;
// The data object contains an expression of the items that the handler is
// being initialized for. Use SHCreateShellItemArrayFromDataObject to
// convert this object to an array of items. Use SHGetItemFromObject if you
// are only interested in a single Shell item. If you need a file system
// path, use IShellItem::GetDisplayName(SIGDN_FILESYSPATH, ...).
IDataObject *m_pdtobj;
// For context menu handlers, the registry key provides access to verb
// instance data that might be stored there. This is a rare feature to use
// so most extensions do not need this variable.
HKEY m_hRegKey;
}
// This method must be very efficient. Do not do any unnecessary work here.
// Use Initialize to acquire resources that will be used later.
IFACEMETHODIMP CSampleShellExtension::Initialize(__in_opt PCIDLIST_ABSOLUTE pidlFolder,
__in_opt IDataObject *pDataObject,
__in_opt HKEY hRegKey)
{
// In some cases, handlers are initialized multiple times. Therefore,
// clear any previous state here.
CoTaskMemFree(m_pidlFolder);
m_pidlFolder = NULL;
if (m_pdtobj)
{
m_pdtobj->Release();
}
if (m_hRegKey)
{
RegCloseKey(m_hRegKey);
m_hRegKey = NULL;
}
// Capture the inputs for use later.
HRESULT hr = S_OK;
if (pidlFolder)
{
m_pidlFolder = ILClone(pidlFolder); // Make a copy to use later.
hr = m_pidlFolder ? S_OK : E_OUTOFMEMORY;
}
if (SUCCEEDED(hr))
{
// If a data object pointer was passed into the method, save it and
// extract the file name.
if (pDataObject)
{
m_pdtobj = pDataObject;
m_pdtobj->AddRef();
}
// It is uncommon to use the registry handle, but if you need it,
// duplicate it now.
if (hRegKey)
{
LSTATUS const result = RegOpenKeyEx(hRegKey, NULL, 0, KEY_READ, &m_hRegKey);
hr = HRESULT_FROM_WIN32(result);
}
}
return hr;
}
信息提示自定义
可通过两种方式自定义信息提示。 一种方法是实现支持 IQueryInfo 的对象,然后在注册表中的适当子项下注册该对象, (请参阅下面的) 。 或者,可以指定要显示的固定字符串或特定文件属性的列表。
若要显示命名空间扩展的固定字符串,请在命名空间扩展的 CLSID 键下创建名为 InfoTip 的子项。 将该子项的数据设置为要显示的字符串。
HKEY_CLASSES_ROOT
CLSID
{CLSID}
InfoTip = InfoTip string for your namespace extension
若要显示某个文件类型的固定字符串,请在要为其提供信息提示的文件类型的 ProgID 键下面创建一个名为“信息提示”的子项。 将该子项的数据设置为要显示的字符串。
HKEY_CLASSES_ROOT
ProgID
InfoTip = InfoTip string for all files of this type
如果希望 Shell 在特定文件类型的信息提示中显示某些文件属性,请在该文件类型的 ProgID 键下创建一个名为 InfoTip 的子项。 将该子项的数据设置为规范属性名称或 {fmtid} 的分号分隔列表,其中 propname 是规范属性名称的 pid 对 ,而 {fmtid},pid 是 FMTID/PID 对。
HKEY_CLASSES_ROOT
ProgID
InfoTip = propname;propname;{fmtid},pid;{fmtid},pid
可以使用以下属性名称。
属性名称 | 说明 | 检索自 |
---|---|---|
作者 | 文档的作者 | PIDSI_AUTHOR |
标题 | 文档的标题 | PIDSI_TITLE |
主题 | 主题摘要 | PIDSI_SUBJECT |
评论 | 文档注释 | PIDSI_COMMENT 或文件夹/驱动器属性 |
PageCount | 页数 | PIDSI_PAGECOUNT |
名称 | 友好名称 | 标准文件夹视图 |
OriginalLocation | 原始文件的位置 | 公文包文件夹和回收站文件夹 |
DateDeleted | 删除日期文件 | 回收站文件夹 |
类型 | 文件类型 | 标准文件夹详细信息视图 |
大小 | 文件大小 | 标准文件夹详细信息视图 |
SyncCopyIn | 与 OriginalLocation 相同 | 与 OriginalLocation 相同 |
修改时间 | 上次修改日期 | 标准文件夹详细信息视图 |
创建 | 创建日期 | 标准文件夹详细信息视图 |
已访问 | 上次访问日期 | 标准文件夹详细信息视图 |
InFolder | 包含文件的目录 | 文档搜索结果 |
级别 | 搜索匹配的质量 | 文档搜索结果 |
FreeSpace | 可用存储空间 | 磁盘驱动器 |
NumberOfVisits | 访问次数 | 收藏夹文件夹 |
特性 | 文件属性 | 标准文件夹详细信息视图 |
Company | 公司名称 | PIDDSI_COMPANY |
类别 | 文档类别 | PIDDSI_CATEGORY |
版权信息 | 媒体版权 | PIDMSI_COPYRIGHT |
HTMLInfoTipFile | HTML 信息提示文件 | 文件夹的Desktop.ini文件 |
相关主题