Как выдать окно выбора каталога?
Автор: Игорь Ткачёв
Windows Shell API включает функцию SHBrowseForFolder, которая отображает стандартный диалог, с помощью которого пользователь может выбрать нужный каталог. На самом деле, выбрать можно не только каталог, а любой объект Shell namespace, в том числе принтеры и компьютеры. Ниже приведён пример использования этой функции:
#include <windows.h>
#include <shlobj.h>
#pragma comment(lib,"shell32")
bool GetFolder (LPTSTR szPath)
{
szPath[0] = 0;
bool result = false;
LPMALLOC pMalloc;
if (::SHGetMalloc(&pMalloc) == NOERROR) {
BROWSEINFO bi;
::ZeroMemory(&bi,sizeof bi);
bi.ulFlags = BIF_RETURNONLYFSDIRS;
LPITEMIDLIST pidl = ::SHBrowseForFolder(&bi);
if (pidl != NULL) {
if (::SHGetPathFromIDList(pidl,szPath))
result = true;
pMalloc->Free(pidl);
}
pMalloc->Release();
}
return result;
}
Хотя наша функция и делает то, что нам нужно, но, скорее всего, вы найдёте её возможности слишком скромными. С другой стороны возможности функции ::SHBrowseForFolder позволяют добавить следующую функциональность:
* Установка дескриптора окна-владельца диалога.
* Добавление заголовка к диалогу.
* Отображение текущего каталога.
* Установка каталога по умолчанию.
* Установка корневого каталога.
Я не вижу причин не использовать эти возможности. Изменим нашу функцию.
#include <windows.h>
#include <atlbase.h>
#include <shlobj.h>
#pragma comment(lib,"shell32")
static int CALLBACK
BrowseCallbackProc (HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
TCHAR szPath[_MAX_PATH];
switch (uMsg) {
case BFFM_INITIALIZED:
if (lpData)
SendMessage(hWnd,BFFM_SETSELECTION,TRUE,lpData);
break;
case BFFM_SELCHANGED:
SHGetPathFromIDList(LPITEMIDLIST(lParam),szPath);
SendMessage(hWnd, BFFM_SETSTATUSTEXT, NULL, LPARAM(szPath));
break;
}
return ;
}
BOOL GetFolder (LPCTSTR szTitle, LPTSTR szPath, LPCTSTR szRoot, HWND hWndOwner)
{
if (szPath == NULL)
return false;
bool result = false;
LPMALLOC pMalloc;
if (::SHGetMalloc(&pMalloc) == NOERROR) {
BROWSEINFO bi;
::ZeroMemory(&bi,sizeof bi);
bi.ulFlags = BIF_RETURNONLYFSDIRS;
bi.hwndOwner = hWndOwner;
bi.lpszTitle = szTitle;
bi.lpfn = BrowseCallbackProc;
bi.ulFlags |= BIF_STATUSTEXT;
bi.lParam = LPARAM(szPath);
if (szRoot != NULL) {
IShellFolder *pDF;
if (SHGetDesktopFolder(&pDF) == NOERROR) {
LPITEMIDLIST pIdl = NULL;
ULONG chEaten;
ULONG dwAttributes;
USES_CONVERSION;
LPOLESTR oleStr = T2OLE(szRoot);
pDF->ParseDisplayName(NULL,NULL,oleStr,&chEaten,&pIdl,&dwAttributes);
pDF->Release();
bi.pidlRoot = pIdl;
}
}
LPITEMIDLIST pidl = ::SHBrowseForFolder(&bi);
if (pidl != NULL) {
if (::SHGetPathFromIDList(pidl,szPath))
result = true;
pMalloc->Free(pidl);
}
if (bi.pidlRoot != NULL)
pMalloc->Free(bi.pidlRoot);
pMalloc->Release();
}
return result;
}
Прототип нашей функции может выглядеть следующим образом:
BOOL GetFolder(LPCTSTR szTitle,LPTSTR szPath,LPCTSTR szRoot=NULL,HWND hWndOwner=NULL);
При успешном выполнении функция возвращает TRUE и возвращает выбранный каталог по указателю szPath, Вы должны сами позаботиться о выделении необходимой памяти. Этот же параметр используется для задания каталога по умолчанию.
Это все на сегодня. Пока!
Алекс Jenter
jenter@rsdn.ru
Duisburg, 2001. Публикуемые в рассылке материалы принадлежат сайту RSDN.