Поделиться через


Получение сведений о содержимом папки

В разделе "Получение идентификатора папки" рассматриваются два подхода к получению указателя объекта пространства имен на список идентификаторов элементов (PIDL). Один из очевидных вопросов: Как только у вас есть PIDL, что можно сделать с ним? Связанный вопрос: Что делать, если ни один из подходов не работает или подходит для вашего приложения? Ответ на оба вопроса требует более подробного просмотра способа реализации пространства имен. Ключ — это интерфейс IShellFolder.

Использование интерфейса IShellFolder

Ранее в этой документации папки пространства имен называются объектами. Хотя, на этом этапе, термин использовался в свободном смысле, это на самом деле верно в строгом смысле, а также. Каждая папка пространства имен представлена объектом объектной модели компонента (COM). Каждый объект папки предоставляет ряд интерфейсов, которые можно использовать для различных задач. Некоторые интерфейсы, которые являются необязательными, могут не предоставляться всеми папками. Однако все папки должны предоставлять базовый интерфейс IShellFolder.

Первым шагом в использовании объекта папки является получение указателя на его интерфейс IShellFolder. Помимо предоставления доступа к другим интерфейсам объекта, IShellFolder предоставляет группу методов, обрабатывающих ряд распространенных задач, некоторые из которых рассматриваются в этом разделе.

Чтобы получить указатель на интерфейс IShellFolder объекта пространства имен, необходимо сначала вызвать SHGetDesktopFolder. Эта функция возвращает указатель на интерфейс IShellFolder корня пространства имен, рабочего стола. После того как вы получите интерфейс IShellFolder для рабочего стола, вы можете продолжить работу с различными способами.

Если у вас уже есть PIDL нужной папки ( например, путем вызова SHGetFolderLocation), вы можете получить свой интерфейс IShellFolder, вызвав метод IShellFolder рабочего стола::BindToObject. Если у вас есть путь к объекту файловой системы, необходимо сначала получить его PIDL, вызвав метод IShellFolder рабочего стола::P arseDisplayName, а затем вызвать IShellFolder::BindToObject. Если ни один из этих подходов не применим, вы можете использовать другие методы IShellFolder для навигации по пространству имен. Дополнительные сведения см. в разделе "Навигация по пространству имен".

Перечисление содержимого папки

Первое, что вы обычно хотите сделать с папкой, — узнать, что он содержит. Сначала необходимо вызвать метод IShellFolder папки::EnumObjects. Папка создаст стандартный объект перечисления OLE и возвращает его интерфейс IEnumIDList. Этот интерфейс предоставляет четыре стандартных метода — клонировать, далее, сброс и пропустить, которые можно использовать для перечисления содержимого папки.

Основной процедурой перечисления содержимого папки является:

  1. Вызовите метод IShellFolder::EnumObjects, чтобы получить указатель на интерфейс IEnumIDList объекта перечисления.
  2. Передайте нераспределенный PIDL в IEnumIDList::Next. Далее необходимо распределить PIDL, но приложение должно освободить его, когда оно больше не требуется. При следующем возвращении PIDL будет содержать только идентификатор элемента объекта и завершающие символы NULL . Другими словами, это одноуровневый PIDL относительно папки, а не полный идентификатор PIDL.
  3. Повторите шаг 2 до следующего возврата S_FALSE, чтобы указать, что все элементы были перечислены.
  4. Вызовите IEnumIDList::Release , чтобы освободить объект перечисления.

Примечание.

Важно следить за тем, работаете ли вы с полным или относительным PIDL. Некоторые функции и методы будут принимать либо, но другие будут принимать только одну или другую.

 

Остальные три метода IEnumIDList (Reset, Skip и Clone) полезны, если необходимо выполнить повторяющиеся перечисления папки. Они позволяют сбрасывать перечисление, пропускать один или несколько объектов и создавать копию объекта перечисления, чтобы сохранить его состояние.

Определение отображаемых имен и других свойств

После перечисления всех ПИН-адресов, содержащихся в папке, можно узнать, какой вид объектов они представляют. Интерфейс IShellFolder предоставляет ряд полезных методов, которые рассматриваются здесь. Далее рассматриваются другие методы IShellFolder и другие интерфейсы папок Оболочки.

Одним из наиболее полезных свойств является отображаемое имя объекта. Чтобы получить отображаемое имя объекта, передайте его PIDL в IShellFolder::GetDisplayNameOf. Хотя объект может находиться в любом месте под родительской папкой в пространстве имен, его PIDL должен быть относительно папки.

IShellFolder::GetDisplayNameOf возвращает отображаемое имя в составе структуры STRRET. Так как извлечение отображаемого имени из структуры STRRET может быть немного сложной, оболочка предоставляет две функции, которые выполняют задание для вас, StrRetToStr и StrRetToBuf. Обе функции принимают структуру STRRET и возвращают отображаемое имя в виде обычной строки. Они отличаются только тем, как выделяется строка.

Помимо отображаемого имени объект может иметь ряд атрибутов, таких как папка или возможность перемещения. Атрибуты объекта можно получить, передав его PIDL в IShellFolder::GetAttributesOf. Полный список атрибутов довольно большой, поэтому вы должны просмотреть ссылку для получения подробных сведений. Обратите внимание, что идентификатор PIDL, который передается в GetAttributesOf , должен быть одним уровнем. В частности, IShellFolder::GetAttributesOf принимает PID-списки, возвращаемые IEnumIDList::Next. Вы можете передать массив ПИН-адресов, и GetAttributesOf вернет эти атрибуты, которые имеют все объекты в массиве.

Если у вас есть полный путь объекта или PIDL, SHGetFileInfo предоставляет простой способ получения сведений об объекте, достаточном для многих целей. SHGetFileInfo принимает полный путь или PIDL, а также возвращает различные сведения об объекте, включая:

  • Отображаемое имя объекта
  • Атрибуты объекта
  • Обрабатывает значки объекта
  • Дескриптор списка системных образов
  • Путь файла, содержащего значок объекта

Получение указателя на интерфейс IShellFolder в подпапке

Вы можете определить, содержит ли папка какие-либо вложенные папки, вызвав IShellFolder::GetAttributesOf и проверка, чтобы узнать, задан ли флаг SFGAO_FOLDER. Если объект является папкой, ее можно привязать, которая предоставляет указатель на его интерфейс IShellFolder.

Чтобы привязать к вложенной папке, вызовите метод IShellFolder родительской папки::BindToObject. Этот метод принимает PIDL вложенной папки и возвращает указатель на его интерфейс IShellFolder. После этого указателя можно использовать методы IShellFolder для перечисления содержимого вложенных папок, определения их свойств и т. д.

Определение родительской папки объекта

Если у вас есть PIDL объекта, может потребоваться дескриптор одного из интерфейсов, предоставляемых родительской папкой. Например, если вы хотите определить отображаемое имя, связанное с PIDL, с помощью IShellFolder::GetDisplayNameOf, необходимо сначала получить интерфейс IShellFolder родительского объекта. Это можно сделать с помощью методов, описанных в предыдущих разделах. Однако гораздо проще использовать функцию Оболочки SHBindToParent. Эта функция принимает полный идентификатор PIDL объекта и возвращает указанный указатель интерфейса в родительской папке. При необходимости он также возвращает одноуровневый PIDL элемента для использования в таких методах, как IShellFolder::GetAttributesOf.

В следующем примере консольного приложения извлекается PIDL специальной папки системы и возвращается отображаемое имя.

#include <shlobj.h>
#include <shlwapi.h>
#include <iostream.h>
#include <objbase.h>

int main()
{
    IShellFolder *psfParent = NULL;
    LPITEMIDLIST pidlSystem = NULL;
    LPCITEMIDLIST pidlRelative = NULL;
    STRRET strDispName;
    TCHAR szDisplayName[MAX_PATH];
    HRESULT hr;

    hr = SHGetFolderLocation(NULL, CSIDL_SYSTEM, NULL, NULL, &pidlSystem);

    hr = SHBindToParent(pidlSystem, IID_IShellFolder, (void **) &psfParent, &pidlRelative);

    if(SUCCEEDED(hr))
    {
        hr = psfParent->GetDisplayNameOf(pidlRelative, SHGDN_NORMAL, &strDispName);
        hr = StrRetToBuf(&strDispName, pidlSystem, szDisplayName, sizeof(szDisplayName));
        cout << "SHGDN_NORMAL - " <<szDisplayName << '\n';
    }

    psfParent->Release();
    CoTaskMemFree(pidlSystem);

    return 0;
}

Приложение сначала использует SHGetFolderLocation для получения PIDL системной папки. Затем он вызывает SHBindToParent, который возвращает указатель на интерфейс IShellFolder родительской папки и PIDL системной папки относительно родительского элемента. Затем он использует метод IShellFolder родительской папки ::GetDisplayNameOf для получения отображаемого имени папки System. Так как GetDisplayNameOf возвращает структуру STRRET , StrRetToBuf используется для преобразования отображаемого имени в обычную строку. После отображения отображаемого имени указатели интерфейса освобождаются и освобождается System PIDL. Обратите внимание, что вы не должны освободить относительный PIDL, возвращаемый SHBindToParent.