BOOL CBrowseForFolder::Browse()
{
BOOL bRet = FALSE;
m_bi.pszDisplayName = m_szDisplayName;
m_bi.lpszTitle = m_strTitle;
m_bi.lpfn=m_lpfn;
m_bi.lParam = (LPARAM)this;
LPITEMIDLIST pidl;
if ((pidl = ::SHBrowseForFolder(&m_bi)) != NULL){
m_strPath.Empty();
if (SUCCEEDED(::SHGetPathFromIDList(pidl, m_szPathSelected))){
bRet = TRUE;
m_strPath = m_szPathSelected;
}
LPMALLOC pMalloc;
//Retrieve a pointer to the shell's IMalloc interface
if (SUCCEEDED(SHGetMalloc(&pMalloc))){
pMalloc->Free(pidl);// free the PIDL that SHBrowseForFolder returned to us.
(void)pMalloc->Release();// release the shell's IMalloc interface
}
}
m_hwnd = NULL;
return bRet;
}
void CBrowseForFolder::OnInit()
{
CDialog dlg;
if(!dlg.Attach(m_hwnd)) return;
if(m_bi.ulFlags&EDITBOX){//initially,the editbox has not the same width the treectrl.Make it the same width.
m_pEdit=NULL;
m_pTree=NULL;
CWnd* pWndChild=dlg.GetWindow(GW_CHILD);
while(pWndChild!=NULL){//seek the editbox and the treectrl.
if(pWndChild->IsKindOf(RUNTIME_CLASS(CEdit)))
m_pEdit=(CEdit*)pWndChild;
if(pWndChild->IsKindOf(RUNTIME_CLASS(CTreeCtrl)))
m_pTree=(CTreeCtrl*)pWndChild;
pWndChild=pWndChild->GetWindow(GW_HWNDNEXT);
}
if(m_pEdit!=NULL&&m_pTree!=NULL){
CRect rcTree,reEdit;
m_pTree->GetWindowRect(&rcTree);
m_pEdit->GetWindowRect(&reEdit);
dlg.ScreenToClient(&rcTree);
dlg.ScreenToClient(&reEdit);
m_pEdit->MoveWindow(reEdit.left,reEdit.top,rcTree.Width(),reEdit.Height());
}
}
dlg.Detach();
}
void CBrowseForFolder::OnSelChanged( LPITEMIDLIST pidl)
{
char pszPath[MAX_PATH];
if(::SHGetPathFromIDList(pidl,pszPath)){//default action,set status text to current selection.
SetStatusText(pszPath);
}
}
void CBrowseForFolder::OnValidFailed()
{
::AfxMessageBox(IDS_INVALID_PATH,MB_TASKMODAL|MB_OK);//display a messagebox.you can provide your own validation messages.
}
void CBrowseForFolder::EnableOK( BOOL bEnable) //disable /enable the ok button
{
if (m_hwnd == NULL) return;
(void)SendMessage(m_hwnd, BFFM_ENABLEOK, (LPARAM)bEnable, NULL);
}
void CBrowseForFolder::SetSelection( LPITEMIDLIST pidl) //set current selection
{
if (m_hwnd == NULL) return;
(void)SendMessage(m_hwnd, BFFM_SETSELECTION, FALSE, (LPARAM)pidl);
}
void CBrowseForFolder::SetSelection( LPCTSTR lpszPath) //set current selection
{
if (m_hwnd == NULL) return;
(void)SendMessage(m_hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)lpszPath);
}
void CBrowseForFolder::SetStatusText( LPCTSTR lpszText) //set current status
{
if (m_hwnd == NULL) return;
(void)SendMessage(m_hwnd, BFFM_SETSTATUSTEXT, NULL, (LPARAM)lpszText);
}
int CALLBACK CBrowseForFolder::BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)//default hook function.
{
CBrowseForFolder* pbff = (CBrowseForFolder*)lpData;
pbff->m_hwnd = hwnd;
switch(uMsg){
case BFFM_INITIALIZED:
pbff->OnInit();
break;
case BFFM_SELCHANGED:
pbff->OnSelChanged((LPITEMIDLIST)lParam);
break;
case BFFM_VALIDATEFAILED :
pbff->OnValidFailed();
break;
}
return 0;//keep dialog displayed
}
// Exercise the PIDL by performing common operations upon it.
HRESULT TestPidl(LPITEMIDLIST pidl)//ͨ¹ýÖ´Ðг£ÓòÙ×÷²âÊÔPIDL
{
HRESULT hr;
LPSHELLFOLDER pshfDesktop = NULL, pshf = NULL;
DWORD uFlags = SHGDN_NORMAL;
STRRET strret;
if (!pidl){
return E_INVALIDARG;
}
hr = SHGetDesktopFolder(&pshfDesktop);
if (!pshfDesktop){
return hr;
}
//µÃµ½Óëpidl¶ÔÓ¦µÄpshf(ISHELLFODER¶ÔÏó)
hr = pshfDesktop->BindToObject(pidl,NULL,IID_IShellFolder,(LPVOID*)&pshf);
if (!pshf)
goto Error;
//µÃµ½Óëpidl¶ÔÓ¦µÄÏÔʾÃûstrret(·µ»Ø×Ö·û´®)
hr = pshfDesktop->GetDisplayNameOf(pidl, uFlags, &strret);
if (STRRET_WSTR == strret.uType)
FreeResources((LPVOID)strret.pOleStr);
Error:
if (pshf)
pshf->Release();
if (pshf)
pshfDesktop->Release();
return hr;
}
// Use the shell's IMalloc implementation to free resources
HRESULT FreeResources(LPVOID pData)//ʹÓÃÍâ¿ÇµÄImallocʵÏÖÊÍ·Å×ÊÔ´
{
HRESULT hr;
LPMALLOC pMalloc = NULL;
if (SUCCEEDED(hr = SHGetMalloc(&pMalloc)))
{
pMalloc->Free((LPVOID)pData);
pMalloc->Release();
}
return hr;
}
// Given a VARIANT, pull out the PIDL using brute force
LPITEMIDLIST PidlFromVARIANT(LPVARIANT pvarLoc)//´ÓVARIENT±äÁ¿Öеõ½PIDL
{
if (pvarLoc){
if (V_VT(pvarLoc) == (VT_ARRAY|VT_UI1)){
LPITEMIDLIST pidl = (LPITEMIDLIST)pvarLoc->parray->pvData;
return pidl;
}
}
return NULL;
}
// Pack a PIDL into a VARIANT
HRESULT InitVARIANTFromPidl(LPVARIANT pvar, LPITEMIDLIST pidl)//ÔÚVARIENT±äÁ¿Öдæ·ÅPIDL
{
if (!pidl || !pvar) {
return E_POINTER;
}
// Get the size of the pidl and allocate a SAFEARRAY of
// equivalent size
UINT cb = ILGetSize(pidl);
LPSAFEARRAY psa = MakeSafeArrayFromData((LPBYTE)pidl, cb);
if (!psa){
VariantInit(pvar);
return E_OUTOFMEMORY;
}
V_VT(pvar) = VT_ARRAY|VT_UI1;
V_ARRAY(pvar) = psa;
return NOERROR;
}
// Allocate a SAFEARRAY of cbData size and pack pData into it
LPSAFEARRAY MakeSafeArrayFromData(LPBYTE pData, DWORD cbData)//°²È«·ÖÅäcbData´óСµÄ°²È«Êý×飬²¢ÇÒ´æ·ÅpData¡£
{
LPSAFEARRAY psa;
if (!pData || 0 == cbData){
return NULL; // nothing to do
}
// create a one-dimensional safe array of BYTEs
psa = SafeArrayCreateVector(VT_UI1, 0, cbData);
if (psa){
// copy data into the area in safe array reserved for data
// Note we party directly on the pointer instead of using locking/
// unlocking functions. Since we just created this and no one
// else could possibly know about it or be using it, this is okay.
memcpy(psa->pvData,pData,cbData);
}
return psa;
}
// Get the size of the PIDL by walking the item id list
UINT ILGetSize(LPITEMIDLIST pidl)//ͨ¹ý±éÀúÏîÄ¿ÁбíµÃµ½PIDLµÄ´óС
{
UINT cbTotal = 0;
if (pidl){
cbTotal += sizeof(pidl->mkid.cb); // Null terminator
while (pidl->mkid.cb){
cbTotal += pidl->mkid.cb;
pidl = _ILNext(pidl);
}
}
return cbTotal;
}
HRESULT ItemIdListFromPath( LPITEMIDLIST& pidl,LPCSTR szPath)
//szPath is assumpted MAX_PATH size
{
LPSHELLFOLDER pDesktopFolder;
OLECHAR olePath[MAX_PATH];
ULONG chEaten;
ULONG dwAttributes;
HRESULT hr;
//
// Get a pointer to the Desktop's IShellFolder interface.
//
if (FAILED(SHGetDesktopFolder(&pDesktopFolder))){
return -1;
}
//
// IShellFolder::ParseDisplayName requires the file name be in
// Unicode.
//
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szPath, -1, olePath, MAX_PATH);
// Convert the path to an ITEMIDLIST.
hr = pDesktopFolder->ParseDisplayName(NULL,NULL,olePath,&chEaten,
&pidl,&dwAttributes);
if (FAILED(hr)){
// Handle error.
::AfxMessageBox (IDS_FAIL_PARSING_PATH);
}
// pidl now contains a pointer to an ITEMIDLIST for .\readme.txt.
// This ITEMIDLIST needs to be freed using the IMalloc allocator
// returned from SHGetMalloc().
//release the desktop folder object
pDesktopFolder->Release();
return 0;
}
LPITEMIDLIST GetNextItem(LPCITEMIDLIST pidl)
{
if(pidl)
return (LPITEMIDLIST)(LPBYTE)(((LPBYTE)pidl) + pidl->mkid.cb);
else
return (NULL);
}
// CopyItemID - creates an item identifier list containing the first
// item identifier in the specified list.
// Returns a PIDL if successful, or NULL if out of memory.
LPITEMIDLIST CopyItemID(LPITEMIDLIST pidl)
{
// Get the size of the specified item identifier.
int cb = pidl->mkid.cb;
LPMALLOC pMalloc;
// Allocate a new item identifier list.
if(::SHGetMalloc (&pMalloc)!=S_OK)
return NULL;
LPITEMIDLIST pidlNew = (LPITEMIDLIST) pMalloc->Alloc(cb + sizeof(USHORT));
if (pidlNew == NULL)
return NULL;
// Copy the specified item identifier.
CopyMemory(pidlNew, pidl, cb);
// Append a terminating zero.
*((USHORT *) (((LPBYTE) pidlNew) + cb)) = 0;
pMalloc->Release ();
return pidlNew;
}