Win32 - Select Directory Dialog from C/C++

前端 未结 3 2062
我在风中等你
我在风中等你 2020-12-23 18:11

How to select an existing folder (or create new) from a native Win32 application?

Here is a similar question. It has a good answer for C#/.NET. But I want the same t

相关标签:
3条回答
  • 2020-12-23 18:36

    SHBrowseForFolder

    Do your users a favor, and set at least the BIF_NEWDIALOGSTYLE flag.

    To set the initial folder, add the following code:

    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;
    ...
    

    and provide a suitable path (such as remembering the last selection, your applications data folder, or similar)

    0 讨论(0)
  • 2020-12-23 18:52

    For Windows Vista and above, it's best to use IFileOpenDialog with the FOS_PICKFOLDERS option for a proper open dialog rather than this tree dialog. See Common Item Dialog on MSDN for more details.

    0 讨论(0)
  • 2020-12-23 18:56

    Just as a go to for future users, this article helped me a lot with getting a directory dialog in C++

    http://www.codeproject.com/Articles/2604/Browse-Folder-dialog-search-folder-and-all-sub-fol

    Here is my code (heavily based/taken on the article)

    NOTE: You should be able to copy/paste this into a file / compile it (g++, see VS in ninja edit below) and it'll work.

    #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: I've updated the code to show people how to remember the last selected path and use that.

    Also, for VS, using Unicode character set. replace this line:

    const char * path_param = saved_path.c_str();
    

    With this:

    std::wstring wsaved_path(saved_path.begin(),saved_path.end());
    const wchar_t * path_param = wsaved_path.c_str();
    

    My Test code above is compiled with g++, but doing this fixed it in VS for me.

    0 讨论(0)
提交回复
热议问题