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