Click here to Skip to main content
15,867,488 members
Articles / Desktop Programming / MFC
Article

How to show a dialog to let users browse for and select a folder

Rate me:
Please Sign up or sign in to vote.
4.61/5 (19 votes)
30 Aug 20024 min read 181.3K   3.4K   48   37
Shows how to use Windows shell functions to browse folders

Sample Image - screenshot.jpg

Introduction

Many times, I met situations where I want the user to choose a folder in the computer. Sometimes, even a special folder like Printer folder or My Computer. Some guys do it by sub-classing the common File Dialog. That's a way to do it, but not much neat to me. Actually, there are several Windows shell functions specific to do this job for us. After digging for some time, I'd like to share my experience with other coders in case you don't know how to do it.

Details

After you read through my demo code, you will agree that this is a convenient and small piece of code if you don't want too many special functionalities from it.

First, the function SHBrowseForFolder(LPBROWSEINFO lpbi) is the core part for browsing folders. It accepts one parameter which is a pointer to the structure BROWSEINFO. There're eight domains in this structure that you can use to customize your folder browser. However, we'll only use a few of them. That's enough for most programmers.

This is the block of code I used to bring out the browser.

void CFolderBrowserDlg::OnButtonBrowse() 
{
    // TODO: Add your control notification 
    // handler code here
    LPMALLOC pMalloc = NULL;
    LPITEMIDLIST pidl = NULL;
    BROWSEINFO bi;
    ZeroMemory(&bi, sizeof(BROWSEINFO));
    
    // set the bi's default values
    bi.hwndOwner = m_hWnd;
    bi.lpszTitle = _T("Current folder is:");
    bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT;
    bi.lpfn = BrowseCallbackProc;
    pidl = SHBrowseForFolder(&bi);
    if(pidl != NULL)
    {
        SHGetPathFromIDList(pidl, 
            m_strFolderPath.GetBuffer(
                m_strFolderPath.GetLength()));
        UpdateData(FALSE);
        // free memory
        if(SUCCEEDED(SHGetMalloc(&pMalloc)) && pMalloc);
        pMalloc->Free(pidl);  
        pMalloc->Release(); 
    }
}

First, we have to set hwndOwner to the handle of the main dialog. This is the only value we have to set. Then, we can set lpszTitle which is the string appearing above the tree view control of folders. ulFlags is a very important domain of BROWSEINFO. By setting the corresponding flag bits, we can get a bunch of functionalities. Here, we set it to BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT. BIF_RETURNONLYFSDIRS means the OK button will be enabled only when the user choose a file system folder instead of a special folder like "My Computer". Most of time, that's what we want. BIF_STATUSTEXT lets the dialog to have a label showing the folder you have chosen. You have to deal with this label in your callback function, which is set in the lpfn domain. It points to a callback function whose prototype is like

int CALLBACK BrowseCallbackProc(HWND hwnd,
UINT uMsg,
LPARAM lParam,
LPARAM dwData);

uMsg is just the code of message it receives. lParam is message dependent. And dwData is user-defined data and it may not be used for some messages. There're three kind of messages it can receive: BFFM_INITIALIZED, BFFM_SELCHANGED and BFFM_VALIDATEFAILED. Usually, we only process one of them BFFM_SELCHANGED(if you like, even this one is not necessary to be processed.). Here is my code for this function.

int CALLBACK BrowseCallbackProc(
    HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
    switch(uMsg)
    {
    case BFFM_INITIALIZED:
        {
            // add your initialization code here
        }
        break;

    case BFFM_SELCHANGED:
        {
            TCHAR szText[MAX_PATH] = {0};
            SHGetPathFromIDList(
                reinterpret_cast<LPITEMIDLIST>(lParam), szText);
            SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0,
                reinterpret_cast<LPARAM>(szText));
        }
        break;
    }

    return 0;
}

For message BFFM_SELCHANGED which means the user selects another folder, lParam is of type LPITEMIDLIST. By using function SHGetPathFromIDList(...), you can get the selected folder's path and save it to szText. Then, I send the browser a message BFFM_SETSTATUSTEXT to let it set the text in the label. Note that BFFM_SETSTATUSTEXT is the message that the callback function can send, but does not receive.

The return value of SHBrowseForFolder(...) is of type LPITEMIDLIST. If the user pressed OK button, you can get the folder's path by the same method I mentioned above. In my code, I save it to my member variable m_strFolderPath and update my main demo dialog. Finally, don't forget to release the memory your program has allocated. This is what LPMALLOC pMalloc is here for.

Pretty short code, isn't it? You can easily embed it into your program. Furthermore, there're many more functionalities you can find with SHBrowseForFolder(...). For example,

  • When your callback function processes message BFFM_INITIALIZED, you can add a 3-D edge to the text label. (But this function is not guaranteed in the future version of Windows.)
  • You can add a text field in the browser so that the user can input a folder by typing. Then, you can also check the validity of the user's input.
  • With this function, you can even get the handle of icon of the selected folder.
  • You can set the root folder of your browser so that users cannot browse folders outside that one.
  • And so on...

There're many more interesting stuff you can dig into with this function. But in most cases, my code should be enough to do the work. For further knowledge about it, I recommend you to read "Visual C++ Windows Shell Programming" by Dino Esposito which is one of very few good books on Windows Shell Programming.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
Hey you,
Out there in the cold,
Getting lonely, getting old,
Can you feel me?
Hey you,
Standing in the aisle,
With itchy feet and fading smile,
Can you feel me?
Hey you,
Don't help them to bury the light.
Don't give in without a fight.

Comments and Discussions

 
GeneralWinCe Pin
Joe ce00113-Dec-05 20:05
Joe ce00113-Dec-05 20:05 
GeneralRe: WinCe Pin
MichP19-Oct-09 11:38
MichP19-Oct-09 11:38 
GeneralHeap error Pin
Golf-HotelDelta16-Jun-05 9:19
Golf-HotelDelta16-Jun-05 9:19 
GeneralRe: Heap error Pin
Tygarsai2-Nov-05 14:51
Tygarsai2-Nov-05 14:51 
I was just using this code also in VC7 and ran into the same bug. I changed his section of code where he is calling SHGetPathFromIDList and it works great now.

What I did was when calling GetBuffer, instead of using GetLength() which is returning 0 since nothing was set in there yet I used GetBuffer(MAX_PATH). This seems to have fixed my problems.
GeneralRe: Heap error Pin
bigkiller28-Apr-06 4:52
bigkiller28-Apr-06 4:52 
Generalerror on return of every &quot;deeper&quot; path Pin
scoroop7-Dec-04 13:15
scoroop7-Dec-04 13:15 
GeneralMultiple edit boxes! Pin
kaStefan29-Aug-03 4:23
kaStefan29-Aug-03 4:23 
GeneralRe: Multiple edit boxes! Pin
MKaitschick30-Oct-03 7:06
MKaitschick30-Oct-03 7:06 
GeneralRe: Multiple edit boxes! Pin
CarsonK26-Feb-04 10:16
CarsonK26-Feb-04 10:16 
GeneralBIF_STATUSTEXT Pin
Thorell28-Apr-03 2:01
Thorell28-Apr-03 2:01 
GeneralRe: BIF_STATUSTEXT Pin
Thorell7-May-03 23:36
Thorell7-May-03 23:36 
QuestionHow to set the root? Pin
Thorell25-Apr-03 1:20
Thorell25-Apr-03 1:20 
AnswerRe: How to set the root? Pin
Thorell25-Apr-03 1:34
Thorell25-Apr-03 1:34 
AnswerRe: How to set the root? Pin
Thorell25-Apr-03 3:08
Thorell25-Apr-03 3:08 
GeneralRe: How to set the root? Pin
Sco++17-Nov-03 12:46
Sco++17-Nov-03 12:46 
GeneralRe: How to set the root? Pin
vlar12-Dec-03 15:08
vlar12-Dec-03 15:08 
QuestionHow to show CREATE Button? Pin
lenghost2-Jan-03 2:17
lenghost2-Jan-03 2:17 
AnswerRe: How to show CREATE Button? Pin
Mingming Lu7-Jan-03 15:08
Mingming Lu7-Jan-03 15:08 
GeneralRe: How to show CREATE Button? Pin
Vic Mackey28-Dec-04 3:23
Vic Mackey28-Dec-04 3:23 
QuestionOpening to the current dir? Pin
Jon Bond12-Nov-02 0:33
Jon Bond12-Nov-02 0:33 
AnswerRe: Opening to the current dir? Pin
Mingming Lu7-Jan-03 15:17
Mingming Lu7-Jan-03 15:17 
GeneralRe: Opening to the current dir? Pin
eric feng10-Jun-04 15:12
eric feng10-Jun-04 15:12 
GeneralThanks, That's exactly what I want! Pin
dingding5-Nov-02 11:52
dingding5-Nov-02 11:52 
Generalcreate function Pin
Kevin Pinkerton3-Sep-02 1:24
Kevin Pinkerton3-Sep-02 1:24 
GeneralRe: create function Pin
Kevin Pinkerton3-Sep-02 1:34
Kevin Pinkerton3-Sep-02 1:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.