原文链接:CYABFFW: Yet Another BrowseForFolder Wrapper
以良好的MFC风格将Shell API函数SHBrowseForFolder()
封装为一个
CWnd
子类。
使用示例1
:
CYABFFWdlg();
if
(IDOK
==
dlg.DoModal())

{
CStrings=dlg.GetPath();
//Dosomethingwith`s'
使用示例
2
:
CYABFFWdlg(_T(
"
Pleaseselectadirectory
"
),
//
Hinttouser
BIF_USE_NEWUI,
//
Flagsforthedlg
this
,
//
Parentwindow
CSIDL_DRIVES);
//
Rootofsearch
if
(IDOK
==
dlg.DoModal())

{
CStrings=dlg.GetPath();
//Dosomethingwith`s'
YABFFW.h
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->
classCYABFFW:publicCWnd


{
//Construction
public:

/**////Constructwithatextualhint,BFFflags,parentwindow,a
///rootfolderexpressedasaCSIDLvalue,andadefault
///selectionexpressedasatextualpath
CYABFFW(constCString&strHint=CString(),UINTnFlags=0U,
CWnd*pParentWnd=NULL,intnRootFolder=CSIDL_DESKTOP,
constCString&strDefaultSel=CString());

/**////ConstructwithadefaultselectionexpressedasaCSIDL
///value,atextualhint,BFFflags,parentwindow,&aroot
///folderexpressedasaCSIDLvalue
CYABFFW(intnDefaultSel,constCString&strHint=CString(),
UINTnFlags=0U,CWnd*pParentWnd=NULL,
intnRootFolder=CSIDL_DESKTOP);

/**////ConstructwithahintfromResource,BFFflags,parent
///window,arootfolderexpressedasaCSIDLvalue,anda
///defaultselectionexpressedasatextualpath
CYABFFW(intnHint,UINTnFlags=0U,CWnd*pParentWnd=NULL,
intnRootFolder=CSIDL_DESKTOP,
constCString&strDefaultSel=CString());

/**////ConstructwithahintfromResource,adefaultselection
///expressedasaCSIDLvalue,BFFflags,parentwindow,&a
///rootfolderexpressedasaCSIDLvalue
CYABFFW(intnDefaultSel,intnHint,UINTnFlags=0U,
CWnd*pParentWnd=NULL,intnRootFolder=CSIDL_DESKTOP);

/**////Constructwithatextualhint,anarbitraryrootfolder,
///BFFflags,aparentwindow,andadefaultselection
///expressedasatextualpath
CYABFFW(constCString&strHint,constCString&strRoot,
UINTnFlags=0U,CWnd*pParentWnd=NULL,
constCString&strDefaultSel=CString());

/**////Constructwithatextualhint,adefaultselection
///expressedasaCSIDLvalue,anarbitraryrootfolder,BFF
///flags,&aparentwindow
CYABFFW(intnDefaultSel,constCString&strHint,constCString&strRoot,
UINTnFlags=0U,CWnd*pParentWnd=NULL);

/**////ConstructwithahintfromResource,anarbitraryroot
///folder,BFFflags,aparentwidnow,andatextualdefault
///selection
CYABFFW(intnHint,constCString&strRoot,UINTnFlags=0U,
CWnd*pParentWnd=NULL,
constCString&strDefaultSel=CString());

/**////ConstructwithahintfromResource,adefaultselection
///expressedasaCSIDLvalue,anarbitraryrootfolder,BFF
///flags,&aparentwidnow
CYABFFW(intnDefaultSel,intnHint,constCString&strRoot,
UINTnFlags=0U,CWnd*pParentWnd=NULL);

//Attributes
public:

/**////Retrievethedisplaynameoftheselecteditem
CStringGetDisplayName()const;

/**////RetrievetheITEMIDLISToftheselecteditem
LPCITEMIDLISTGetItemIdList()const;

/**////Retrievethepathtotheselecteditem
CStringGetPath()const;

//Operations
public:

/**////DisplaytheDialog-returnsIDOKorIDCANCEL
intDoModal();
//Overrides
public:

/**////CalledwhentheBFFDialoghasinitialized
virtualvoidOnInitBFFDialog();

/**////Calledwhentheselectionhaschangedinthetreecontrol
virtualvoidOnBFFSelChanged(LPITEMIDLISTpNewSel);

/**////Calledwhentheusertypesaninvalidname
virtualBOOLOnBFFValidateFailed(constCString&strBadName);

//ClassWizardgeneratedvirtualfunctionoverrides
//{{AFX_VIRTUAL(CYABFFW)
//}}AFX_VIRTUAL

//Implementation
public:
virtual~CYABFFW();

//Generatedmessagemapfunctions
protected:
//{{AFX_MSG(CYABFFW)NOTE-theClassWizardwilladdandremove
//memberfunctionshere.
//}}AFX_MSG
DECLARE_MESSAGE_MAP()

private:

/**////StaticmethodtobeusedfortheSHBFFcallback
staticintCALLBACKBrowseCallbackProc(HWNDhWnd,UINTnMsg,
LPARAMlParam,
LPARAMlpData);

private:

/**////Freethememoryreferencedbym_pItemIdList
voidFreeItemIdList(IMalloc*pMalloc=NULL);

/**////CSIDL=>ITEMIDLIST
LPITEMIDLISTResolveCsidl(intnCsidl)const;

/**////Textualfilesystempath=>ITEMIDLIST
LPITEMIDLISTResolveFsPath(constCString&strPath)const;

private:

/**////Displaynameoftheselecteditem
CStringm_strDisplayName;

/**////Flagstobepassedtothebrowsedialog
UINTm_nFlags;

/**////"Hint"tobedisplayedabovethetreecontrol
CStringm_strHint;

/**////ITEMIDLISTidentifyingtheselectedShellitem
LPITEMIDLISTm_pItemIdList;

/**////ParentCWnd(NULL=>Appmainwindow)
CWnd*m_pParentWnd;

/**////Selectedpath
CStringm_strPath;

/**////ITEMIDLISTidentifyingtheroot
LPITEMIDLISTm_pRoot;

/**////Defaultselection,ifgivenastext(emptyifnone)
CStringm_strDefaultSel;

/**////Defaultselection,ifgivenasaCSIDLvalue(NULLifnone)
LPITEMIDLISTm_pDefaultSel;

};
YABFFW.cpp
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->
CYABFFW::CYABFFW(constCString&strHint/**//*=CString()*/,

UINTnFlags/**//*=0U*/,

CWnd*pParentWnd/**//*=NULL*/,

intnRootFolder/**//*=CSIDL_DESKTOP*/,

constCString&strDefault/**//*=CString()*/):
m_nFlags(nFlags),
m_strHint(strHint),
m_pItemIdList(NULL),
m_pParentWnd(pParentWnd),
m_pRoot(NULL),
m_strDefaultSel(strDefault),
m_pDefaultSel(NULL)


{
ASSERT_NULL_OR_VALID(pParentWnd);//Paranoia

m_pRoot=ResolveCsidl(nRootFolder);
}


CYABFFW::CYABFFW(intnDefaultSel,

constCString&strHint/**//*=CString()*/,

UINTnFlags/**//*=0U*/,

CWnd*pParentWnd/**//*=NULL*/,

intnRootFolder/**//*=CSIDL_DESKTOP*/):
m_nFlags(nFlags),
m_strHint(strHint),
m_pItemIdList(NULL),
m_pParentWnd(pParentWnd),
m_pRoot(NULL),
m_pDefaultSel(NULL)


{
ASSERT_NULL_OR_VALID(pParentWnd);//Paranoia

m_pRoot=ResolveCsidl(nRootFolder);
m_pDefaultSel=ResolveCsidl(nDefaultSel);
}


CYABFFW::CYABFFW(intnHint,

UINTnFlags/**//*=0U*/,

CWnd*pParentWnd/**//*=NULL*/,

intnRootFolder/**//*=CSIDL_DESKTOP*/,

constCString&strDefaultSel/**//*=CString()*/):
m_nFlags(nFlags),
m_pItemIdList(NULL),
m_pParentWnd(pParentWnd),
m_pRoot(NULL),
m_strDefaultSel(strDefaultSel),
m_pDefaultSel(NULL)


{
ASSERT_NULL_OR_VALID(pParentWnd);//Paranoia

if(!m_strHint.LoadString(nHint))
AfxThrowResourceException();

m_pRoot=ResolveCsidl(nRootFolder);
}

CYABFFW::CYABFFW(intnDefaultSel,
intnHint,

UINTnFlags/**//*=0U*/,

CWnd*pParentWnd/**//*=NULL*/,

intnRootFolder/**//*=CSIDL_DESKTOP*/):
m_nFlags(nFlags),
m_pItemIdList(NULL),
m_pParentWnd(pParentWnd),
m_pRoot(NULL),
m_pDefaultSel(NULL)


{
ASSERT_NULL_OR_VALID(pParentWnd);//Paranoia

if(!m_strHint.LoadString(nHint))
AfxThrowResourceException();

m_pRoot=ResolveCsidl(nRootFolder);
m_pDefaultSel=ResolveCsidl(nDefaultSel);
}


CYABFFW::CYABFFW(constCString&strHint,
constCString&strRoot,

UINTnFlags/**//*=0U*/,

CWnd*pParentWnd/**//*=NULL*/,

constCString&strDefaultSel/**//*=CString()*/):
m_nFlags(nFlags),
m_strHint(strHint),
m_pItemIdList(NULL),
m_pParentWnd(pParentWnd),
m_pRoot(NULL),
m_strDefaultSel(strDefaultSel),
m_pDefaultSel(NULL)


{
ASSERT_NULL_OR_VALID(pParentWnd);//Paranoia

m_pRoot=ResolveFsPath(strRoot);
}


CYABFFW::CYABFFW(intnDefaultSel,
constCString&strHint,
constCString&strRoot,

UINTnFlags/**//*=0U*/,

CWnd*pParentWnd/**//*=NULL*/):
m_nFlags(nFlags),
m_strHint(strHint),
m_pItemIdList(NULL),
m_pParentWnd(pParentWnd),
m_pRoot(NULL),
m_pDefaultSel(NULL)


{
ASSERT_NULL_OR_VALID(pParentWnd);//Paranoia

m_pRoot=ResolveFsPath(strRoot);
m_pDefaultSel=ResolveCsidl(nDefaultSel);
}


CYABFFW::CYABFFW(intnHint,
constCString&strRoot,

UINTnFlags/**//*=0U*/,

CWnd*pParentWnd/**//*=NULL*/,

constCString&strDefaultSel/**//*=CString()*/):
m_nFlags(nFlags),
m_pItemIdList(NULL),
m_pParentWnd(pParentWnd),
m_pRoot(NULL),
m_strDefaultSel(strDefaultSel),
m_pDefaultSel(NULL)


{
ASSERT_NULL_OR_VALID(pParentWnd);//Paranoia

if(!m_strHint.LoadString(nHint))
AfxThrowResourceException();

m_pRoot=ResolveFsPath(strRoot);
}


CYABFFW::CYABFFW(intnDefaultSel,
intnHint,
constCString&strRoot,

UINTnFlags/**//*=0U*/,

CWnd*pParentWnd/**//*=NULL*/):
m_nFlags(nFlags),
m_pItemIdList(NULL),
m_pParentWnd(pParentWnd),
m_pRoot(NULL)


{
ASSERT_NULL_OR_VALID(pParentWnd);//Paranoia

if(!m_strHint.LoadString(nHint))
AfxThrowResourceException();

m_pRoot=ResolveFsPath(strRoot);
m_pDefaultSel=ResolveCsidl(nDefaultSel);
}

#ifdef_DEBUG
CStringCYABFFW::GetDisplayName()const


{
returnm_strDisplayName;
}


LPCITEMIDLISTCYABFFW::GetItemIdList()const


{
returnm_pItemIdList;
}

CStringCYABFFW::GetPath()const


{
returnm_strPath;
}
#endif//_DEBUG

intCYABFFW::DoModal()


{
//We'llneedthiseventually
HRESULThr;
IMalloc*pMalloc;
if(FAILED(hr=::SHGetMalloc(&pMalloc)))
AfxThrowOleException(hr);

//Fillouta'BROWSEINFO'structuretohandto'SHBrowseFor-
//Folder':
BROWSEINFObrowseInfo;
::ZeroMemory(&browseInfo,sizeof(BROWSEINFO));
browseInfo.hwndOwner=(NULL==m_pParentWnd?NULL:
m_pParentWnd->m_hWnd);

browseInfo.pidlRoot=m_pRoot;

//UseaCStringformemorymanagement
browseInfo.pszDisplayName=
m_strDisplayName.GetBufferSetLength(MAX_PATH);

browseInfo.lpszTitle=m_strHint;
browseInfo.ulFlags=m_nFlags;
browseInfo.lpfn=BrowseCallbackProc;
browseInfo.lParam=(long)this;

if(NULL!=m_pItemIdList)
FreeItemIdList();//Probablyneverhappen,but

if(NULL==(m_pItemIdList=::SHBrowseForFolder(&browseInfo)))


{
//UserCancelledout-cleanup&bail.
m_strDisplayName.ReleaseBuffer();
pMalloc->Release();
returnIDCANCEL;
}

//Right-ifwe'rehere,theuseractuallyselectedanitem.
//Trytogetafullpath.Thiswillfailiftheselecteditem
//isnotpartoftheFileSystem.
::SHGetPathFromIDList(m_pItemIdList,
m_strPath.GetBufferSetLength(MAX_PATH));

//Cleanuptime
m_strPath.ReleaseBuffer();
m_strDisplayName.ReleaseBuffer();
pMalloc->Release();

//Note:m_pItemIdListhas*not*beenfreed!Wekeeparoundin
//casethecallerwantstoretrieveitlater.Itwill
//ultimatelybefree-dinthedestructor.

returnIDOK;
}

voidCYABFFW::OnInitBFFDialog()


{
if(!m_strDefaultSel.IsEmpty())


{
TRACE(_T("Settingthedefaultselectionto%s./n"),
(LPCTSTR)m_strDefaultSel);
SendMessage(BFFM_SETSELECTION,TRUE,(LPARAM)(LPCTSTR)m_strDefaultSel);
}
elseif(m_pDefaultSel)


{
SendMessage(BFFM_SETSELECTION,FALSE,(LPARAM)m_pDefaultSel);
}
}


voidCYABFFW::OnBFFSelChanged(LPITEMIDLIST/**//*pNewSel*/)


{/**//*Nohandlingbydefault*/}



BOOLCYABFFW::OnBFFValidateFailed(constCString&/**//*strBadName*/)


{returnTRUE;/**//*Nohandlingbydefault*/}

CYABFFW::~CYABFFW()


{
HRESULThr;
IMalloc*pMalloc;
if(FAILED(hr=::SHGetMalloc(&pMalloc)))
AfxThrowOleException(hr);

pMalloc->Free(m_pRoot);

FreeItemIdList(pMalloc);
}


BEGIN_MESSAGE_MAP(CYABFFW,CWnd)
//{{AFX_MSG_MAP(CYABFFW)
//NOTE-theClassWizardwilladdandremovemappingmacroshere.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()


intCYABFFW::BrowseCallbackProc(HWNDhWnd,
UINTnMsg,
LPARAMlParam,
LPARAMlpData)


{
CYABFFW*pWnd=reinterpret_cast<CYABFFW*>(lpData);
ASSERT_VALID(pWnd);
ASSERT(NULL==pWnd->m_hWnd||hWnd==pWnd->m_hWnd);

if(NULL==pWnd->m_hWnd&&!pWnd->SubclassWindow(hWnd))
AfxThrowOleException(HRESULT_FROM_WIN32(::GetLastError()));

switch(nMsg)


{
caseBFFM_INITIALIZED:
//Indicatesthebrowsedialogboxhasfinished
//initializing.ThelParamvalueiszero.
pWnd->OnInitBFFDialog();
return0;
caseBFFM_SELCHANGED:
//Indicatestheselectionhaschanged.ThelParamparameter
//pointstotheitemidentifierlistforthenewlyselected
//item.


{
LPITEMIDLISTp=reinterpret_cast<LPITEMIDLIST>(lParam);
ASSERT_POINTER(p,ITEMIDLIST);
pWnd->OnBFFSelChanged(p);
return0;
}
caseBFFM_VALIDATEFAILED:
//Indicatestheusertypedaninvalidnameintotheeditbox
//ofthebrowsedialogbox.ThelParamparameteristhe
//addressofacharacterbufferthatcontainstheinvalid
//name.Anapplicationcanusethismessagetoinformthe
//userthatthenameenteredwasnotvalid.Returnzeroto
//allowthedialogtobedismissedornonzerotokeepthe
//dialogdisplayed.


{
LPTSTRp=reinterpret_cast<LPTSTR>(lParam);
ASSERT(!::IsBadStringPtr(p,UINT_MAX));
BOOLbDismissOk=pWnd->OnBFFValidateFailed(CString(p));
returnbDismissOk?0:1;
}
default:
TRACE(_T("WARNING:Unknownmessage0x%08x(0x%08x)")
_T("passedtoCYABFFW::BrowseCallbackProc!/n"),
nMsg,lParam);
return0;
}//EndswitchonnMsg.
}


voidCYABFFW::FreeItemIdList(IMalloc*pMalloc/**//*=NULL*/)


{
if(NULL==m_pItemIdList)
return;

boolbWeRelease=false;
if(NULL==pMalloc)


{
bWeRelease=true;
HRESULThr;
IMalloc*pMalloc;
if(FAILED(hr=::SHGetMalloc(&pMalloc)))
AfxThrowOleException(hr);
}

pMalloc->Free(m_pItemIdList);

if(bWeRelease)
pMalloc->Release();

m_pItemIdList=NULL;
}

LPITEMIDLISTCYABFFW::ResolveCsidl(intnCsidl)const


{
//Short-circuitspecialcase
if(CSIDL_DESKTOP==nCsidl)
returnNULL;

LPITEMIDLISTpidlRoot;
HRESULThr=::SHGetFolderLocation(NULL,nCsidl,NULL,0U,
&pidlRoot);
if(FAILED(hr))


{
ASSERT(NULL==pidlRoot);
AfxThrowOleException(hr);
}

returnpidlRoot;//Callerassumesresponsibility
}

LPITEMIDLISTCYABFFW::ResolveFsPath(constCString&strPath)const


{
USES_CONVERSION;

#ifdef_DEBUG
DWORDdwFileAttrs=::GetFileAttributes(strPath);
ASSERT(0xffffffff!=dwFileAttrs&&
FILE_ATTRIBUTE_DIRECTORY&dwFileAttrs);
#endif//_DEBUG

HRESULThr;
IShellFolder*pDesktop;
if(FAILED(hr=::SHGetDesktopFolder(&pDesktop)))
AfxThrowOleException(hr);

//Unfortunately,T2OLEexpectsanon-conststring,so
LPOLESTRp2=T2OLE(const_cast<LPTSTR>(
static_cast<LPCTSTR>(strPath)));
LPITEMIDLISTpItemIdList;
if(FAILED(hr=pDesktop->ParseDisplayName(NULL,NULL,
p2,
NULL,
&pItemIdList,
NULL)))


{
pDesktop->Release();
AfxThrowOleException(hr);
}

pDesktop->Release();
returnpItemIdList;//Callerassumesresponsibility
}
