psilogic: (Default)
psilogic ([personal profile] psilogic) wrote2010-02-03 07:16 pm

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

В виндах есть диалог для выбора каталога 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;
}


[identity profile] gaussrifle.livejournal.com 2010-02-06 09:40 am (UTC)(link)
А со мной еще Кесседи был и тоже с гаусовкой. Жалко на метерикое к гауссовке патронов всего 50 было у двух охранников великого дракона и добыча этих 50-ти патронов стоила жизни всему китайскому населению Сан-Франциско :)

[identity profile] leo-sosnine.livejournal.com 2010-02-06 10:00 am (UTC)(link)
Кэссиди не стоит давать гауссовку из-за нехватки патронов. Маловато хитов он из неё вышибает, тока патроны переводить. Вообще, следует признать, что во втором фоллауте если играть боевым персонажем, то команда только мешает. Лезут на амбразуры, постоянно попадают под очередь из минигана, дамэйдж выдают просто никакой по сравнению с прокаченным персом.

Патроны для гауссовки продаёт верхний продавец в сан-фране у входа, правда, у него обновляются они редко, приходится ждать.

[identity profile] gaussrifle.livejournal.com 2010-02-06 11:11 am (UTC)(link)
Спасибо! Жаль я не знал этого 12 лет назад.

[identity profile] psilogic.livejournal.com 2010-02-06 10:15 am (UTC)(link)
чо та из второго фаллаута запомнились тока муравьи, плюющаяся колючками трава и взорванный туалет =)

[identity profile] gaussrifle.livejournal.com 2010-02-06 11:12 am (UTC)(link)
взорваный туалет это да!

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

[identity profile] psilogic.livejournal.com 2010-02-06 11:20 am (UTC)(link)
че та не помню такого...