一个MFC风格的BrowseForFolder 封装类
原文链接:CYABFFW: Yet Another BrowseForFolder Wrapper
以良好的MFC风格将Shell API函数SHBrowseForFolder()
封装为一个
CWnd
子类。
使用示例
1
:
CYABFFW dlg();
if (IDOK == dlg.DoModal())
{
CString s = dlg.GetPath();
// Do something with `s'
使用示例2:CYABFFW dlg(_T("Please select a directory"), // Hint to user
BIF_USE_NEWUI, // Flags for the dlg
this, // Parent window
CSIDL_DRIVES); // Root of search
if (IDOK == dlg.DoModal())
{
CString s = dlg.GetPath();
// Do something with `s'
BIF_USE_NEWUI, // Flags for the dlg
this, // Parent window
CSIDL_DRIVES); // Root of search
if (IDOK == dlg.DoModal())
{
CString s = dlg.GetPath();
// Do something with `s'
YABFFW.h
class CYABFFW : public CWnd
{
// Construction
public:
/**//// Construct with a textual hint, BFF flags, parent window, a
/// root folder expressed as a CSIDL value, and a default
/// selection expressed as a textual path
CYABFFW(const CString &strHint = CString(), UINT nFlags = 0U,
CWnd *pParentWnd = NULL, int nRootFolder = CSIDL_DESKTOP,
const CString &strDefaultSel = CString());
/**//// Construct with a default selection expressed as a CSIDL
/// value, a textual hint, BFF flags, parent window, & a root
/// folder expressed as a CSIDL value
CYABFFW(int nDefaultSel, const CString &strHint = CString(),
UINT nFlags = 0U, CWnd *pParentWnd = NULL,
int nRootFolder = CSIDL_DESKTOP);
/**//// Construct with a hint from Resource, BFF flags, parent
/// window, a root folder expressed as a CSIDL value, and a
/// default selection expressed as a textual path
CYABFFW(int nHint, UINT nFlags = 0U, CWnd *pParentWnd = NULL,
int nRootFolder = CSIDL_DESKTOP,
const CString &strDefaultSel = CString());
/**//// Construct with a hint from Resource, a default selection
/// expressed as a CSIDL value, BFF flags, parent window, & a
/// root folder expressed as a CSIDL value
CYABFFW(int nDefaultSel, int nHint, UINT nFlags = 0U,
CWnd *pParentWnd = NULL, int nRootFolder = CSIDL_DESKTOP);
/**//// Construct with a textual hint, an arbitrary root folder,
/// BFF flags, a parent window, and a default selection
/// expressed as a textual path
CYABFFW(const CString &strHint, const CString &strRoot,
UINT nFlags = 0U, CWnd *pParentWnd = NULL,
const CString &strDefaultSel = CString());
/**//// Construct with a textual hint, a default selection
/// expressed as a CSIDL value, an arbitrary root folder, BFF
/// flags, & a parent window
CYABFFW(int nDefaultSel, const CString &strHint, const CString &strRoot,
UINT nFlags = 0U, CWnd *pParentWnd = NULL);
/**//// Construct with a hint from Resource, an arbitrary root
/// folder, BFF flags, a parent widnow, and a textual default
/// selection
CYABFFW(int nHint, const CString &strRoot, UINT nFlags = 0U,
CWnd *pParentWnd = NULL,
const CString &strDefaultSel = CString());
/**//// Construct with a hint from Resource, a default selection
/// expressed as a CSIDL value, an arbitrary root folder, BFF
/// flags, & a parent widnow
CYABFFW(int nDefaultSel, int nHint, const CString &strRoot,
UINT nFlags = 0U, CWnd *pParentWnd = NULL);
// Attributes
public:
/**//// Retrieve the display name of the selected item
CString GetDisplayName() const;
/**//// Retrieve the ITEMIDLIST of the selected item
LPCITEMIDLIST GetItemIdList() const;
/**//// Retrieve the path to the selected item
CString GetPath() const;
// Operations
public:
/**//// Display the Dialog - returns IDOK or IDCANCEL
int DoModal();
// Overrides
public:
/**//// Called when the BFF Dialog has initialized
virtual void OnInitBFFDialog();
/**//// Called when the selection has changed in the tree control
virtual void OnBFFSelChanged(LPITEMIDLIST pNewSel);
/**//// Called when the user types an invalid name
virtual BOOL OnBFFValidateFailed(const CString &strBadName);
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CYABFFW)
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CYABFFW();
// Generated message map functions
protected:
//{{AFX_MSG(CYABFFW) NOTE - the ClassWizard will add and remove
// member functions here.
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
/**//// Static method to be used for the SHBFF callback
static int CALLBACK BrowseCallbackProc(HWND hWnd, UINT nMsg,
LPARAM lParam,
LPARAM lpData);
private:
/**//// Free the memory referenced by m_pItemIdList
void FreeItemIdList(IMalloc *pMalloc = NULL);
/**//// CSIDL => ITEMIDLIST
LPITEMIDLIST ResolveCsidl(int nCsidl) const;
/**//// Textual filesystem path => ITEMIDLIST
LPITEMIDLIST ResolveFsPath(const CString &strPath) const;
private:
/**//// Display name of the selected item
CString m_strDisplayName;
/**//// Flags to be passed to the browse dialog
UINT m_nFlags;
/**//// "Hint" to be displayed above the tree control
CString m_strHint;
/**//// ITEMIDLIST identifying the selected Shell item
LPITEMIDLIST m_pItemIdList;
/**//// Parent CWnd (NULL => App main window)
CWnd *m_pParentWnd;
/**//// Selected path
CString m_strPath;
/**//// ITEMIDLIST identifying the root
LPITEMIDLIST m_pRoot;
/**//// Default selection, if given as text (empty if none)
CString m_strDefaultSel;
/**//// Default selection, if given as a CSIDL value (NULL if none)
LPITEMIDLIST m_pDefaultSel;
};
class CYABFFW : public CWnd
{
// Construction
public:
/**//// Construct with a textual hint, BFF flags, parent window, a
/// root folder expressed as a CSIDL value, and a default
/// selection expressed as a textual path
CYABFFW(const CString &strHint = CString(), UINT nFlags = 0U,
CWnd *pParentWnd = NULL, int nRootFolder = CSIDL_DESKTOP,
const CString &strDefaultSel = CString());
/**//// Construct with a default selection expressed as a CSIDL
/// value, a textual hint, BFF flags, parent window, & a root
/// folder expressed as a CSIDL value
CYABFFW(int nDefaultSel, const CString &strHint = CString(),
UINT nFlags = 0U, CWnd *pParentWnd = NULL,
int nRootFolder = CSIDL_DESKTOP);
/**//// Construct with a hint from Resource, BFF flags, parent
/// window, a root folder expressed as a CSIDL value, and a
/// default selection expressed as a textual path
CYABFFW(int nHint, UINT nFlags = 0U, CWnd *pParentWnd = NULL,
int nRootFolder = CSIDL_DESKTOP,
const CString &strDefaultSel = CString());
/**//// Construct with a hint from Resource, a default selection
/// expressed as a CSIDL value, BFF flags, parent window, & a
/// root folder expressed as a CSIDL value
CYABFFW(int nDefaultSel, int nHint, UINT nFlags = 0U,
CWnd *pParentWnd = NULL, int nRootFolder = CSIDL_DESKTOP);
/**//// Construct with a textual hint, an arbitrary root folder,
/// BFF flags, a parent window, and a default selection
/// expressed as a textual path
CYABFFW(const CString &strHint, const CString &strRoot,
UINT nFlags = 0U, CWnd *pParentWnd = NULL,
const CString &strDefaultSel = CString());
/**//// Construct with a textual hint, a default selection
/// expressed as a CSIDL value, an arbitrary root folder, BFF
/// flags, & a parent window
CYABFFW(int nDefaultSel, const CString &strHint, const CString &strRoot,
UINT nFlags = 0U, CWnd *pParentWnd = NULL);
/**//// Construct with a hint from Resource, an arbitrary root
/// folder, BFF flags, a parent widnow, and a textual default
/// selection
CYABFFW(int nHint, const CString &strRoot, UINT nFlags = 0U,
CWnd *pParentWnd = NULL,
const CString &strDefaultSel = CString());
/**//// Construct with a hint from Resource, a default selection
/// expressed as a CSIDL value, an arbitrary root folder, BFF
/// flags, & a parent widnow
CYABFFW(int nDefaultSel, int nHint, const CString &strRoot,
UINT nFlags = 0U, CWnd *pParentWnd = NULL);
// Attributes
public:
/**//// Retrieve the display name of the selected item
CString GetDisplayName() const;
/**//// Retrieve the ITEMIDLIST of the selected item
LPCITEMIDLIST GetItemIdList() const;
/**//// Retrieve the path to the selected item
CString GetPath() const;
// Operations
public:
/**//// Display the Dialog - returns IDOK or IDCANCEL
int DoModal();
// Overrides
public:
/**//// Called when the BFF Dialog has initialized
virtual void OnInitBFFDialog();
/**//// Called when the selection has changed in the tree control
virtual void OnBFFSelChanged(LPITEMIDLIST pNewSel);
/**//// Called when the user types an invalid name
virtual BOOL OnBFFValidateFailed(const CString &strBadName);
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CYABFFW)
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CYABFFW();
// Generated message map functions
protected:
//{{AFX_MSG(CYABFFW) NOTE - the ClassWizard will add and remove
// member functions here.
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
/**//// Static method to be used for the SHBFF callback
static int CALLBACK BrowseCallbackProc(HWND hWnd, UINT nMsg,
LPARAM lParam,
LPARAM lpData);
private:
/**//// Free the memory referenced by m_pItemIdList
void FreeItemIdList(IMalloc *pMalloc = NULL);
/**//// CSIDL => ITEMIDLIST
LPITEMIDLIST ResolveCsidl(int nCsidl) const;
/**//// Textual filesystem path => ITEMIDLIST
LPITEMIDLIST ResolveFsPath(const CString &strPath) const;
private:
/**//// Display name of the selected item
CString m_strDisplayName;
/**//// Flags to be passed to the browse dialog
UINT m_nFlags;
/**//// "Hint" to be displayed above the tree control
CString m_strHint;
/**//// ITEMIDLIST identifying the selected Shell item
LPITEMIDLIST m_pItemIdList;
/**//// Parent CWnd (NULL => App main window)
CWnd *m_pParentWnd;
/**//// Selected path
CString m_strPath;
/**//// ITEMIDLIST identifying the root
LPITEMIDLIST m_pRoot;
/**//// Default selection, if given as text (empty if none)
CString m_strDefaultSel;
/**//// Default selection, if given as a CSIDL value (NULL if none)
LPITEMIDLIST m_pDefaultSel;
};
YABFFW.cpp
CYABFFW::CYABFFW( const CString &strHint /**//*= CString()*/,
UINT nFlags /**//*= 0U*/,
CWnd *pParentWnd /**//*= NULL*/,
int nRootFolder /**//*= CSIDL_DESKTOP*/,
const CString &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(int nDefaultSel,
const CString &strHint /**//*= CString()*/,
UINT nFlags /**//*= 0U*/,
CWnd *pParentWnd /**//*= NULL*/,
int nRootFolder /**//*= 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(int nHint,
UINT nFlags /**//*= 0U*/,
CWnd *pParentWnd /**//*= NULL*/,
int nRootFolder /**//*= CSIDL_DESKTOP*/,
const CString &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(int nDefaultSel,
int nHint,
UINT nFlags /**//*= 0U*/,
CWnd *pParentWnd /**//*= NULL*/,
int nRootFolder /**//*= 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(const CString &strHint,
const CString &strRoot,
UINT nFlags /**//*= 0U*/,
CWnd *pParentWnd /**//*= NULL*/,
const CString &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(int nDefaultSel,
const CString &strHint,
const CString &strRoot,
UINT nFlags /**//*= 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(int nHint,
const CString &strRoot,
UINT nFlags /**//*= 0U*/,
CWnd *pParentWnd /**//*= NULL*/,
const CString &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(int nDefaultSel,
int nHint,
const CString &strRoot,
UINT nFlags /**//*= 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
CString CYABFFW::GetDisplayName() const
{
return m_strDisplayName;
}
LPCITEMIDLIST CYABFFW::GetItemIdList() const
{
return m_pItemIdList;
}
CString CYABFFW::GetPath() const
{
return m_strPath;
}
#endif // _DEBUG
int CYABFFW::DoModal()
{
// We'll need this eventually
HRESULT hr;
IMalloc *pMalloc;
if (FAILED(hr = ::SHGetMalloc(&pMalloc)))
AfxThrowOleException(hr);
// Fill out a 'BROWSEINFO' structure to hand to 'SHBrowseFor-
// Folder':
BROWSEINFO browseInfo;
::ZeroMemory(&browseInfo, sizeof(BROWSEINFO));
browseInfo.hwndOwner = (NULL == m_pParentWnd ? NULL :
m_pParentWnd->m_hWnd);
browseInfo.pidlRoot = m_pRoot;
// Use a CString for memory management
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(); // Probably never happen, but
if (NULL == (m_pItemIdList = ::SHBrowseForFolder(&browseInfo)))
{
// User Cancelled out - clean up & bail.
m_strDisplayName.ReleaseBuffer();
pMalloc->Release();
return IDCANCEL;
}
// Right - if we're here, the user actually selected an item.
// Try to get a full path. This will fail if the selected item
// is not part of the FileSystem.
::SHGetPathFromIDList(m_pItemIdList,
m_strPath.GetBufferSetLength(MAX_PATH));
// Cleanup time
m_strPath.ReleaseBuffer();
m_strDisplayName.ReleaseBuffer();
pMalloc->Release();
// Note: m_pItemIdList has *not* been freed! We keep around in
// case the caller wants to retrieve it later. It will
// ultimately be free-d in the destructor.
return IDOK;
}
void CYABFFW::OnInitBFFDialog()
{
if ( ! m_strDefaultSel.IsEmpty( ) )
{
TRACE( _T( "Setting the default selection to %s.\n" ),
( LPCTSTR ) m_strDefaultSel );
SendMessage( BFFM_SETSELECTION, TRUE, ( LPARAM ) ( LPCTSTR ) m_strDefaultSel );
}
else if ( m_pDefaultSel )
{
SendMessage( BFFM_SETSELECTION, FALSE, ( LPARAM ) m_pDefaultSel );
}
}
void CYABFFW::OnBFFSelChanged(LPITEMIDLIST /**//*pNewSel*/)
{ /**//* No handling by default */ }
BOOL CYABFFW::OnBFFValidateFailed(const CString & /**//*strBadName*/)
{ return TRUE; /**//* No handling by default */ }
CYABFFW::~CYABFFW()
{
HRESULT hr;
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 - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
int CYABFFW::BrowseCallbackProc(HWND hWnd,
UINT nMsg,
LPARAM lParam,
LPARAM lpData)
{
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)
{
case BFFM_INITIALIZED:
// Indicates the browse dialog box has finished
// initializing. The lParam value is zero.
pWnd->OnInitBFFDialog();
return 0;
case BFFM_SELCHANGED:
// Indicates the selection has changed. The lParam parameter
// points to the item identifier list for the newly selected
// item.
{
LPITEMIDLIST p = reinterpret_cast<LPITEMIDLIST>(lParam);
ASSERT_POINTER(p, ITEMIDLIST);
pWnd->OnBFFSelChanged(p);
return 0;
}
case BFFM_VALIDATEFAILED:
// Indicates the user typed an invalid name into the edit box
// of the browse dialog box. The lParam parameter is the
// address of a character buffer that contains the invalid
// name. An application can use this message to inform the
// user that the name entered was not valid. Return zero to
// allow the dialog to be dismissed or nonzero to keep the
// dialog displayed.
{
LPTSTR p = reinterpret_cast<LPTSTR>(lParam);
ASSERT(!::IsBadStringPtr(p, UINT_MAX));
BOOL bDismissOk = pWnd->OnBFFValidateFailed(CString(p));
return bDismissOk ? 0 : 1;
}
default:
TRACE(_T("WARNING: Unknown message 0x%08x (0x%08x) ")
_T("passed to CYABFFW::BrowseCallbackProc!\n"),
nMsg, lParam);
return 0;
} // End switch on nMsg.
}
void CYABFFW::FreeItemIdList(IMalloc *pMalloc /**//*= NULL*/)
{
if (NULL == m_pItemIdList)
return;
bool bWeRelease = false;
if (NULL == pMalloc)
{
bWeRelease = true;
HRESULT hr;
IMalloc *pMalloc;
if (FAILED(hr = ::SHGetMalloc(&pMalloc)))
AfxThrowOleException(hr);
}
pMalloc->Free(m_pItemIdList);
if (bWeRelease)
pMalloc->Release();
m_pItemIdList = NULL;
}
LPITEMIDLIST CYABFFW::ResolveCsidl(int nCsidl) const
{
// Short-circuit special case
if (CSIDL_DESKTOP == nCsidl)
return NULL;
LPITEMIDLIST pidlRoot;
HRESULT hr = ::SHGetFolderLocation(NULL, nCsidl, NULL, 0U,
&pidlRoot);
if (FAILED(hr))
{
ASSERT(NULL == pidlRoot);
AfxThrowOleException(hr);
}
return pidlRoot; // Caller assumes responsibility
}
LPITEMIDLIST CYABFFW::ResolveFsPath(const CString &strPath) const
{
USES_CONVERSION;
# ifdef _DEBUG
DWORD dwFileAttrs = ::GetFileAttributes(strPath);
ASSERT(0xffffffff != dwFileAttrs &&
FILE_ATTRIBUTE_DIRECTORY & dwFileAttrs);
# endif // _DEBUG
HRESULT hr;
IShellFolder *pDesktop;
if ( FAILED(hr = ::SHGetDesktopFolder(&pDesktop)) )
AfxThrowOleException(hr);
// Unfortunately, T2OLE expects a non-const string, so
LPOLESTR p2 = T2OLE(const_cast<LPTSTR>(
static_cast<LPCTSTR>(strPath)));
LPITEMIDLIST pItemIdList;
if ( FAILED(hr = pDesktop->ParseDisplayName(NULL, NULL,
p2,
NULL,
&pItemIdList,
NULL)) )
{
pDesktop->Release();
AfxThrowOleException(hr);
}
pDesktop->Release();
return pItemIdList; // Caller assumes responsibility
}
CYABFFW::CYABFFW( const CString &strHint /**//*= CString()*/,
UINT nFlags /**//*= 0U*/,
CWnd *pParentWnd /**//*= NULL*/,
int nRootFolder /**//*= CSIDL_DESKTOP*/,
const CString &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(int nDefaultSel,
const CString &strHint /**//*= CString()*/,
UINT nFlags /**//*= 0U*/,
CWnd *pParentWnd /**//*= NULL*/,
int nRootFolder /**//*= 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(int nHint,
UINT nFlags /**//*= 0U*/,
CWnd *pParentWnd /**//*= NULL*/,
int nRootFolder /**//*= CSIDL_DESKTOP*/,
const CString &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(int nDefaultSel,
int nHint,
UINT nFlags /**//*= 0U*/,
CWnd *pParentWnd /**//*= NULL*/,
int nRootFolder /**//*= 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(const CString &strHint,
const CString &strRoot,
UINT nFlags /**//*= 0U*/,
CWnd *pParentWnd /**//*= NULL*/,
const CString &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(int nDefaultSel,
const CString &strHint,
const CString &strRoot,
UINT nFlags /**//*= 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(int nHint,
const CString &strRoot,
UINT nFlags /**//*= 0U*/,
CWnd *pParentWnd /**//*= NULL*/,
const CString &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(int nDefaultSel,
int nHint,
const CString &strRoot,
UINT nFlags /**//*= 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
CString CYABFFW::GetDisplayName() const
{
return m_strDisplayName;
}
LPCITEMIDLIST CYABFFW::GetItemIdList() const
{
return m_pItemIdList;
}
CString CYABFFW::GetPath() const
{
return m_strPath;
}
#endif // _DEBUG
int CYABFFW::DoModal()
{
// We'll need this eventually
HRESULT hr;
IMalloc *pMalloc;
if (FAILED(hr = ::SHGetMalloc(&pMalloc)))
AfxThrowOleException(hr);
// Fill out a 'BROWSEINFO' structure to hand to 'SHBrowseFor-
// Folder':
BROWSEINFO browseInfo;
::ZeroMemory(&browseInfo, sizeof(BROWSEINFO));
browseInfo.hwndOwner = (NULL == m_pParentWnd ? NULL :
m_pParentWnd->m_hWnd);
browseInfo.pidlRoot = m_pRoot;
// Use a CString for memory management
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(); // Probably never happen, but
if (NULL == (m_pItemIdList = ::SHBrowseForFolder(&browseInfo)))
{
// User Cancelled out - clean up & bail.
m_strDisplayName.ReleaseBuffer();
pMalloc->Release();
return IDCANCEL;
}
// Right - if we're here, the user actually selected an item.
// Try to get a full path. This will fail if the selected item
// is not part of the FileSystem.
::SHGetPathFromIDList(m_pItemIdList,
m_strPath.GetBufferSetLength(MAX_PATH));
// Cleanup time
m_strPath.ReleaseBuffer();
m_strDisplayName.ReleaseBuffer();
pMalloc->Release();
// Note: m_pItemIdList has *not* been freed! We keep around in
// case the caller wants to retrieve it later. It will
// ultimately be free-d in the destructor.
return IDOK;
}
void CYABFFW::OnInitBFFDialog()
{
if ( ! m_strDefaultSel.IsEmpty( ) )
{
TRACE( _T( "Setting the default selection to %s.\n" ),
( LPCTSTR ) m_strDefaultSel );
SendMessage( BFFM_SETSELECTION, TRUE, ( LPARAM ) ( LPCTSTR ) m_strDefaultSel );
}
else if ( m_pDefaultSel )
{
SendMessage( BFFM_SETSELECTION, FALSE, ( LPARAM ) m_pDefaultSel );
}
}
void CYABFFW::OnBFFSelChanged(LPITEMIDLIST /**//*pNewSel*/)
{ /**//* No handling by default */ }
BOOL CYABFFW::OnBFFValidateFailed(const CString & /**//*strBadName*/)
{ return TRUE; /**//* No handling by default */ }
CYABFFW::~CYABFFW()
{
HRESULT hr;
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 - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
int CYABFFW::BrowseCallbackProc(HWND hWnd,
UINT nMsg,
LPARAM lParam,
LPARAM lpData)
{
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)
{
case BFFM_INITIALIZED:
// Indicates the browse dialog box has finished
// initializing. The lParam value is zero.
pWnd->OnInitBFFDialog();
return 0;
case BFFM_SELCHANGED:
// Indicates the selection has changed. The lParam parameter
// points to the item identifier list for the newly selected
// item.
{
LPITEMIDLIST p = reinterpret_cast<LPITEMIDLIST>(lParam);
ASSERT_POINTER(p, ITEMIDLIST);
pWnd->OnBFFSelChanged(p);
return 0;
}
case BFFM_VALIDATEFAILED:
// Indicates the user typed an invalid name into the edit box
// of the browse dialog box. The lParam parameter is the
// address of a character buffer that contains the invalid
// name. An application can use this message to inform the
// user that the name entered was not valid. Return zero to
// allow the dialog to be dismissed or nonzero to keep the
// dialog displayed.
{
LPTSTR p = reinterpret_cast<LPTSTR>(lParam);
ASSERT(!::IsBadStringPtr(p, UINT_MAX));
BOOL bDismissOk = pWnd->OnBFFValidateFailed(CString(p));
return bDismissOk ? 0 : 1;
}
default:
TRACE(_T("WARNING: Unknown message 0x%08x (0x%08x) ")
_T("passed to CYABFFW::BrowseCallbackProc!\n"),
nMsg, lParam);
return 0;
} // End switch on nMsg.
}
void CYABFFW::FreeItemIdList(IMalloc *pMalloc /**//*= NULL*/)
{
if (NULL == m_pItemIdList)
return;
bool bWeRelease = false;
if (NULL == pMalloc)
{
bWeRelease = true;
HRESULT hr;
IMalloc *pMalloc;
if (FAILED(hr = ::SHGetMalloc(&pMalloc)))
AfxThrowOleException(hr);
}
pMalloc->Free(m_pItemIdList);
if (bWeRelease)
pMalloc->Release();
m_pItemIdList = NULL;
}
LPITEMIDLIST CYABFFW::ResolveCsidl(int nCsidl) const
{
// Short-circuit special case
if (CSIDL_DESKTOP == nCsidl)
return NULL;
LPITEMIDLIST pidlRoot;
HRESULT hr = ::SHGetFolderLocation(NULL, nCsidl, NULL, 0U,
&pidlRoot);
if (FAILED(hr))
{
ASSERT(NULL == pidlRoot);
AfxThrowOleException(hr);
}
return pidlRoot; // Caller assumes responsibility
}
LPITEMIDLIST CYABFFW::ResolveFsPath(const CString &strPath) const
{
USES_CONVERSION;
# ifdef _DEBUG
DWORD dwFileAttrs = ::GetFileAttributes(strPath);
ASSERT(0xffffffff != dwFileAttrs &&
FILE_ATTRIBUTE_DIRECTORY & dwFileAttrs);
# endif // _DEBUG
HRESULT hr;
IShellFolder *pDesktop;
if ( FAILED(hr = ::SHGetDesktopFolder(&pDesktop)) )
AfxThrowOleException(hr);
// Unfortunately, T2OLE expects a non-const string, so
LPOLESTR p2 = T2OLE(const_cast<LPTSTR>(
static_cast<LPCTSTR>(strPath)));
LPITEMIDLIST pItemIdList;
if ( FAILED(hr = pDesktop->ParseDisplayName(NULL, NULL,
p2,
NULL,
&pItemIdList,
NULL)) )
{
pDesktop->Release();
AfxThrowOleException(hr);
}
pDesktop->Release();
return pItemIdList; // Caller assumes responsibility
}
作者:洞庭散人
出处:http://phinecos.cnblogs.com/
本博客遵从Creative Commons Attribution 3.0 License,若用于非商业目的,您可以自由转载,但请保留原作者信息和文章链接URL。
posted on 2008-06-20 11:04 Phinecos(洞庭散人) 阅读(1257) 评论(0) 编辑 收藏 举报