A COMPLETE SHBrowseForFolder wrapper class

Download Source Code and Example Download Source Code Only


This is the CBrowseForFolder class. I looked high and low to find a COMPLETE wrapper for the call to SHBrowseForFolder, and I couldn't find one, so I wrote my own. The idea is to derive from CBrowseForFolder to create a folder browser that behaves the way you want.

In the demo project, CSBDestination shows a really good example of what you can do.

-- BrowseForfolder.h --

//////////////////////////////////////////////////////////////////////
//
// ShellBrowser.h: interface for the CShellBrowser class.
//
// Copyright 1998 Scott D. Killen
//
//////////////////////////////////////////////////////////////////////

#ifndef __SHELLBROWSER_H__
#define __SHELLBROWSER_H__

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

#include 
#include 

//////////////////////////////////////////////////////////////////////
//
// CShellBrowser
//

class CBrowseForFolder
{
public:
	CBrowseForFolder(const HWND hParent = NULL,
			 const LPITEMIDLIST pidl = NULL,
			 const int nTitleID = 0);

	CBrowseForFolder(const HWND hParent,
			 const LPITEMIDLIST pidl,
			 const CString& strTitle);

	virtual ~CBrowseForFolder() = 0;

	//
	// Set the handle of the owner window for the dialog box.
	//
	void SetOwner(const HWND hwndOwner);

	//
	// Set the root of the heirarchy that will be browsed.  Get pidl from
	// SHGetSpecialFolderLocation.  This can be set to NULL to use the Virtual Folder
	// that represents the Windows Desktop.
	//
	void SetRoot(const LPITEMIDLIST pidl);

	//
	// Access a string that is displayed above the tree view control in the dialog box.
	// This string can be used to specify instructions to the user.  strTitle is a
	// CString containing the text to be displayed.  nTitle is the index of a string
	// resource to be loaded.  The return value is false if the resource could not be
	// loaded.
	//
	CString GetTitle() const;
	void SetTitle(const CString& strTitle);
	bool SetTitle(const int nTitle);

	//
	// ulFlags = Value specifying the types of folders to be listed in the dialog box
	// as well as other options. This member can include zero or more of the following
	// values:
	//
	//          BIF_BROWSEFORCOMPUTER    Only returns computers. If the user selects
	//                                   anything other than a computer, the OK button
	//                                   is grayed.
	//
	//          BIF_BROWSEFORPRINTER     Only returns printers. If the user selects
	//                                   anything other than a printer, the OK button
	//                                   is grayed.
	//
	//          BIF_DONTGOBELOWDOMAIN    Does not include network folders below the
	//                                   domain level in the tree view control.
	//
	//          BIF_RETURNFSANCESTORS    Only returns file system ancestors. If the user
	//                                   selects anything other than a file system
	//                                   ancestor, the OK button is grayed.
	//
	//          BIF_RETURNONLYFSDIRS     Only returns file system directories. If the
	//                                   user selects folders that are not part of the
	//                                   file system, the OK button is grayed.
	//
	//          BIF_STATUSTEXT           Includes a status area in the dialog box. The
	//                                   callback function can set the status text by
	//                                   sending messages to the dialog box. 
	//
	UINT GetFlags() const;
	void SetFlags(const UINT ulFlags);

	//
	// Call GetSelectedFolder to retrieve the folder selected by the user.
	//
	CString GetSelectedFolder() const;

	//
	// Function to retreive the image associated with the selected folder. The image is
	// specified as an index to the system image list. 
	//
	int GetImage() const;

	//
	// Call SelectFolder to display the dialog and get a selection from the user.  Use
	// GetSelectedFolder and GetImage to get the results of the dialog.
	//
	bool SelectFolder();

protected:
	//
	// OnInit is called before the dialog is displayed on the screen.
	//
	virtual void OnInit() const;

	//
	// OnSelChanged is called whenever the user selects a different directory.  pidl is
	// the LPITEMIDLIST of the new selection.  Use SHGetPathFromIDList to retrieve the
	// path of the selection.
	//
	virtual void OnSelChanged(const LPITEMIDLIST pidl) const;

	//
	// Call EnableOK to enable the OK button on the active dialog.  If bEnable is true
	// then the button is enabled, otherwise it is disabled.
	// NOTE -- This function should only be called within overrides of OnInit and
	// OnSelChanged.
	//
	void EnableOK(const bool bEnable) const;

	//
	// Call SetSelection to set the selection in the active dialog.  pidl is the
	// LPITEMIDLIST
	// of the path to be selected.  strPath is a CString containing the path to be
	// selected.
	// NOTE -- This function should only be called within overrides of OnInit and
	// OnSelChanged.
	//
	void SetSelection(const LPITEMIDLIST pidl) const;
	void SetSelection(const CString& strPath) const;

	//
	// Call SetStatusText to set the text in the Status area in the active dialog.
	// strText is the text to be displayed.
	// NOTE -- This function should only be called within overrides of OnInit and
	// OnSelChanged.
	//
	void SetStatusText(const CString& strText) const;

private:
	static int __stdcall BrowseCallbackProc(HWND hwnd,
						UINT uMsg,
						LPARAM lParam,
						LPARAM lpData);

	typedef std::auto_ptr AUTO_STR;
	AUTO_STR m_pchTitle;

	BROWSEINFO m_bi;
	char m_szSelected[MAX_PATH];
	CString m_strPath;
	HWND m_hwnd;
};

inline UINT CBrowseForFolder::GetFlags() const
{
	return m_bi.ulFlags;
}

inline int CBrowseForFolder::GetImage() const
{
	return m_bi.iImage;
}

#endif // __SHELLBROWSER_H__

-- BrowseForFolder.cpp -- ////////////////////////////////////////////////////////////////////// // // ShellBrowser.cpp: implementation of the CShellBrowser class. // #include "stdafx.h" #include "BrowseForFolder.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // // Construction/Destruction // CBrowseForFolder::CBrowseForFolder(const HWND hParent /*= NULL*/, const LPITEMIDLIST pidl /*= NULL*/, const int nTitleID /*= 0*/) { m_hwnd = NULL; SetOwner(hParent); SetRoot(pidl); SetTitle(nTitleID); m_bi.lpfn = BrowseCallbackProc; m_bi.lParam = reinterpret_cast(this); m_bi.pszDisplayName = m_szSelected; } CBrowseForFolder::CBrowseForFolder(const HWND hParent, const LPITEMIDLIST pidl, const CString& strTitle) { m_hwnd = NULL; SetOwner(hParent); SetRoot(pidl); SetTitle(strTitle); m_bi.lpfn = BrowseCallbackProc; m_bi.lParam = reinterpret_cast(this); m_bi.pszDisplayName = m_szSelected; } CBrowseForFolder::~CBrowseForFolder() { } ////////////////////////////////////////////////////////////////////// // // Implementation // void CBrowseForFolder::SetOwner(const HWND hwndOwner) { if (m_hwnd != NULL) return; m_bi.hwndOwner = hwndOwner; } void CBrowseForFolder::SetRoot(const LPITEMIDLIST pidl) { if (m_hwnd != NULL) return; m_bi.pidlRoot = pidl; } CString CBrowseForFolder::GetTitle() const { return m_bi.lpszTitle; } void CBrowseForFolder::SetTitle(const CString& strTitle) { if (m_hwnd != NULL) return; m_pchTitle = std::auto_ptr(new char [static_cast(strTitle.GetLength()) + 1]); strcpy(m_pchTitle.get(), strTitle); m_bi.lpszTitle = m_pchTitle.get(); } bool CBrowseForFolder::SetTitle(const int nTitle) { if (nTitle <= 0) return false; CString strTitle; if(!strTitle.LoadString(static_cast(nTitle))) { return false; } SetTitle(strTitle); return true; } void CBrowseForFolder::SetFlags(const UINT ulFlags) { if (m_hwnd != NULL) return; m_bi.ulFlags = ulFlags; } CString CBrowseForFolder::GetSelectedFolder() const { return m_szSelected; } bool CBrowseForFolder::SelectFolder() { bool bRet = false; LPITEMIDLIST pidl; if ((pidl = ::SHBrowseForFolder(&m_bi)) != NULL) { m_strPath.Empty(); if (SUCCEEDED(::SHGetPathFromIDList(pidl, m_szSelected))) { bRet = true; m_strPath = m_szSelected; } LPMALLOC pMalloc; //Retrieve a pointer to the shell's IMalloc interface if (SUCCEEDED(SHGetMalloc(&pMalloc))) { // free the PIDL that SHBrowseForFolder returned to us. pMalloc->Free(pidl); // release the shell's IMalloc interface (void)pMalloc->Release(); } } m_hwnd = NULL; return bRet; } void CBrowseForFolder::OnInit() const { } void CBrowseForFolder::OnSelChanged(const LPITEMIDLIST pidl) const { (void)pidl; } void CBrowseForFolder::EnableOK(const bool bEnable) const { if (m_hwnd == NULL) return; (void)SendMessage(m_hwnd, BFFM_ENABLEOK, static_cast(bEnable), NULL); } void CBrowseForFolder::SetSelection(const LPITEMIDLIST pidl) const { if (m_hwnd == NULL) return; (void)SendMessage(m_hwnd, BFFM_SETSELECTION, FALSE, reinterpret_cast(pidl)); } void CBrowseForFolder::SetSelection(const CString& strPath) const { if (m_hwnd == NULL) return; (void)SendMessage(m_hwnd, BFFM_SETSELECTION, TRUE, reinterpret_cast(LPCTSTR(strPath))); } void CBrowseForFolder::SetStatusText(const CString& strText) const { if (m_hwnd == NULL) return; (void)SendMessage(m_hwnd, BFFM_SETSTATUSTEXT, NULL, reinterpret_cast(LPCTSTR(strText))); } int __stdcall CBrowseForFolder::BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) { CBrowseForFolder* pbff = reinterpret_cast(lpData); pbff->m_hwnd = hwnd; if (uMsg == BFFM_INITIALIZED) pbff->OnInit(); else if (uMsg == BFFM_SELCHANGED) pbff->OnSelChanged(reinterpret_cast(lParam)); return 0; }

Last updated: 5 June 1998


Comments

  • Need Contact Information

    Posted by Manoj Prajapat on 10/07/2015 04:58am

    Hi Bill Hi Scott Greetings!!! Myself Manoj Prajapat, I need your email ID for private message to contact you regarding licensing of your code to use in commercial application. Can you please share your email ID. Thanks a lot.

    • Re:Need Contact Information

      Posted by on 10/07/2015 08:31am

      Manoj -Code posted on this site falls under the following permission statement unless the article says otherwise:Permissions As you know, this site is a valuable resource for the developer community. Please note, however, that to avoid legal complications, we need to obtain your permission to use any computer code and any related materials ("resources") that you are providing to us. Accordingly, by submitting any such resource to CodeGuru, you grant to QuinStreet a nonexclusive, worldwide, perpetual license to reproduce, distribute, adapt, perform, display, and sublicense the submitted resource (in both object and source code formats, as well as on and off the Web), and you acknowledge that you have the authority to grant such rights to QuinStreet.By submitting the resource, you also grant your article's readers the permission to use any source code in the resource for commercial or noncommercial software. PLEASE NOTE THAT YOU RETAIN OWNERSHIP OF ANY COPYRIGHTS IN ANY RESOURCES SUBMITTED!ALSO, IN MAKING THE RESOURCE AVAILABLE TO OTHER SITE VISITORS FOR DOWNLOADING, QUINSTREET WILL INFORM SUCH OTHER VISITORS THAT, ALTHOUGH THEY MAY DOWNLOAD ANY RESOURCES FOR COMMERCIAL OR NONCOMMERCIAL USES, THEY MAY NOT REPUBLISH THE SOURCE CODE SO THAT IT IS ACCESSIBLE TO THE PUBLIC WITHOUT FIRST OBTAINING THE COPYRIGHT OWNER'S PERMISSION.

      Reply
    Reply
  • Licensing

    Posted by Joel on 07/30/2014 08:52am

    Hi Scott Would you please share the license that governs this code? Regards.

    • Re:Licensing

      Posted by on 09/08/2014 07:31am

      The intent of posting code on this site is so that others can learn from it and thus use the code. Code on this site is free to be reused unless the author has explicitly stated something within the article or code.Brad! Jones, Codeguru admin

      Reply
    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Complex hybrid environments can make it difficult to track interdependencies, increasing the risk of disrupting critical business services. In this white paper by EMA, you'll learn how application discovery and dependency mapping can help you: Meet granular targets for availability, cost, and time-to-revenue for cloud services. Accelerate mean time to repair (MTTR) while communicating better with stakeholders. Manage even the most complex hybrid environments more efficiently and effectively Understand the …

  • Rocket Mobile® for IBM i is an enterprise mobile application development and deployment platform for customers who rely on the IBM i system. Rocket Mobile for IBM i enables customers to leave proven applications in-place and rapidly repurpose them into new managed and secure mobile applications. Fast, easy creation of mobile, web, and hybrid mobile applications that deploy to any iOS, Android, or Windows mobile phone or tablet Built-in integration for seamless repurposing of existing IBM i applications …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date