Click here to Skip to main content
15,860,972 members
Articles / Desktop Programming / MFC

Selecting a Subfolder from a Particular Folder

Rate me:
Please Sign up or sign in to vote.
4.56/5 (10 votes)
23 Feb 2010CPOL2 min read 89.2K   2.9K   39   5
Restricting the user to browse and select from a particular folder
Sample Image - BrowsePF.jpg

Introduction

The Shell API function SHBrowseForFolder displays a dialog box that enables the user to select a Shell folder. The dialog box allows the user to select any folder because its root folder is Desktop (which contains My Documents, My Computer and My Network Places). Some applications need to restrict the user in the selection of folders. Restricting the selection for My Computer or My Network Places is easier. But restricting the user for a particular folder requires little manipulation.

Background

The function SHBrowseForFolder takes a pointer to the structure BROWSEINFO. This structure has eight members. One of the members,  pidlRoot, is a pointer to the structure ITEMIDLIST. If pidlRoot is NULL, the root folder is Desktop. One can use pre-defined CSIDL values such as CSIDL_MYDOCUMENTS, CSIDL_NETWORK, etc. If any other arbitrary folder is to be used as root folder, it should be appropriately converted to the structure ITEMIDLIST

The class CFoldersDialog puts the whole code for SHBrowseForFolder dialog. The function ConvertPathToLpItemIdList converts an arbitrary folder into ITEMIDLIST. This class can be used in MFC as well as SDK without making any changes. It can also be used in VC++.NET.

The function ConvertPathToLpItemIdList takes an arbitrary folder as string type input parameter. It first converts the string to OLECHAR. Then SHGetDesktopFolder function retrieves IShellFolder interface and calls the method ParseDisplayName. This method puts the OLECHAR form of root folder into ITEMIDLIST structure.

Using the Code

The function BrowseFolder is called from any other class by creating an object of CFoldersDialog. It first uses the function ConvertPathToLpItemIdList for converting string to ITEMIDLIST and then use its callback function BrowseCallbackProc.

C++
LPITEMIDLIST ConvertPathToLpItemIdList(const char *pszPath)
{
	LPITEMIDLIST  pidl = NULL;
	LPSHELLFOLDER pDesktopFolder = NULL;
	OLECHAR       olePath[MAX_PATH];
	ULONG         chEaten;
	HRESULT       hr;

	if (SUCCEEDED(SHGetDesktopFolder(&pDesktopFolder)))
	{
		MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszPath, -1, 
					olePath, MAX_PATH);
		hr = pDesktopFolder->ParseDisplayName(NULL, NULL, 
					olePath, &chEaten, &pidl, NULL);
		pDesktopFolder->Release();
		return pidl;
	}
	return NULL;
}

int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData) 
{
	switch(uMsg) 
	{
		case BFFM_SELCHANGED: 
		{
		   // Set the status window to the currently selected path.
		   if (SHGetPathFromIDList((LPITEMIDLIST) lp, szDir)) 
			  SendMessage(hwnd,BFFM_SETSTATUSTEXT, 0, (LPARAM)szDir);
		   break;
		}
        case BFFM_INITIALIZED:
        {
            SendMessage(hwnd, BFFM_SETSELECTION, 1,(LPARAM) szDir);
        }
        break;

		default:
		   break;
	}
	return 0;
}

int CFoldersDialog::BrowseFolder(HWND hWnd, CString RootPath)
{
	BROWSEINFO bi;
	TCHAR szDir[MAX_PATH];
	LPITEMIDLIST pidl;
	LPMALLOC pMalloc;
	int nRet = 0;

	if (SUCCEEDED(SHGetMalloc(&pMalloc))) 
	{
		ZeroMemory(&bi,sizeof(bi));
		bi.hwndOwner = hWnd;
		bi.pszDisplayName = 0;
		bi.lpszTitle = 0;
        char *pszRootPath = new char[RootPath.GetLength() + 1];
        wcstombs(pszRootPath, RootPath, RootPath.GetLength());
		bi.pidlRoot = ConvertPathToLpItemIdList(pszRootPath);
		if (bi.pidlRoot == NULL)
			nRet = 1;
		bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT;
		bi.lpfn = BrowseCallbackProc;

		pidl = SHBrowseForFolder(&bi);
		if (pidl) 
		   SHGetPathFromIDList(pidl,szDir);
		else
			nRet = 2;
		pMalloc->Free(pidl); 
		pMalloc->Release();
	}
	return nRet;
}

Points of Interest

The callback function displays the user selected subfolder at the top of the dialog. Once the user click the OK button, the folder value is transferred to the second text box in the first dialog box. The variable szDir is accessed from both CFoldersDialog and the calling class.

History

  • First version 1.0: April 27, 2003
  • Second version 2.0: February 22, 2010
    • Fixed bugs
    • Added Unicode support
    • Compiled demo project with Visual Studio 6, 2005, 2008 and 2010

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO GIPL
India India
Ahamad has done M.Tech. in Information Technology. He has 15 years software development experience. He started learning programming with GW-BASIC. He learnt COBOL, Pascal, Fortran, C, C++, Java and C#. He worked with DOS, Unix, Novel Netware and Windows platforms. He has been working on Microsoft technologies for the last 10 years. He worked with .NET, Visual C++, ATL COM/DCOM, Win SDK, MFC, WTL, Visual Basic, ASP, JavaScript, XML, OOAD and Rational Rose. He has written three books on Computer Science:

1. Programming in GW-BASIC, BPB Publications, New Delhi, 1993
2. Computer Science with C++, Allied Publishers, New Delhi, 1997
3. Introduction to C++, Allied Publishers, New Delhi. 1998

He enjoys playing badminton and musical keyboards in his spare time. He also participates in community activities. He can be reached by ahamadalisha@yahoo.com

Comments and Discussions

 
QuestionSet initial dir, and still be able to browse to parent folders. Pin
JPB77721-Sep-07 4:47
JPB77721-Sep-07 4:47 
AnswerRe: Set initial dir, and still be able to browse to parent folders. Pin
jpm24729-Nov-07 21:38
jpm24729-Nov-07 21:38 
GeneralFinding a digital camera folder Pin
Alex Evans13-Feb-05 19:44
Alex Evans13-Feb-05 19:44 
GeneralHelp with accessing folder Pin
vgandhi13-Jun-03 8:33
vgandhi13-Jun-03 8:33 
GeneralSome bugs Pin
Anders Dalvander27-Apr-03 9:03
Anders Dalvander27-Apr-03 9:03 

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.