Общие замечания

Начиная с Windows 95, система поддерживает так называемое пространство имен (shell namespace), в котором каждый объект (файл или папка) однозначно идентифицируется структурой типа ITEMIDLIST. Функции работы с пространством имен принимают в качестве одного из параметров указатель на такую структуру (или массив таких структур). В документации такие указатели обычно носят название PIDL. Подобный механизм позволяет операционной системе поддерживать так называемые виртуальные папки, которым не соответствуют никакие объекты в реальной файловой системе.

Существует некоторое количество системных папок, доступ к которым можно получить с помощью функции

HRESULT SHGetSpecialFolderLocation(
   HWND hWnd,
   int nFolder,
   ITEMIDLIST** ppidl
);

Через параметр hWnd передается дескриптор окна, поверх которого при необходимости будут выводиться диалоговые окна или окна сообщений. В качестве параметра nFolder необходимо указать идентификатор системной папки, PIDL которой функция должна записать в переменную по адресу ppidl. Освобождение памяти, которую функция выделяет под PIDL, должно выполняться приложением-клиентом при помощи метода Free интерфейса IMalloc. Ниже перечислены возможные значения параметра nFolder.

Значение Папка Вид папки
CSIDL_CONTROLS Control Panel виртуальная
CSIDL_COOKIES Cookies физическая
CSIDL_DESKTOP Desktop (вершина пространства имен) виртуальная
CSIDL_DESKTOPDIRECTORY Desktop (в файловой системе) физическая
CSIDL_DRIVES My Computer виртуальная
CSIDL_FAVORITES Favorites физическая
CSIDL_FONTS Fonts виртуальная
CSIDL_HISTORY History физическая
CSIDL_INTERNET Internet Explorer виртуальная
CSIDL_INTERNET_CACHE Temporary Internet Files физическая
CSIDL_NETWORK Network Neighborhood (My Network Places) виртуальная
CSIDL_PERSONAL My Documents физическая
CSIDL_PRINTERS Printers виртуальная
CSIDL_PROGRAMS Ярлыки меню StartPrograms физическая
CSIDL_RECENT Ярлыки меню StartDocuments физическая
CSIDL_SENDTO Ярлыки меню Send To физическая
CSIDL_STARTMENU Ярлыки меню Start физическая
CSIDL_STARTUP Ярлыки меню StartProgramsStartup физическая
CSIDL_TEMPLATES Templates физическая

Функция возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае. Заметим, что создаваемый этой функцией PIDL идентифицирует указанную папку относительно вершины пространства имен (то есть виртуальной папки Desktop).

Для создания в папке Documents ярлыка на заданный документ используется функция

void SHAddToRecentDocs(
   UINT fuFlags,
   const void* pvDoc

Значение параметра fuFlags определяет, как функция будет интерпретировать параметр pvDoc: при fuFlags равном SHARD_PATH по адресу pvDoc должна находиться завершающаяся двоичным нулем строка с полным именем файла, на который должен ссылаться создаваемый ярлык; а при fuFlags равном SHARD_PIDL через pvDoc необходимо передать PIDL этого файла.

Для работы с объектами пространства имен предназначены интерфейсы IShellFolder и IEnumIDList.

Интерфейс IShellFolder

Заголовочный файл #include <shlobj.h>
Непосредственный предок интерфейс IUnknown

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

HRESULT GetDisplayNameOf(
   ITEMIDLIST* pidl,
   DWORD fdwFlags,
   STRRET* pNameStr
);

Метод записывает текстовое имя объекта с идентификатором pidl в переменную по адресу pNameStr. Параметр fdwFlags определяет вид этого имени и может быть комбинацией следующих флагов:

SHGDN_NORMAL
полное имя относительно папки Desktop;
SHGDN_INFOLDER
имя относительно папки, с которой связан данный указатель на интерфейс;
SHGDN_FOREDITING
имя будет использоваться для редактирования in-place;
SHGDN_FORADDRESSBAR
имя будет отображаться в адресной строке (address bar);
SHGDN_FORPARSING
имя будет использоваться для синтаксического анализа.

Заметим, что первые два флага являются взаимоисключающими; если не один из них не указан явно, то используется флаг SHGDN_NORMAL. Опыт показывает, что для получения имени объекта в «привычном» виде необходимо использовать флаг SHGDN_FORPARSING.

Структура STRRET объявлена следующим образом:

typedef struct _STRRET
{
   UINT uType;
   union
   {
      LPWSTR pOleStr;
      LPSTR pStr;
      UINT uOffset;
      char cStr[MAX_PATH];
   };
} STRRET;

В поле uType метод записывает тип возвращенного значения, который может быть одним из следующих:

STRRET_WSTR
в поле pOleStr записан адрес строки в кодировке Unicode (приложение-клиент должно самостоятельно освобождать эту область памяти при помощи метода Free интерфейса IMalloc);
STRRET_OFFSET
в поле uOffset записано смещение строки относительно начала области памяти, в которой расположен PIDL;
STRRET_CSTR
строка в кодировке ANSI записана в поле cStr.

Заметим, что поле pStr структуры STRRET вообще не используется. Метод возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае.

HRESULT GetAttributesOf(
   UINT cItems,
   ITEMIDLIST** apidl,
   ULONG* pfuFlags
);

Этот метод предназначен для получения атрибутов одного или нескольких объектов пространства имен. Через параметр apidl передается адрес массива, каждый элемент которого содержит PIDL объекта, а через параметр cItems — количество элементов в этом массиве. В переменную по адресу pfuFlags перед вызовом метода необходимо записать комбинацию битовых флагов, соответствующую проверяемым атрибутам; после выполнения метода по этому адресу будет записана комбинация флагов, соответствующая общим для всех объектов атрибутам. Допустимы следующие флаги:

SFGAO_CANCOPY
объект может быть скопирован;
SFGAO_CANMOVE
объект может быть перемещен;
SFGAO_CANRENAME
объект может быть переименован;
SFGAO_CANDELETE
объект может быть удален;
SFGAO_CANLINK
возможно создание ярлыка, ссылающегося на объект;
SFGAO_DROPTARGET
объект может быть приемником при операциях drag-n-drop;
SFGAO_LINK
объект является ярлыком;
SFGAO_READONLY
доступ к объекту возможен только на чтение;
SFGAO_SHARE
к объекту разрешен совместный доступ;
SFGAO_HASSUBFOLDER
объект содержит вложенные папки;
SFGAO_FILESYSTEM
объект существует в физической файловой системе;
SFGAO_FOLDER
объект является папкой;
CFGAO_COMPRESSED
объект сжат (только для NTFS-томов);
SFGAO_REMOVABLE
объект находится на сменном носителе.

Метод возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае.

Получить указатель на интерфейс IShellFolder, связанный с виртуальной папкой Desktop, можно с помощью функции

HRESULT SHGetDesktopFolder(
   IShellFolder** ppDest
);

которая записывает требуемый указатель в переменную по адресу ppDest и возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае.

Просмотр пространства имен

Для просмотра содержимого пространства имен необходимо вначале получить указатель на интерфейс IEnumIDList. Это можно сделать с помощью метода интерфейса IShellFolder

HRESULT EnumObjects(
   HWND hWnd,
   DWORD fdwFlags,
   IEnumIDList** ppDest
);

Через параметр hWnd передается дескриптор окна, поверх которого система будет выводить диалоговые окна, если потребуется ввод пользователя. Этот параметр можно задать равным NULL, но если при этом ввод пользователя все-таки потребуется, то метод завершится с ошибкой. Параметр fdwFlags определяет, объекты каких типов необходимо просмотреть, и может быть комбинацией следующих флагов:

SHCONTF_FOLDERS
папки;
SHCONTF_NONFOLDERS
не папки;
SHCONTF_INCLUDEHIDDEN
скрытые объекты;
SHCONTF_NETPRINTSCRH
принтеры.

Дополнительно может быть указан флаг SHCONTF_INIT_ON_FIRST_NEXT; в этом случае созданный экземпляр интерфейса IEnumIDList будет сразу же инициализирован PIDL'ом первого найденного объекта, соответствующего заданным условиям.

Через параметр ppDest необходимо передать адрес переменной, в которую будет записан полученный указатель. Метод возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае.

После получения указателя на интерфейс IEnumIDList необходимо циклически вызывать его метод

HRESULT Next(
   ULONG cItems,
   ITEMIDLIST** apidl,
   ULONG* pcFetched
);

до тех пор, пока он не вернет значение S_FALSE. Через параметр apidl необходимо передавать адрес массива, в который метод будет записывать PIDL'ы найденных объектов, а через параметр cItems — емкость этого массива. В переменную по адресу pcFetched метод будет записывать количество PIDL'ов, скопированных в массив по адресу apidl. Если этот массив будет состоять из одного элемента, то параметр pcFetched можно задать равным NULL. Метод возвращает значение NOERROR при успешном выполнении или код ошибки OLE — в противном случае; еще раз отметим, что значение S_FALSE соответствует успешному окончанию перебора объектов.

Стандартное окно выбора папки

Для создания стандартного окна выбора папки используется функция

ITEMIDLIST* SHBrowseForFolder(
   BROWSEINFO* pbi
);

Через параметр pbi передается указатель на структуру, определяющую внешний вид и поведение создаваемого диалогового окна. Функция возвращает PIDL выбранного пользователем объекта или NULL, если пользователь отказался от выбора.

Ниже перечислены поля структуры BROWSEINFO:

HWND hWndOwner
Окно-владелец диалогового окна (оно создается как модальное).
ITEMIDLIST* pidlRoot
PIDL объекта, который будет отображаться в качестве коревого. Если это поле задать равным NULL, то в корневым объектом будет виртуальная папка Desktop.
LPTSTR pszDisplayName
В строку по этому адресу будет скопировано имя выбранного объекта.
LPCTSTR lpszTitle
Адрес строки, которая будет отображаться в диалоговом окне над деревом объектов. Если это поле задать равным NULL, то будет использоваться стандартная строка.
UINT ulFlags
Набор флагов, определяющих, какие объекты будут отображаться в дереве.
BFFCALLBACK lpfn
Адрес функции, которая будет получать извещения от диалогового окна. Это поле может быть задано равным NULL.
LONG lParam
Произвольное 4-байтовое значение, которое будет доступно в функции, адресуемой полем lpfn.
int iImage
В это поле будет записан индекс картинки, соответствующей выбранному объекту, в системном списке изображений.

Для формирования значения поля ulFlags могут использоваться следующие флаги:

BIF_BROWSEINCLUDEFILES
отображать в дереве не только папки, но и файлы (IE 4.0+);
BIF_BROWSEFORCOMPUTER
отображать в дереве видимые по сети компьютеры;
BIF_BROWSEFORPRINTER
отображать в дереве подключенные принтеры;
BIF_EDITBOX
отображать в диалоговом окне поле ввода, при наборе символов в котором будет происходить автоматический переход к объектам, имена которых начинаются с введенной строки (IE 4.0+);
BIF_NEWDIALOGSTYLE
вывести диалоговое окно «нового стиля», размер которого можно изменять с помощью мыши (IE 5.0+);
BIF_RETURNONLYFSDIRS
кнопка OK будет доступна только в том случае, если в дереве выбран объект, физически существующий в файловой системе;
BIF_STATUSTEXT
диалоговое окно будет содержать текстовое поле, в котором приложение сможет отображать произвольную информацию, посылая сообщения из функции, адресуемой полем lpfn;
BIF_SHAREABLE
отображать в дереве совместно используемые сетевые ресурсы: файлы, папки, принтеры, etc. (IE 5.0+);
BIF_VALIDATE
посылать в функцию, адресуемую полем lpfn, извещения, если в поле ввода (флаг BIF_EDITBOX) набрано недопустимое имя (IE 4.0+).

Функция, адресуемая полем lpfn, должна иметь следующий прототип:

int CALLBACK имя_функции(
   HWND hDlg,
   UINT uMsg,
   LONG lParam,
   LONG lData
);

Через параметр hDlg в нее будет передаваться дескриптор диалогового окна, а через параметр uMsg — один из следующих идентификаторов извещений:

BFFM_INITIALIZED
диалоговое окно полностью создано и инициализировано, но еще не выведено на экран (параметр lParam в этом случае равен нулю);
BFFM_SELCHANGED
пользователь выделил в дереве другую папку (параметр lParam содержит ее PIDL);
BFFM_VALIDATEFAILED
при создании диалогового был указан флаг BIF_VALIDATE и пользователь набрал в поле ввода недопустимое имя (параметр lParam содержит адрес строки с его копией).

В каждом из этих случаев через параметр lData в функцию передается значение, указанное в поле lParam структуры BROWSEINFO.

При обработке перечисленных извещений можно использовать функцию SendMessage для отправки диалоговому окну одного из следующих управляющих сообщений:

BFFM_ENABLEOK
разрешить (при lParam отличном от нуля) или запретить (при lParam равном нулю) кнопку OK;
BFFM_SETSELECTION
выделить в дереве объект, PIDL которого содержится в параметре lParam;
BFFM_SETSTATUSTEXT
назначает текст, отображаемый в статусной области (флаг BIF_STATUSTEXT), в соответствии со строкой, адрес которой указан в параметре lParam.
обновлено
29.03.2006
 
Проверка PR и ТИЦ