在VC++6.0編程中,經(jīng)常要用到選擇目錄的功能,就象在 AppWizard中選擇放置工作區(qū)目錄一樣。在MFC中提供了類似的標準文件對話框CfileDialog類,支持用戶對文件的瀏覽、查找等操作。用SDK函數(shù)構(gòu)造這么一個對話框至少需要幾百行代碼,用這個類可以簡單地實現(xiàn)和Windows標準模式一致的文件打開、另存為等功能。但在MFC中并沒有提供選擇目錄對話框的標準類,而這在有關(guān)目錄路徑操作中經(jīng)常用到。針對此問題,筆者設(shè)計了一個通用的瀏覽目錄對話框的類CbrowseDirDialog,采用 Windows API函數(shù)SHBrowseForFolder。用戶可以采用這個類瀏覽任何指定的目錄,磁 盤,并返回用戶最后選擇的目錄信息。下面對這個類的使用作一簡單介紹:在CbrowseDirDialog.h頭文件中,定義了如下成員變量和函數(shù):
public:
CDirDialog();
virtual ~CDirDialog();
int DoBrowse();
CString m_Path;
CString m_InitDir;
CString m_SelDir;
CString m_Title;
int m_ImageIndex;
用戶可以設(shè)置對話框中瀏覽信息的標題在m_Title變量中,如果用戶不進行設(shè)置,系統(tǒng) 默認標題為“打開”;設(shè)置起始顯示目錄在m_InitDir變量中,如用戶需要列出C盤下的所有目錄,只需在定義的對象中設(shè)置m_InitDir=“C:\\”, 如果用戶不進行設(shè)置,系統(tǒng)默認為整個桌面;設(shè)置每次顯示的默認目錄在m_SelDir變量中,如果用戶不進行設(shè)置,系統(tǒng)默認為根目錄。最后,調(diào)用DoBrowse函數(shù),即可顯示選擇對話框目錄。如果該函數(shù)返回TRUE,則選中的目錄名賦予變量m_Path,與選中的目錄相關(guān)的圖標在系統(tǒng)圖標中的索引號賦予變量m_ImageIndex;如果返回FALSE,表明用戶按下“取消”按鈕放棄了此次操作或者程序中出現(xiàn)其他一些不可知錯誤。
附源程序清單(本程序在中文Windows98,Visual C++ 6.0中調(diào)試通過):
////////////////////////////////////////////////////////////////////////
// BrowseDirDialog.h
//////////////////////////////////////////////////////////////////////
class CBrowseDirDialog
{
public:
CBrowseDirDialog();
virtual ~CBrowseDirDialog();
int DoBrowse();
CString m_Path; //存放返回的路徑信息
CString m_InitDir; //初始顯示的路徑名,默認為桌面
CString m_SelDir; //打開對話框后,默認選中的目錄名,缺省為根目錄
CString m_Title; //設(shè)置對話框中瀏覽信息的標題,默認為"打開"
int m_ImageIndex;
};
///////////////////////////////////////////////////////////////////////////
// BrowseDirDialog.cpp
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "BrowseDirDialog.h"
#include "shlobj.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//SHBrowseForFolder控件在初始化或選擇改變后的回調(diào)函數(shù)
static int __stdcall BrowseCtrlCallback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
CBrowseDirDialog* pBrowseDirDialogObj = (CBrowseDirDialog*)lpData;
if (uMsg == BFFM_INITIALIZED
&& !pBrowseDirDialogObj->m_SelDir.IsEmpty())
{
::SendMessage(hwnd,BFFM_SETSELECTION,TRUE,(LPARAM)(LPCTSTR)(pBrowseDirDialogObj->m_SelDir));
}
else // uMsg == BFFM_SELCHANGED
{
}
return 0;
}
//構(gòu)造函數(shù)
CBrowseDirDialog::CBrowseDirDialog()
{
}
//析構(gòu)函數(shù)
CBrowseDirDialog::~CBrowseDirDialog()
{
}
int CBrowseDirDialog::DoBrowse()
{
LPMALLOC pMalloc;
if (SHGetMalloc (&pMalloc)!= NOERROR)
{
return 0;
}
BROWSEINFO bInfo;
LPITEMIDLIST pidl;
ZeroMemory ( (PVOID) &bInfo,sizeof (BROWSEINFO));
if (!m_InitDir.IsEmpty ())
{
OLECHAR olePath[MAX_PATH];
ULONG chEaten;
ULONG dwAttributes;
HRESULT hr;
LPSHELLFOLDER pDesktopFolder;
if (SUCCEEDED(SHGetDesktopFolder(&pDesktopFolder)))
{
MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED, m_InitDir.GetBuffer(MAX_PATH), -1,
olePath, MAX_PATH);
m_InitDir.ReleaseBuffer (-1);
//轉(zhuǎn)換路徑為ITEMLIST
hr = pDesktopFolder->ParseDisplayName(NULL,NULL,olePath,&chEaten,&pidl,
&dwAttributes);
if (FAILED(hr))
{
pMalloc ->Free (pidl);
pMalloc ->Release ();
return 0;
}
bInfo.pidlRoot = pidl;
}
}
bInfo.hwndOwner = NULL;
bInfo.pszDisplayName = m_Path.GetBuffer (MAX_PATH);
bInfo.lpszTitle = (m_Title.IsEmpty()) ? "打開":m_Title;
bInfo.ulFlags = BIF_RETURNFSANCESTORS|BIF_RETURNONLYFSDIRS;
bInfo.lpfn = BrowseCtrlCallback; //回調(diào)函數(shù)地址
bInfo.lParam = (LPARAM)this;
if ((pidl = ::SHBrowseForFolder(&bInfo)) == NULL)
{
return 0;
}
m_Path.ReleaseBuffer();
m_ImageIndex = bInfo.iImage;
if (::SHGetPathFromIDList(pidl,m_Path.GetBuffer(MAX_PATH)) == FALSE)
{
pMalloc ->Free(pidl);
pMalloc ->Release();
return 0;
}
m_Path.ReleaseBuffer();
pMalloc ->Free(pidl);
pMalloc ->Release();
return 1;
}
public:
CDirDialog();
virtual ~CDirDialog();
int DoBrowse();
CString m_Path;
CString m_InitDir;
CString m_SelDir;
CString m_Title;
int m_ImageIndex;
用戶可以設(shè)置對話框中瀏覽信息的標題在m_Title變量中,如果用戶不進行設(shè)置,系統(tǒng) 默認標題為“打開”;設(shè)置起始顯示目錄在m_InitDir變量中,如用戶需要列出C盤下的所有目錄,只需在定義的對象中設(shè)置m_InitDir=“C:\\”, 如果用戶不進行設(shè)置,系統(tǒng)默認為整個桌面;設(shè)置每次顯示的默認目錄在m_SelDir變量中,如果用戶不進行設(shè)置,系統(tǒng)默認為根目錄。最后,調(diào)用DoBrowse函數(shù),即可顯示選擇對話框目錄。如果該函數(shù)返回TRUE,則選中的目錄名賦予變量m_Path,與選中的目錄相關(guān)的圖標在系統(tǒng)圖標中的索引號賦予變量m_ImageIndex;如果返回FALSE,表明用戶按下“取消”按鈕放棄了此次操作或者程序中出現(xiàn)其他一些不可知錯誤。
附源程序清單(本程序在中文Windows98,Visual C++ 6.0中調(diào)試通過):
////////////////////////////////////////////////////////////////////////
// BrowseDirDialog.h
//////////////////////////////////////////////////////////////////////
class CBrowseDirDialog
{
public:
CBrowseDirDialog();
virtual ~CBrowseDirDialog();
int DoBrowse();
CString m_Path; //存放返回的路徑信息
CString m_InitDir; //初始顯示的路徑名,默認為桌面
CString m_SelDir; //打開對話框后,默認選中的目錄名,缺省為根目錄
CString m_Title; //設(shè)置對話框中瀏覽信息的標題,默認為"打開"
int m_ImageIndex;
};
///////////////////////////////////////////////////////////////////////////
// BrowseDirDialog.cpp
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "BrowseDirDialog.h"
#include "shlobj.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//SHBrowseForFolder控件在初始化或選擇改變后的回調(diào)函數(shù)
static int __stdcall BrowseCtrlCallback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
CBrowseDirDialog* pBrowseDirDialogObj = (CBrowseDirDialog*)lpData;
if (uMsg == BFFM_INITIALIZED
&& !pBrowseDirDialogObj->m_SelDir.IsEmpty())
{
::SendMessage(hwnd,BFFM_SETSELECTION,TRUE,(LPARAM)(LPCTSTR)(pBrowseDirDialogObj->m_SelDir));
}
else // uMsg == BFFM_SELCHANGED
{
}
return 0;
}
//構(gòu)造函數(shù)
CBrowseDirDialog::CBrowseDirDialog()
{
}
//析構(gòu)函數(shù)
CBrowseDirDialog::~CBrowseDirDialog()
{
}
int CBrowseDirDialog::DoBrowse()
{
LPMALLOC pMalloc;
if (SHGetMalloc (&pMalloc)!= NOERROR)
{
return 0;
}
BROWSEINFO bInfo;
LPITEMIDLIST pidl;
ZeroMemory ( (PVOID) &bInfo,sizeof (BROWSEINFO));
if (!m_InitDir.IsEmpty ())
{
OLECHAR olePath[MAX_PATH];
ULONG chEaten;
ULONG dwAttributes;
HRESULT hr;
LPSHELLFOLDER pDesktopFolder;
if (SUCCEEDED(SHGetDesktopFolder(&pDesktopFolder)))
{
MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED, m_InitDir.GetBuffer(MAX_PATH), -1,
olePath, MAX_PATH);
m_InitDir.ReleaseBuffer (-1);
//轉(zhuǎn)換路徑為ITEMLIST
hr = pDesktopFolder->ParseDisplayName(NULL,NULL,olePath,&chEaten,&pidl,
&dwAttributes);
if (FAILED(hr))
{
pMalloc ->Free (pidl);
pMalloc ->Release ();
return 0;
}
bInfo.pidlRoot = pidl;
}
}
bInfo.hwndOwner = NULL;
bInfo.pszDisplayName = m_Path.GetBuffer (MAX_PATH);
bInfo.lpszTitle = (m_Title.IsEmpty()) ? "打開":m_Title;
bInfo.ulFlags = BIF_RETURNFSANCESTORS|BIF_RETURNONLYFSDIRS;
bInfo.lpfn = BrowseCtrlCallback; //回調(diào)函數(shù)地址
bInfo.lParam = (LPARAM)this;
if ((pidl = ::SHBrowseForFolder(&bInfo)) == NULL)
{
return 0;
}
m_Path.ReleaseBuffer();
m_ImageIndex = bInfo.iImage;
if (::SHGetPathFromIDList(pidl,m_Path.GetBuffer(MAX_PATH)) == FALSE)
{
pMalloc ->Free(pidl);
pMalloc ->Release();
return 0;
}
m_Path.ReleaseBuffer();
pMalloc ->Free(pidl);
pMalloc ->Release();
return 1;
}