Сортировка элементов оболочки, таких как проводник Windows

Я делаю панель хлебных крошек в Delphi и имею некоторые проблемы с сортировкой выпадающего списка хлебных крошек.

Как ни странно, даже Vista не последовательно показывает эти пункты.

Я пробовал много способов выяснить, что такое системные папки, что такое zip-файлы и что такое обычные папки. Это кажется простой задачей, но пока я не нашел хорошего способа сделать это.

Один из способов — использовать TypeDisplayName из TSHFileinfo, но это локализованные имена, поэтому я не могу быть уверен, что они будут в правильном порядке на каждом языке.

Вот код, который я использую для заполнения меню:

  bool:= IsDesktop(SelectedPIDL);
  if bool then
    OleCheck(SHGetDesktopFolder(CurFolder))
  else
    OleCheck(DesktopShellFolder.BindToObject(SelectedPIDL, nil, IID_IShellFolder, Pointer(CurFolder)));
  if CurFolder.EnumObjects(0, SHCONTF_FOLDERS, EnumIDList) = NOERROR then
  begin
    while EnumIDList.Next(1, CurPidl, Fetched) = S_OK do
    begin
      FName:= GetDisplayName(CurFolder, CurPidl, SHGDN_NORMAL);
      Text:= GetPIDLNameForAddressBar(CurFolder, CurPidl);
      if bool then
        Text:= PSpecialFolderItem(SpecialFolders[0]).Name + '\' + Text;
      if Text[Length(Text)] <> '\' then
        Text:= Text + '\';
      NewPidl:= ConcatPIDLs(SelectedPIDL, CurPidl);
      SHGetFileInfo(PChar(NewPidl), 0, SFI, SizeOf(SFI), SHGFI_ATTRIBUTES or SHGFI_PIDL or
        SHGFI_SYSICONINDEX or SHGFI_TYPENAME);

      n:= SFI.dwAttributes;
      MenuList.Add(GetAttr(n) + FName);

      AddMenuItem(Text, FName, SFI.iIcon);
      CoTaskMemFree(CurPidl);
      CoTaskMemFree(NewPidl);
    end;
  end;
  CoTaskMemFree(SelectedPIDL);

Любое решение, как получить правильный порядок сортировки? Странно, что в dwAttributes TSHFileInfo нет способа определить, является ли папка системной.

Благодаря Киту Гиддингсу мне удалось найти это решение:

  PidlList:= TList.Create;
  // Add PIDLs for sorting
  bool:= IsDesktop(SelectedPIDL);
  if bool then
    OleCheck(SHGetDesktopFolder(IShellFld))
  else
    OleCheck(DesktopShellFolder.BindToObject(SelectedPIDL, nil, IID_IShellFolder, Pointer(IShellFld)));
  if IShellFld.EnumObjects(0, SHCONTF_FOLDERS, EnumIDList) = NOERROR then
    while EnumIDList.Next(1, CurPidl, Fetched) = S_OK do
      PidlList.Add(CurPidl);
  // Sort it ...
  PidlList.Sort(ComparePIDLs);
  // Get display name and icon for item
  for i:= 0 to PidlList.Count - 1 do
  begin
    CurPidl:= PidlList[i];
    FName:= GetDisplayName(IShellFld, CurPidl, SHGDN_NORMAL);
    Text:= GetPIDLNameForAddressBar(IShellFld, CurPidl);
    if bool then
      Text:= PSpecialFolderItem(SpecialFolders[0]).Name + '\' + Text;
    if Text[Length(Text)] <> '\' then
      Text:= Text + '\';
    NewPidl:= ConcatPIDLs(SelectedPIDL, CurPidl);
    SHGetFileInfo(PChar(NewPidl), 0, SFI, SizeOf(SFI), SHGFI_ATTRIBUTES or SHGFI_PIDL or
      SHGFI_SYSICONINDEX or SHGFI_TYPENAME);
    AddMenuItem(Text, FName, SFI.iIcon);
    CoTaskMemFree(NewPidl);
  end;
  CoTaskMemFree(SelectedPIDL);
  for i:= PidlList.Count - 1 downto 0 do
  begin
    CoTaskMemFree(PidlList[i]);
    PidlList.Delete(i);
  end;
  // We are done free it
  PidlList.Free;

function ComparePIDLs(Item1, item2: Pointer): Integer;
begin
  Result:= SmallInt(IShellFld.CompareIDs(0, Item1, Item2));
end;

Рой М Клевер


person Roy M Klever    schedule 30.05.2010    source источник
comment
Не могли бы вы объяснить желаемое поведение/функции сортировки, возможно, на примере.   -  person Tim Lloyd    schedule 30.05.2010
comment
Привет, chibacity, я хочу, чтобы он сортировался, поэтому я получаю тот же результат, что и при нажатии на тот же элемент хлебной крошки в проводнике Vista. Но поскольку Vista не является следствием, я хочу, чтобы системные папки были вверху, а затем обычные папки, а внизу - zip-файлы (папки) ... Я хочу, чтобы выпадающие списки выглядели более организованно. Сейчас это выглядит немного запутанным. Я вижу, могу ли я добавить изображение к моему вопросу...   -  person Roy M Klever    schedule 30.05.2010
comment
Я не знаком с таким использованием консеквента, и словарь не помогает мне понять его. Вы можете пояснить?   -  person Dennis Williamson    schedule 30.05.2010
comment
Не будучи последовательным, я просто имею в виду, что Vista время от времени сортирует одни и те же элементы по-разному. Иногда zip-файлы (сжатые папки) и обычные папки смешиваются, а иногда они сортируются, поэтому zip-файлы отделяются от обычных папок... Мне просто нужен способ получить состояние папки System, Normal или zip-файла, затем я помещаю все это в отсортированном списке строк, прежде чем помещать его в пункт меню ... Может быть, есть еще типы папок, которых я не знаю, но какой-то способ сортировки элементов - это то, что я ищу   -  person Roy M Klever    schedule 30.05.2010
comment
Быть последовательным, возможно, является чем-то вроде голландского языка: последовательный gedrag означает последовательное поведение.   -  person Marjan Venema    schedule 30.05.2010


Ответы (1)


Как насчет использования IShellFolder.CompareIds для всех pidl ваших перечисленных объектов. Это должно позволить вам расположить их в том же порядке, что и проводник, независимо от того, какая версия Windows и какой язык пользовательского интерфейса.

person Keith Giddings    schedule 30.05.2010
comment
Хм... Я хочу, чтобы решение работало в любой версии Windows. Итак, вы думаете, что нужно просто сортировать предметы, используя pidls предметов? Что ж, я пошел попробовать ... Я даже не думал об этом как о решении. - person Roy M Klever; 30.05.2010
comment
Большое спасибо за ваше решение, оно работает отлично. Единственная проблема, с которой я столкнулся при попытке, заключалась в том, что мне пришлось добавить SmallInt перед результатом IShellfolder.CompareIds. функция ComparePIDLs(Item1, Item2: Pointer): Integer; начало Результат: = SmallInt (IShellFld.CompareIDs (0, Item1, Item2)); конец; - person Roy M Klever; 30.05.2010