Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В разделе Получение идентификатора папки рассматривается два подхода к получению указателя объекта пространства имен на список идентификаторов элементов (PIDL). Один из очевидных вопросов: Как только у вас есть PIDL, что можно сделать с ним? Связанный вопрос: Что делать, если ни один из подходов не работает или подходит для вашего приложения? Ответ на оба вопроса требует более подробного просмотра способа реализации пространства имен. Ключ — это интерфейс IShellFolder.
- Использование интерфейса IShellFolder
- Перечисление содержимого папки
- Определение отображаемых имен и других свойств
- Получение указателя на интерфейс 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 . Этот интерфейс предоставляет четыре стандартных метода —Клон, Next, Resetи Пропуск— которые можно использовать для перечисления содержимого папки.
Основной процедурой перечисления содержимого папки является:
- Вызовите папки методом IShellFolder::EnumObjects, чтобы получить указатель на интерфейс объекта перечисления IEnumIDList.
- Передайте нераспределенный PIDL в IEnumIDList::Next. В дальнейшем занимается выделением PIDL, но приложение должно освободить его, когда он больше не нужен. Когда Next возвращается, PIDL будет содержать только идентификатор элемента объекта и завершающие символы NULL. Другими словами, это одноуровневый PIDL, связанный с папкой, а не полный квалифицированный PIDL.
- Продолжайте повторять шаг 2 до тех пор, пока Next не вернет S_FALSE, что будет указывать на то, что все элементы были перечислены.
- Вызовите IEnumIDList::Release, чтобы освободить объект перечисления.
Заметка
Важно следить за тем, работаете ли вы с полным или относительным PIDL. Некоторые функции и методы будут принимать как одно, так и другое, но некоторые будут принимать только одно из двух.
Остальные три метода IEnumIDList (Сброс, Пропускатьи Клонировать) полезны, если необходимо выполнить повторяющиеся перечисления папки. Они позволяют обнулить перечисление, пропустить один или несколько объектов и скопировать объект перечисления, чтобы сохранить его текущую позицию.
Определение отображаемых имен и других свойств
После того как вы перечислите все PIDL, содержащиеся в папке, можно определить, какие объекты они представляют. Интерфейс IShellFolder предоставляет ряд полезных методов, два из которых рассматриваются здесь. Далее рассматриваются другие методы IShellFolder и другие интерфейсы папок оболочки.
Одним из наиболее полезных свойств является отображаемое имя объекта. Чтобы получить отображаемое имя объекта, передайте его PIDL в IShellFolder::GetDisplayNameOf. Хотя объект может находиться в любом месте под родительской папкой в пространстве имен, его PIDL должен быть относительно папки.
IShellFolder::GetDisplayNameOf возвращает отображаемое имя в составе структуры STRRET. Так как извлечение отображаемого имени из структуры STRRET может быть немного сложным, оболочка предоставляет две функции, которые решают эту задачу, StrRetToStr и StrRetToBuf. Обе функции принимают структуру STRRET и возвращают отображаемое имя как обычную строку. Они отличаются только способом выделения строки.
Помимо отображаемого имени объект может иметь ряд атрибутов, таких как папка или возможность перемещения. Атрибуты объекта можно получить, передав его PIDL в IShellFolder::GetAttributesOf. Полный список атрибутов довольно большой, поэтому вы должны просмотреть ссылку для получения подробных сведений. Обратите внимание, что идентификатор PIDL, который передается в GetAttributesOf, должен быть одноуровневым. В частности, IShellFolder::GetAttributesOf будет принимать PID-списки, возвращаемые IEnumIDList::Next. Вы можете передать массив PIDL, и GetAttributesOf вернет те атрибуты, которые общие для всех объектов в массиве.
Если у вас есть полный путь объекта или PIDL, SHGetFileInfo предоставляет простой способ получения сведений об объекте, достаточном для многих целей. SHGetFileInfo принимает полный путь или PIDL, а также возвращает различные сведения об объекте, включая:
- Отображаемое имя объекта
- Атрибуты объекта
- Обрабатывает значки объекта
- Дескриптор списка системных образов
- Путь файла, содержащего значок объекта
Получение указателя на интерфейс IShellFolder в подпапке
Вы можете определить, содержит ли папка любые вложенные папки, вызвав IShellFolder::GetAttributesOf и проверьте, задан ли флаг SFGAO_FOLDER. Если объект является папкой, к нему можно привязаться, что предоставляет указатель на интерфейс IShellFolder.
Чтобы привязать к вложенной папке, вызовите метод родительской папки IShellFolder::BindToObject. Этот метод принимает PIDL вложенной папки и возвращает указатель на его интерфейс IShellFolder. Получив этот указатель, можно использовать методы IShellFolder для перечисления содержимого вложенных папок, определения их свойств и т. д.
Определение родительской папки объекта
Если у вас есть PIDL объекта, может потребоваться дескриптор одного из интерфейсов, предоставляемых родительской папкой. Например, если вы хотите определить отображаемое имя, связанное с PIDL, с помощью IShellFolder::GetDisplayNameOf, необходимо сначала получить интерфейс IShellFolder интерфейса родительского объекта. Это можно сделать с помощью методов, описанных в предыдущих разделах. Однако гораздо проще использовать функцию Shell, 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.