Click here to Skip to main content
Click here to Skip to main content

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

, 30 Aug 2002
Rate this:
Please Sign up or sign in to vote.
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

Share

About the Author

Mingming Lu
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 PinmemberJoe ce00113-Dec-05 21:05 
GeneralRe: WinCe PinmemberMichP19-Oct-09 12:38 
GeneralHeap error PinmemberGolf-HotelDelta16-Jun-05 10:19 
GeneralRe: Heap error PinmemberTygarsai2-Nov-05 15:51 
GeneralRe: Heap error Pinmemberbigkiller28-Apr-06 5:52 
Generalerror on return of every &quot;deeper&quot; path Pinmemberscoroop7-Dec-04 14:15 
GeneralMultiple edit boxes! PinmemberkaStefan29-Aug-03 5:23 
GeneralRe: Multiple edit boxes! Pinmemberkam2uh30-Oct-03 8:06 
GeneralRe: Multiple edit boxes! PinmemberCarsonK26-Feb-04 11:16 
GeneralBIF_STATUSTEXT PinmemberThorell28-Apr-03 3:01 
GeneralRe: BIF_STATUSTEXT PinmemberThorell8-May-03 0:36 
QuestionHow to set the root? PinmemberThorell25-Apr-03 2:20 
AnswerRe: How to set the root? PinmemberThorell25-Apr-03 2:34 
AnswerRe: How to set the root? PinmemberThorell25-Apr-03 4:08 
GeneralRe: How to set the root? PinmemberSco++17-Nov-03 13:46 
GeneralRe: How to set the root? Pinmembervlar12-Dec-03 16:08 
QuestionHow to show CREATE Button? Pinmemberlenghost2-Jan-03 3:17 
AnswerRe: How to show CREATE Button? PinmemberMingming Lu7-Jan-03 16:08 
GeneralRe: How to show CREATE Button? PinmemberVic Mackey28-Dec-04 4:23 
QuestionOpening to the current dir? PinmemberJon Bond12-Nov-02 1:33 
AnswerRe: Opening to the current dir? PinmemberMingming Lu7-Jan-03 16:17 
GeneralRe: Opening to the current dir? Pinmembereric feng10-Jun-04 16:12 
GeneralThanks, That's exactly what I want! PinsussDingDing5-Nov-02 12:52 
Generalcreate function PinmemberKevin Pinkerton3-Sep-02 2:24 
GeneralRe: create function PinmemberKevin Pinkerton3-Sep-02 2:34 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141220.1 | Last Updated 31 Aug 2002
Article Copyright 2002 by Mingming Lu
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid