【发布时间】:2018-11-07 10:22:17
【问题描述】:
短版
IShellFolder.CompareIDs的SHCIDS_ALLFIELDS标志是什么意思?
加长版
在 Windows 95 中,Microsoft 引入了 shell。与其假设计算机是由文件和文件夹组成的,不如说它是由一个抽象的命名空间项组成的。
- 而不是从驱动器根目录开始的路径(例如
C:\Documents & Settings\Ian) - 路径从命名空间的根目录开始 (
Desktop)
为了容纳不是文件和文件夹的东西(例如网络打印机、控制面板、我的 Android 手机):
- 您不要使用由反斜杠分隔的一系列名称(例如 C: \ Users \ Ian )
- 你使用 pidls,一系列不透明的 blob(例如 Desktop This PC OS (C:) 用户 伊恩)
PIDL 是不透明的 blob,每个 blob 仅对生成它的文件夹有意义。
为了扩展(或使用)shell 命名空间,您实现(或调用)一个 IShellFolder 接口。
IShellFolder 的方法之一用于要求命名空间扩展比较 到 ID 列表(PIDLs):
IShellFolder::CompareIDs 方法
根据项目标识符列表确定两个文件对象或文件夹的相对顺序。
HRESULT CompareIDs( [in] LPARAM lParam, [in] PCUIDLIST_RELATIVE pidl1, [in] PCUIDLIST_RELATIVE pidl2 );
多年来,LPARAM 被记录为几乎始终为 0。来自shlobj.h c。 1999:
// IShellFolder::CompareIDs(lParam, pidl1, pidl2)
// This function compares two IDLists and returns the result. The shell
// explorer always passes 0 as lParam, which indicates "sort by name".
// It should return 0 (as CODE of the scode), if two id indicates the
// same object; negative value if pidl1 should be placed before pidl2;
// positive value if pidl2 should be placed before pidl1.
所以你比较了两个 ID 列表——无论是什么意思,我们都完成了。
Windows 2000 添加了额外的排序选项标志
从 shell 的 版本 5 开始,LPARAM 的高 16 位现在可以包含额外的标志来控制 IShellFolder 应如何处理排序。
来自ShObjIdl.idl c。 Windows 8.1 SDK:
// IShellFolder::CompareIDs lParam flags
// *these should only be used if the folder supports IShellFolder2*
//
// SHCIDS_ALLFIELDS
//
// only be used in conjunction with SHCIDS_CANONCALONLY or column 0.
// This flag requests that the folder test for *pidl identity*, that is
// "are these pidls logically the same". This implies that cached fields
// in the pidl that would distinguish them should be tested.
// Without this flag, you are comparing the *object* s the pidls refer to.
//
// SHCIDS_CANONICALONLY
//
// This indicates that the sort should be *the most efficient sort possible*, the implication
// being that the result will not be displayed to the UI: the SHCIDS_COLUMNMASK portion
// of the lParam can be ignored. (Before we had SHCIDS_CANONICALONLY
// we assumed column 0 was the "efficient" sort column.)
注意这里的重点:
- SHCIDS_CANONICALONLY 旨在成为我们拥有的最快最有效的排序方式
- 从 UI 可用性的角度来看,它不必是合乎逻辑的;它必须是一致的
正如 Raymond Chen 指出的那样,它是the moral equivalent of a Unicode ordinal comparison。
头文件甚至指出我们使用只是假设第 0 列是 “最快” 排序。但是现在我们将使用一个标志来说 “使用可用的最快排序”:
在我们使用
SHCIDS_CANONICALONLY之前,我们假设第 0 列是“高效”的排序列。
它还指出,您可以忽略 LPARAM 的低 16 位(即列),因为我们不在乎 - 我们使用的是最有效的。
官方文档中反映了很多内容:
SHCIDS_CANONICALONLY
版本 5.0。 按名称比较时,比较系统名称而不是显示名称。传递此标志时,只要 Shell 文件夹实现一致的排序功能,就会根据 Shell 文件夹确定最有效的任何标准来比较这两项。当比较相等或排序结果不向用户显示时,此标志很有用。此标志不能与其他标志组合。
但是有了 SHCIDS_ALLFIELDS,我们开始偏离轨道
头文件说明AllFields只能与CanonicalOnly结合:
只能与 SHCIDS_CANONCALONLY 或第 0 列结合使用。
但 SDK 规定 CanonicalOnly 必须单独出现:
此标志不能与其他标志组合。
那是什么?
我们可以判断头文件是错误的,SDK 是大炮,照它说的做。
但是 AllFields 在说什么?
AllFields 正在试图 要求一些概念,但在文档后面却被掩盖了。
比较 ITEMIDLIST 结构中包含的所有信息,而不仅仅是显示名称。
ItemIDList 不包含显示名称,它包含一个 ItemIDList。他们是想说我应该只查看 pidl blob 的内容吗?
- 例如,如果这两个项目是文件,则文件夹应比较它们的名称、大小、文件时间、属性以及结构中的任何其他信息。
在什么情况下,对*同一个**文件的两个引用可能具有不同的名称、大小、文件时间、属性等?
SDK 示例做了一些不同的事情
Windows SDK Explorer Data Provider Shell Extension 示例 (github) 似乎会出现 CanonicalOnly 和 AllFields 标志一起:
HRESULT CFolderViewImplFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
{
if (lParam & (SHCIDS_CANONICALONLY | SHCIDS_ALLFIELDS))
{
// First do a "canonical" comparison, meaning that we compare with the intent to determine item
// identity as quickly as possible. The sort order is arbitrary but it must be consistent.
_GetName(pidl1, &psz1);
_GetName(pidl2, &psz2);
ResultFromShort(StrCmp(psz1, psz2));
}
// If we've been asked to do an all-fields comparison, test for any other fields that
// may be different in an item that shares the same identity. For example if the item
// represents a file, the identity may be just the filename but the other fields contained
// in the idlist may be file size and file modified date, and those may change over time.
// In our example let's say that "level" is the data that could be different on the same item.
if ((ResultFromShort(0) == hr) && (lParam & SHCIDS_ALLFIELDS))
{
//...
}
}
else
{
//...Compares by the column number in LOWORD of LPARAM
}
所以我们有完全冲突的文档、标题和示例:
SHCIDS_ALLFIELDS
- SDK:永远不能与 SHCIDS_CANONICALONLY 一起出现
- 标题:可以随时出现
- 示例:只能与 SHCIDS_CANONICALONLY 一起出现
它想问什么
Windows 始终假定第 0 列是 fast 列。这可能是因为 Windows shell API 作者假定 PIDL 的 ItemID 将始终包含名称inside pidl opaque blob。
shell STRRET 结构允许您指向 pidl 中的字符串这一事实强化了这一点。
所以在某个时候,他们添加了一个明确的标志,上面写着:
- 我们不关心本地化、特定于区域设置的语言排序规则和 unicode 规范化算法
- 只需对它们进行排序,因为我们需要查找重复项并检查是否相等
这对于 canonical 标志是有意义的:
- 只要告诉我两个 IDList 是否指向同一个 对象
但是当他们谈论 All Fields 选项时,SDK 示例意味着什么:
如果我们被要求进行所有字段比较,请测试具有相同身份的项目中可能不同的任何其他字段。例如:
- 如果项目代表一个文件,标识可能只是文件名
- 但 idlist 中包含的其他字段可能是文件大小和文件修改日期,这些可能会随着时间而改变。
如果两个 PIDL 代表同一个 文件,比较它们的大小、日期等有何意义?我已经告诉过你它们是同一个 file,你用 All Fields 标志问我什么?为什么我不能只对 blob 进行二进制比较?为什么没有壳? CompareIDs 有什么作用
MemCmp(pidl1, pidl2)
没有?
-
SHCIDS_ALLFIELDS只会与SHCIDS_CANONICALONLY一起出现吗? -
SHCIDS_ALLFIELDS永远不会与SHCIDS_CANONICALONLY一起出现吗? -
SHCIDS_ALLFIELDS可以在有和没有SHCIDS_CANONICALONLY的情况下同时出现吗? -
SHCIDS_ALLFIELDSwithSHCIDS_CANONICALONLY是什么意思? -
SHCIDS_ALLFIELDS没有SHCIDS_CANONICALONLY是什么意思?
如果SHCIDS_ALLFIELDS 被通过,它要我做什么?我应该点击底层数据存储来查询我知道的所有字段吗?
CompareIDs是用来比较ID的,还是用来比较对象的?
我想知道 CompareID 的目的是否是绝对不访问底层数据存储(例如硬盘、USB 电话、Mapi),并且仅根据您拥有的进行比较-hand 在 pidl 中。
这有两个原因:
- 更快;许多命名空间在其 PIDL blob 中包含一些元数据 - 无需返回磁盘/Internet
- 即使 pidls 可能引用同一个对象,它们的元数据也可能已过期
- SHCIDS_CANONICALONLY 让调用者意识到两个 pidl 是同一个东西
- 但是单独调用
SHCIDS_CANONICALONLY | SHCIDS_ALLFIELDS可以告诉我们额外的元数据可能已经过时(尽管我不知道该信息对调用者有什么用处)
也许SHCIDS_CANONICALONLY 的意思是:
- 请限制自己使用 pidl - 不要触摸磁盘来执行比较
- 省略它的意思是:“是的,如果你真的需要的话,你可以打硬盘”
是这样吗?
- 如果
SHCIDS_CANONICALONLY的意思是:“不要看除了 pidl 中的内容之外的任何东西,并告诉我这两件事是否是同一个对象” - 那么
SHCIDS_ALLFIELDS得到了什么? - 它们什么时候会有所不同?
- shell 在问我什么?
奖金问题
- 如果
SHCIDS_CANONICALONLY表示执行最有效的排序, - 缺少
SHCIDS_CANONICALONLY是否意味着可以根据名称的本地化和自定义进行排序? - 缺少
SHCIDS_CANONICALONLY是否意味着强制根据名称的本地化和自定义进行排序?
“排序” 到 itemID 列表是什么意思?
SDK 示例根据每一列执行switch,并查找每一列的值。如果这意味着我必须通过网络加载视频才能加载音频采样率?
- 我在比较 PIDLs
- 或者我是在比较那些 pidls 指向的对象吗?
【问题讨论】:
-
一些来自微软人(当时)的旧博客的一些输入可能解释了一点:archives.miloush.net/michkap/archive/2009/09/11/9894019.html
-
@SimonMourier 我已经找到那个博客了;我没有意识到这是迈克尔卡普兰。不过我记得他的旧帖子。 翻录
标签: windows winapi windows-shell shell32