Entry tags:
Выбор каталога
В виндах есть диалог для выбора каталога SHBrowseForFolder. В работе сие позорище выглядит так:

Не буду объяснять, насколько оно неудобно - если разок столкнетесь, то поймете на опыте.
Вместо этого хотелось бы иметь диалог, подобный тем, что дают функции GetSaveFileName/GetOpenFileName. Что-то в таком роде:

Осталось понять, как этого добиться - ведь те функции позволяют выбрать файл, а не фолдер. Под катом решение, опробованное на работоспособность под Win XP и Win 7. Можно прямо копипастить.

Не буду объяснять, насколько оно неудобно - если разок столкнетесь, то поймете на опыте.
Вместо этого хотелось бы иметь диалог, подобный тем, что дают функции GetSaveFileName/GetOpenFileName. Что-то в таком роде:

Осталось понять, как этого добиться - ведь те функции позволяют выбрать файл, а не фолдер. Под катом решение, опробованное на работоспособность под Win XP и Win 7. Можно прямо копипастить.
//ага, просто static, без выпендрежа
static WNDPROC wProcBase;
static char getFolderNameResult[_MAX_PATH];
//функция для субклассинга
LRESULT CALLBACK wProcNew(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg == WM_COMMAND && HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDOK)
{
//сохраняем путь в lpstrFile и выходим
SendMessage(hwnd, CDM_GETFILEPATH, _MAX_PATH, (LPARAM)getFolderNameResult);
//здесь можно проверить getFolderNameResult если надо чтобы это был существующий каталог, например так:
struct _stat buffer;
if (0 == _stat(fname, &buffer) && 0 != (buffer.st_mode & _S_IFDIR))
EndDialog(hwnd, IDOK);
return 0;
}
//вызов прежнего обработчика
return CallWindowProc(wProcBase, hwnd, msg, wParam, lParam);
}
//Hook-функция для диалога
static UINT_PTR CALLBACK OFNHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
if (uiMsg == WM_INITDIALOG)
{
//hdlg - это не сам диалог, а его child, так что на шаг вверх
HWND par= (HWND)GetWindowLong(hdlg, GWL_HWNDPARENT);
//субклассинг
wProcBase= (WNDPROC)GetWindowLong(par, GWL_WNDPROC);
SetWindowLong(par, GWL_WNDPROC, (LONG)wProcNew);
//скрываем лишние контролы, на некоторых меняем надпейси
SendMessage(par, CDM_HIDECONTROL, cmb1, NULL);
SendMessage(par, CDM_HIDECONTROL, stc2, NULL);
SendMessage(par, CDM_SETCONTROLTEXT, stc3, (LPARAM)"Folder:");
SendMessage(par, CDM_SETCONTROLTEXT, IDOK, (LPARAM)"Accept");
SendMessage(par, CDM_SETCONTROLTEXT, stc4, (LPARAM)"In folder:");
return 0;
}
return 0;
}
//на входе надо заполнить ofn так, как будто хотим сохранить файл
//в каталоге. на выходе результат будет в ofn->lpstrFile.
int GetFolderName(OPENFILENAME *ofn)
{
ofn->Flags|= OFN_EXPLORER|OFN_ENABLEHOOK;
ofn->lpfnHook= OFNHookProc;
ofn->lpstrCustomFilter= NULL;
ofn->nFilterIndex= 0;
ofn->lpstrFilter= " \0:\0\0"; //фильтр, который гарантирует показ только каталогов, но не файлов
ofn->lpstrTitle= "Select Folder...";
int r= GetSaveFileName(ofn);
strcpy(ofn->lpstrFile, getFolderNameResult);
ofn->nFileOffset= (WORD)strlen(getFolderNameResult);
return r;
}

no subject
А ты могилы выкапивал?
no subject