Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Windows IShellFolder.CompareIDs的SHCIDS_ALLFIELDS标志试图是什么? 短版_Windows_Winapi_Windows Shell_Shell32 - Fatal编程技术网

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
为了容纳非文件和文件夹的内容(例如网络打印机、控制面板、我的Android手机):

  • 不能使用由反斜杠分隔的一系列名称(例如C:\Users\Ian)
  • 您使用PIDL,一系列不透明的BLOB(例如,桌面电脑操作系统(C:)用户)
PIDL是不透明的blob,每个blob只对生成它的文件夹有意义

为了扩展(或使用)shell名称空间,您需要实现(或调用)一个接口

IShellFolder的其中一种方法用于请求命名空间扩展以将与ID列表(PIDL)进行比较:

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是我们拥有的速度最快、效率最高的产品
  • 从用户界面可用性的角度来看,它不必是合乎逻辑的;它必须是一致的
正如陈雷蒙所指出的,这是一个很好的例子

头文件甚至指出,我们使用来假定列0是“最快”的排序。但是现在我们将使用一个标志“使用可用的最快排序”:

在使用
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的内容吗

  • 例如,如果这两个项目是文件,则文件夹应比较它们的名称、大小、文件时间、属性以及结构中的任何其他信息
在什么情况下,对*相同**文件的两个引用可能具有不同的名称、大小、文件时间、属性等

SDK示例做了一些不同的事情 Windows SDK资源管理器数据提供程序外壳扩展sample(),看起来好像CanonicalOnlyAllFields标志将一起出现:

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一起出现
它想问什么 Windows始终假定列0是fast列。这可能是因为WindowsShellAPI的作者假设PIDL的ItemID在PIDL不透明blob中始终包含名称

shell STRRET结构允许您指向pidl中的字符串,这一点得到了加强

额外阅读:

因此,在某个时刻,他们添加了一个快速标志,上面写着:

  • 我们不关心本地化、特定于语言环境的语言排序规则和unicode规范化算法
  • 只需对它们进行排序,因为我们需要找到重复项并检查是否相等
这对于规范的标志是有意义的:

  • 告诉我两个懒汉是否指向同一个对象
但是,当他们谈到所有字段选项时,SDK示例意味着什么:

如果我们
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;
}