Windows IShellFolder.CompareIDs的SHCIDS_ALLFIELDS标志试图是什么? 短版
的Windows IShellFolder.CompareIDs的SHCIDS_ALLFIELDS标志试图是什么? 短版,windows,winapi,windows-shell,shell32,Windows,Winapi,Windows Shell,Shell32,的SHCIDS\u ALLFIELDS标志是什么意思 长版本 在Windows95中,微软引入了shell。它不是假设计算机由文件和文件夹组成,而是由项目的抽象名称空间组成 而不是从驱动器根目录开始的路径(例如C:\Documents&Settings\Ian) 路径从名称空间的根开始(Desktop) 为了容纳非文件和文件夹的内容(例如网络打印机、控制面板、我的Android手机): 不能使用由反斜杠分隔的一系列名称(例如C:\Users\Ian) 您使用PIDL,一系列不透明的BLOB
SHCIDS\u ALLFIELDS
标志是什么意思
长版本
在Windows95中,微软引入了shell。它不是假设计算机由文件和文件夹组成,而是由项目的抽象名称空间组成
- 而不是从驱动器根目录开始的路径(例如
)C:\Documents&Settings\Ian
- 路径从名称空间的根开始(
)Desktop
- 不能使用由反斜杠分隔的一系列名称(例如C:\Users\Ian)
- 您使用PIDL,一系列不透明的BLOB(例如,桌面电脑操作系统(C:)用户)
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是我们拥有的速度最快、效率最高的产品
- 从用户界面可用性的角度来看,它不必是合乎逻辑的;它必须是一致的
SHCIDS\u CANONICALONLY
之前,我们假设列0是“有效”排序列
它还指出,您可以忽略LPRAM的较低16位(即列),因为我们不在乎——我们使用的是最有效的一个
官方文件中反映了许多这方面的情况:
SHCIDS\u规范版
5.0版。按名称比较时,比较系统名称,但不比较显示名称。当传递此标志时,只要Shell文件夹实现了一致的排序函数,就会根据Shell文件夹确定的最有效的标准对这两个项进行比较。当比较是否相等或排序结果未显示给用户时,此标志非常有用。此标志不能与其他标志组合
但是有了SHCIDS_ALLFIELDS,我们开始失控了
头文件指出,所有字段只能与CanonicalOnly组合:
只能与SHCIDS_CANONCALONLY或列0一起使用
但是SDK说,CanonicalOnly必须单独出现:
此标志不能与其他标志组合
那是哪一个呢
我们可以确定头文件是错误的,SDK是cannon,然后按照它所说的去做
但是AllFields在说什么?
AllFields试图要求一些概念,但这些概念在文档背后被掩盖了
比较ITEMIDLIST结构中包含的所有信息,而不仅仅是显示名称
ItemIDList不包含显示名称,它包含ItemIDList。他们是想说我应该只查看pidl blob的内容吗
- 例如,如果这两个项目是文件,则文件夹应比较它们的名称、大小、文件时间、属性以及结构中的任何其他信息李>
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\u所有字段
- SDK:永远不能仅与SHCIDS\U规范一起出现
- 标题:可随时显示
- 示例:只能与SHCIDS\u CANONICALONLY一起出现
- 我们不关心本地化、特定于语言环境的语言排序规则和unicode规范化算法
- 只需对它们进行排序,因为我们需要找到重复项并检查是否相等
- 告诉我两个懒汉是否指向同一个对象
MemCmp(pidl1, pidl2)
Index | Title
-------------
0 Name
1 Size
2 Type
3 Date Modified
for (UINT i = 0; i < mycolumcount; ++i)
{
hr = CompareIDs(i, pidl1, pidl2);
if (hr && SUCCEEDED(hr)) break;
}
return hr;
typedef struct { UINT16 cb; WCHAR name[99]; UINT size; bool isFolder } MYITEM;
enum { COL_NAME = 0, COL_SIZE, COLCOUNT, COLCANONICAL = COL_NAME };
MYITEM* GetDataPtr(PCUIDLIST_RELATIVE pidl) { ... }
bool IsFolder(MYITEM*p) { ... }
void GetForDisplay_Name(WCHAR*buf, MYITEM*p)
{
lstrcpy(buf, p->name);
SHGetSetSettings(...);
if (!ss.fShowExtensions && !IsFolder(p)) PathRemoveExtension(buf); // Assuming p->name is a "filenameish" property.
}
void GetForDisplay_Size(WCHAR*buf, MYITEM*p)
{
// Localized size string returned by GetDetailsOf, not used by CompareIDs
}
HRESULT CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
{
HRESULT hr = E_FAIL; // Bad column
MYITEM *p1 = GetDataPtr(pidl1), *p2 = GetDataPtr(pidl2); // A real implementation must validate items
if (lParam & (SHCIDS_CANONICALONLY | SHCIDS_ALLFIELDS))
{
hr = ResultFromShort(StrCmp(p1->name, p2->name));
if ((ResultFromShort(0) == hr) && (lParam & SHCIDS_ALLFIELDS))
{
for (UINT i = 0; i < COLCOUNT; ++i)
{
// if (COLCANONICAL == i) continue; // This optimization might be valid, depends on the difference between a items canonical and display name
hr = CompareIDs(i, pidl1, pidl2);
if (hr && SUCCEEDED(hr)) break;
}
}
return hr;
}
WCHAR b1[99], b2[99];
switch(LOWORD(lParam))
{
case COL_NAME:
GetForDisplay_Name(b1, p1);
GetForDisplay_Name(b2, p2);
return ResultFromShort(StrCmp(b1, b2));
case COL_SIZE:
return ResultFromShort(p1->size - p2->size);
}
return hr;
}