Мирослав Войнаровский (psilogic) wrote,
Мирослав Войнаровский
psilogic

Выбор каталога

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



Не буду объяснять, насколько оно неудобно - если разок столкнетесь, то поймете на опыте.

Вместо этого хотелось бы иметь диалог, подобный тем, что дают функции 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;
}


Tags: Программирование
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 40 comments