Thread: multiple selection folder chooser

  1. #1
    Registered User
    Join Date
    Nov 2003
    Posts
    9

    multiple selection folder chooser

    I have been looking all around, but I cannot find a way to make a win32 multiple selection folder chooser, not file chooser. It can be win32 api, or managed .NET, I just need to figure this out. Thanks a lot in advance.

  2. #2
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    The best solution would be to create your own control. Here are a couple of .NET projects you can leverage:
    Explorer Tree .NET Control
    FolderTreeView .NET Control

    The other alternative is to hack an existing API to do what you want. The danger of extending a control that you don't own is that it will change (or has changed) and your extension may fail. All the same, here is my code that extends SHBrowseForFolder to select multiple folders.
    Code:
    #include <windows.h>
    #include <shlobj.h>
    #include <objbase.h>
    #include <stdio.h>
    
    #if defined(_MSC_VER)
    #pragma comment(lib, "shell32.lib")
    #pragma comment(lib, "ole32.lib")
    #endif
    
    /*
     * Structure to hold information needed for hacking the SHBrowseForFolder
     * dialog. Probably should be per-instance but we'll use a global for simplicity.
     */
    struct
    {
        WNDPROC oldWndProc;
        TCHAR   szLastSelection[MAX_PATH];
        UINT    cFolders;
    } g_Multi;
    
    
    /*
     * Subclassed window procedure for dialog created by SHBrowseForFolder. 
     */
    static LRESULT CALLBACK SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        if (uMsg == WM_COMMAND && HIWORD(wParam) == BN_CLICKED)
        {
            TCHAR szText[50];
    
            if (GetWindowText((HWND) lParam, szText, 50) &&
                0 == lstrcmp(szText, TEXT("Add Folder")))
            {
                if (0 != lstrcmp(g_Multi.szLastSelection, TEXT("")))
                {
                    g_Multi.cFolders++;
    
                    /* User has clicked the "Add Folder" button.
                     * Add the contents of szLastSelection to your list. */
                    printf("%s\n", g_Multi.szLastSelection);
                }
                else
                {
                    /* A non-file system folder is selected. eg. Network Neighbourhood. */
                    printf("Please select a valid file folder and try again.\n");
                }
    
                /* Eat the BN_CLICKED message so the dialog is not closed. */
                return 0;
            }
        }
    
        return CallWindowProc(g_Multi.oldWndProc, hwnd, uMsg, wParam, lParam);
    }
    
    
    /*
     * Callback function for SHBrowseForFolder.
     */
    static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
    {
        switch (uMsg)
        {
            case BFFM_INITIALIZED:
            {
                /* Change the text for the OK button and subclass the dialog. */
                SendMessage(hwnd, BFFM_SETOKTEXT, 0, (LPARAM) L"Add Folder");
                g_Multi.oldWndProc = (WNDPROC) SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) SubclassProc);
                break;
            }
    
            case BFFM_SELCHANGED:
            {
                /* Record the selection, so we can record it if the user clicks "Add Folder". */
                if (!SHGetPathFromIDList((LPCITEMIDLIST) lParam, g_Multi.szLastSelection))
                    g_Multi.szLastSelection[0] = TEXT('\0');
                break;
            }
        }
    
        return 0;
    }
    
    
    /*
     * Displays a directory selection dialog that allows the user to select
     * multiple folders. CoInitialize must be called before calling this function.
     * hWnd may be NULL. Returns the number of folders that were selected.
     * This function is not thread safe. It must not be called from more than
     * one thread at a time.
     */
    UINT MultiFolderSelect(HWND hWnd, LPCTSTR szTitle)
    {
        LPITEMIDLIST pidl           = NULL;
        BROWSEINFO   bi             = { 0 };
        TCHAR        buf[MAX_PATH];
    
        bi.hwndOwner      = hWnd;
        bi.pszDisplayName = buf;
        bi.pidlRoot       = NULL;
        bi.lpszTitle      = szTitle;
        bi.ulFlags        = BIF_RETURNONLYFSDIRS | BIF_USENEWUI;
        bi.lpfn           = BrowseCallbackProc;
    
        g_Multi.cFolders           = 0;
        g_Multi.szLastSelection[0] = TEXT('\0');
    
        if ((pidl = SHBrowseForFolder(&bi)) != NULL)
            CoTaskMemFree(pidl);
    
        return g_Multi.cFolders;
    }
    
    #if 1
    #include <stdio.h>
    
    int main(void)
    {
        UINT cFoldersAdded;
    
        CoInitialize(NULL);
    
        cFoldersAdded = MultiFolderSelect(NULL, TEXT("Please add some folders."));
        printf("Test1: %u folders were added.\n", cFoldersAdded);
    
        cFoldersAdded = MultiFolderSelect(NULL, TEXT("Please add some folders."));
        printf("Test2: %u folders were added.\n", cFoldersAdded);
    
        CoUninitialize();
    
        getchar();
        return 0;
    }
    #endif
    Last edited by anonytmouse; 02-06-2005 at 09:25 PM. Reason: Added CoUninitialize & wrapped pragmas (Thanks for the tip).

  3. #3
    Registered User
    Join Date
    Nov 2003
    Posts
    9
    thanks so much, but that is not exactly what I am looking for. Is it possible to make it so the user could select all the directories, and then press ok. I took a look at the .net projects, but they also don't seem to support the type of multiple selection I am looking for, and I am new to .NET, so that may not be the best option. Thanks
    Last edited by Corrington_j; 02-07-2005 at 06:54 PM.

  4. #4
    Registered User
    Join Date
    Nov 2003
    Posts
    9
    ok, actually its working fine for what I am doing. However it doesn't appear to work on win 98, are some of the function just for win xp or what?

  5. #5
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    It turns out that BIF_USENEWUI needs at least Windows ME or 2000. So change:
    Code:
        bi.ulFlags        = BIF_RETURNONLYFSDIRS | BIF_USENEWUI;
    to:
    Code:
        bi.ulFlags        = BIF_RETURNONLYFSDIRS;
    This will mean that the old dialog is used on all platforms. If you want the new dialog to be used where available, you can use GetVersionEx to check the windows version and use the flag if available on that platform. I should have mentioned that you may get duplicates in your list.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. accessing all files in a folder.
    By pastitprogram in forum C++ Programming
    Replies: 15
    Last Post: 04-30-2008, 10:56 AM
  2. selection problem
    By Ken JS in forum C Programming
    Replies: 3
    Last Post: 08-04-2007, 09:47 PM
  3. Folder selection menu using Common Dialog Box?
    By Devil Panther in forum Windows Programming
    Replies: 6
    Last Post: 04-29-2007, 01:09 PM
  4. Linker errors - Multiple Source files
    By nkhambal in forum C Programming
    Replies: 3
    Last Post: 04-24-2005, 02:41 AM
  5. Sorry just one more (case Multiple Selection)
    By Prezo in forum C++ Programming
    Replies: 2
    Last Post: 09-15-2002, 06:34 AM