第 ⑥ 章 · 属性处理器(IPropertyStore)

用一个 IPropertyStore 统一供数据给详细信息列、信息提示、分组和搜索——这是老“列处理器 IColumnProvider(Vista 已移除)”的现代替代;讲 PROPERTYKEY、系统属性与自定义 .propdesc schema。

作者 David更新于

老教程里有一章叫“列处理器”(IColumnProvider),用来往资源管理器的详细信息视图加自定义列。这个接口在 Windows Vista 就被彻底移除了。它的现代替代——而且能力大得多——是属性处理器 IPropertyStore。

关键变化:过去详细信息列、信息提示、属性页各写一套;现在一个属性处理器统一供数据,同时喂给:详细信息列、信息提示(infotip)、分组、排序、搜索索引、属性页。写一处,处处生效。

本例给自定义扩展 .shdemo 暴露一个属性。配套代码:06-property。

属性 = PROPERTYKEY + 值

属性系统里每个属性由一个 PROPERTYKEY(一个 {FMTID} + 一个整数 PID)唯一标识,值是 PROPVARIANT。系统预定义了几百个规范属性(System.Author、System.Comment、System.Size…),头文件 propkey.h 里是 PKEY_Author、PKEY_Comment 这些常量。

IPropertyStore 就五个方法:

PropertyStore.cpp(节选)
IFACEMETHODIMP PropertyStore::GetCount(DWORD* c) { *c = 1; return S_OK; }          // 我暴露几个属性
IFACEMETHODIMP PropertyStore::GetAt(DWORD i, PROPERTYKEY* k) {                     // 第 i 个是哪个键
    if (i != 0) return E_INVALIDARG;
    *k = PKEY_Comment; return S_OK;
}
IFACEMETHODIMP PropertyStore::GetValue(REFPROPERTYKEY key, PROPVARIANT* pv) {      // 取值
    PropVariantInit(pv);
    if (IsEqualPropertyKey(key, PKEY_Comment)) {
        wchar_t buf[96];
        StringCchPrintfW(buf, ARRAYSIZE(buf), L"演示属性:该文件 %llu 字节", m_size);
        return InitPropVariantFromString(buf, pv);
    }
    return S_OK;   // 未知属性返回 VT_EMPTY
}
IFACEMETHODIMP PropertyStore::SetValue(REFPROPERTYKEY, REFPROPVARIANT) { return STG_E_ACCESSDENIED; } // 只读
IFACEMETHODIMP PropertyStore::Commit() { return STG_E_ACCESSDENIED; }

内容还是通过 IInitializeWithStream 以流的形式拿到(和缩略图、属性同一套现代初始化方式)。

用系统预定义属性(如 PKEY_Comment)拿来即用。要暴露自定义属性(比如“项目编号”),得写一份 .propdesc XML schema,用 PSRegisterPropertySchema 注册,属性才有规范名、类型和本地化显示名,才能作为列/分组项出现。

注册

属性处理器注册在 HKLM 的属性系统里,按扩展名绑定:

HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\PropertySystem\PropertyHandlers\.shdemo
    (默认) = {CLSID}
RegWriteString(HKEY_LOCAL_MACHINE,
    L"SOFTWARE\\...\\PropertySystem\\PropertyHandlers\\.shdemo", nullptr, clsidStr);

属性处理器跑在索引器 / 属性系统宿主里、且会被系统缓存。别在里面做重活;写属性(可写处理器)时要正确实现 SetValue/Commit 的事务语义。改扩展名绑定后可能要重启资源管理器或重建索引才生效。

迁移提示:从列处理器到属性处理器

如果你在维护老代码里的 IColumnProvider:它在 Vista 起就不再被调用了。把“每列一个值”改写成“每个 PROPERTYKEY 一个值”的属性处理器,再在文件类型上配置要显示哪些列(System.PropList.* 或属性 schema),即可恢复并增强原来的详细信息列功能。

参考

本页目录