正文
1、API概述
使用Windows的SHBrowseForFolder可以实现目录选择功能。
该函数的参数也实现如下:见MSDN
Displays a dialog box that enables the user to select a shell folder.
LPITEMIDLIST SHBrowseForFolder(LPBROWSEINFO lpbi);
Returns a pointer to an ITEMIDLIST structure (PIDL) that specifies the location of the selected folder relative to the root of the namespace. If the user chooses the Cancel button in the dialog box, the return value is NULL.
2、使用
#define REMOVE_HEIGHT 28
// 回调函数的声明
int CALLBACK _SHBrowseForFolderCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
BOOL SelectFolder(CString& lpstrFolderPos, CString strInitPosition)
{
BOOL bRes = FALSE;
char lpszPath[MAX_PATH];
LPMALLOC lpMalloc;
BROWSEINFO sInfo;
LPITEMIDLIST lpidlBrowse;
if (::SHGetMalloc(&lpMalloc) != NOERROR)
return FALSE;
if (strInitFolder != _T(""))
{
if(strInitFolder.Right(1) == _T("//")) // 删除尾部的"//"
strInitFolder = strInitFolder.Left(strInitFolder.GetLength() - 1);
}
::ZeroMemory(&sInfo, sizeof(BROWSEINFO));
sInfo.pidlRoot = 0;
sInfo.pszDisplayName = lpszPath;
sInfo.lpszTitle = _T("请选择您需要的目的文件夹:");
sInfo.ulFlags = BIF_DONTGOBELOWDOMAIN | BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_USENEWUI;
sInfo.lpfn = _SHBrowseForFolderCallbackProc;
sInfo.lParam = (LPARAM)strInitFolder.GetBuffer(0);
// 显示文件夹选择对话框
lpidlBrowse = ::SHBrowseForFolder(&sInfo);
if (lpidlBrowse != NULL)
{
// 取得文件夹名
if (::SHGetPathFromIDList(lpidlBrowse,lpszPath))
{
lpstrFolder = _T("");
lpstrFolder = lpszPath;
if(lpstrFolder != "")
{
if(lpstrFolder.Right(1) != _T("//"))
lpstrFolder += _T("//"); //在末尾时附加"//"
}
}
bRes = TRUE;
}
if(lpidlBrowse != NULL)
{
::CoTaskMemFree(lpidlBrowse);
}
lpMalloc->Release();
return bRes;
}
下面是回调函数,以及函数的处理
int CALLBACK _SHBrowseForFolderCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
static HWND hWndEdit = NULL;
CString strDir;
switch (uMsg)
{
case BFFM_INITIALIZED:
{
::SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
CRect rect;
HWND hChild = GetWindow(hwnd, GW_CHILD);
while (hChild)
{
TCHAR szClass[256];
GetClassName(hChild, szClass, 255);
// 如果是中间的树目录控件,使可以随窗口移动大小
if (strcmp(szClass, "SHBrowseForFolder ShellNameSpace Control") == 0)
{
GetWindowRect(hChild, rect);
rect.top -= REMOVE_HEIGHT;
CPoint pt = rect.TopLeft();
ScreenToClient(hwnd, &pt);
MoveWindow(hChild, pt.x, pt.y, rect.Width(), rect.Height(), TRUE);
}
if (strcmp(szClass, "Edit") == 0)
{
hWndEdit = hChild;
}
hChild = GetNextWindow(hChild, GW_HWNDNEXT);
}
SetWindowText(hwnd, "alinx文件浏览...");
}
break;
case BFFM_SELCHANGED:
if(hWndEdit)
{
if(::SHGetPathFromIDList((LPITEMIDLIST)lParam, strDir.GetBufferSetLength(MAX_PATH)))
{
SetWindowText(hWndEdit, strDir);
}
else
{
SetWindowText(hWndEdit, NULL);
SendMessage(hwnd, BFFM_VALIDATEFAILED, 0, 0);
}
strDir.ReleaseBuffer();
}
break;
default:
break;
}
return 0;
}
3、效果
另一应用实例
#ifndef GLOBAL_H
#define GLOBAL_H
#ifndef BIF_NEWDIALOGSTYLE
#define BIF_NEWDIALOGSTYLE 0x0040
#endif
#ifndef BIF_USENEWUI
#define BIF_USENEWUI 0x0050
#endif
// 初始化文件夹设定用的回调函数
int CALLBACK _SHBrowseForFolderCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
if(uMsg == BFFM_INITIALIZED)
::SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
return 0;
}
bool g_fSelectFolderDlg(CString* lpstrFolder,CString strIniFolder,bool bAvailNewFolder)
{
bool ret;
char lpszPath[MAX_PATH];
LPMALLOC lpMalloc;
BROWSEINFO sInfo;
LPITEMIDLIST lpidlRoot;
LPITEMIDLIST lpidlBrowse;
if(lpstrFolder == NULL)
return false;
if(::SHGetMalloc(&lpMalloc) != NOERROR)
return false;
ret = false;
if(strIniFolder != "")
{
if(strIniFolder.Right(1) == "//")
strIniFolder = strIniFolder.Left(strIniFolder.GetLength() - 1); //删除末尾的"//"
}
::SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &lpidlRoot); //取得选定的文件夹名
::ZeroMemory(&sInfo, sizeof(BROWSEINFO));
sInfo.pidlRoot = lpidlRoot;
sInfo.pszDisplayName = lpszPath;
sInfo.lpszTitle = _T("Please Select Work Directory:");
sInfo.ulFlags = BIF_RETURNONLYFSDIRS;
if(bAvailNewFolder == true)
sInfo.ulFlags |= BIF_EDITBOX | BIF_NEWDIALOGSTYLE | BIF_USENEWUI;
sInfo.lpfn = _SHBrowseForFolderCallbackProc;
sInfo.lParam = (LPARAM)strIniFolder.GetBuffer(0);
lpidlBrowse = ::SHBrowseForFolder(&sInfo); //显示文件夹选择对话框
if(lpidlBrowse != NULL)
{
if(::SHGetPathFromIDList(lpidlBrowse,lpszPath)) //取得文件夹名
{
*lpstrFolder = "";
*lpstrFolder = lpszPath;
if(*lpstrFolder != "")
{
if(lpstrFolder->Right(1) != "//")
*lpstrFolder += "//"; //在末尾时附加"//"
}
}
ret = true;
}
if(lpidlBrowse != NULL)
::CoTaskMemFree(lpidlBrowse);
if(lpidlRoot != NULL)
::CoTaskMemFree(lpidlRoot);
lpMalloc->Release();
return ret;
}
#endif
调用:
void CSelectDir::OnButton1()
{
// TODO: Add your control notification handler code here
if(g_fSelectFolderDlg(&m_strFolder,m_strFolder,false))
{
UpdateData(false);
}
}