Win32 - Выбрать каталог из C/С++
Как выбрать существующую папку (или создать новую) из собственного приложения Win32?
Вот аналогичный вопрос. Он имеет хороший ответ для С#/. NET. Но я хочу то же самое для собственного Win32.
Кто-нибудь знает решение, бесплатный код и т.д.
Update:
Я попробовал функцию из ответа. Все работало, как ожидалось, за исключением того, что необходимо вызвать функцию SHGetPathFromIDList
для получения имени выбранной директории. Вот пример экрана:
![Example of the directory pickup dialog.]()
Ответы
Ответ 1
SHBrowseForFolder
Сделайте одолжение своим пользователям и установите хотя бы флаг BIF_NEWDIALOGSTYLE
.
Чтобы установить исходную папку, добавьте следующий код:
static int CALLBACK BrowseFolderCallback(
HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
if (uMsg == BFFM_INITIALIZED) {
LPCTSTR path = reinterpret_cast<LPCTSTR>(lpData);
::SendMessage(hwnd, BFFM_SETSELECTION, true, (LPARAM) path);
}
return 0;
}
// ...
BROWSEINFO binf = { 0 };
...
binf.lParam = reinterpret_cast<LPARAM>(initial_path_as_lpctstr);
binf.lpfn = BrowseFolderCallback;
...
и укажите подходящий путь (например, запомните последний выбор, папку с данными ваших приложений и т.п.)
Ответ 2
Как и для будущих пользователей, эта статья очень помогла мне получить диалог каталога на С++
http://www.codeproject.com/Articles/2604/Browse-Folder-dialog-search-folder-and-all-sub-fol
Вот мой код (сильно основанный на статье)
ПРИМЕЧАНИЕ. Вы должны иметь возможность скопировать/вставить это в файл/скомпилировать его (g++, см. VS в редакторе ninja ниже), и он будет работать.
#include <windows.h>
#include <string>
#include <shlobj.h>
#include <iostream>
#include <sstream>
static int CALLBACK BrowseCallbackProc(HWND hwnd,UINT uMsg, LPARAM lParam, LPARAM lpData)
{
if(uMsg == BFFM_INITIALIZED)
{
std::string tmp = (const char *) lpData;
std::cout << "path: " << tmp << std::endl;
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
}
return 0;
}
std::string BrowseFolder(std::string saved_path)
{
TCHAR path[MAX_PATH];
const char * path_param = saved_path.c_str();
BROWSEINFO bi = { 0 };
bi.lpszTitle = ("Browse for folder...");
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
bi.lpfn = BrowseCallbackProc;
bi.lParam = (LPARAM) path_param;
LPITEMIDLIST pidl = SHBrowseForFolder ( &bi );
if ( pidl != 0 )
{
//get the name of the folder and put it in path
SHGetPathFromIDList ( pidl, path );
//free memory used
IMalloc * imalloc = 0;
if ( SUCCEEDED( SHGetMalloc ( &imalloc )) )
{
imalloc->Free ( pidl );
imalloc->Release ( );
}
return path;
}
return "";
}
int main(int argc, const char *argv[])
{
std::string path = BrowseFolder(argv[1]);
std::cout << path << std::endl;
return 0;
}
EDIT: Я обновил код, чтобы показать людям, как запомнить последний выбранный путь и использовать его.
Кроме того, для VS используется набор символов Unicode. замените эту строку:
const char * path_param = saved_path.c_str();
При этом:
std::wstring wsaved_path(saved_path.begin(),saved_path.end());
const wchar_t * path_param = wsaved_path.c_str();
Мой тестовый код выше скомпилирован с g++, но для этого он исправил его в VS для меня.
Ответ 3
Для Windows Vista и выше лучше использовать IFileDialog с опцией FOS_PICKFOLDERS для правильного открытого диалога, а не этого дерева диалога. Видеть https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/bb776913(v=vs.85)