以选择文件夹对话框为例,研究C++11新特性。

调用Windows API SHBrowseForFolder 可以打开该对话框,进行浏览和选择对话框。调用该接口之前,需要构造一个结构体BROWSEINFO 。参考下面的函数:
-
-
BOOL WINAPI SelectFolder(HWND hParent, CString &strFolder)
-
{
-
BOOL bRet = FALSE;
-
LPMALLOC lpMalloc;
-
if (::SHGetMalloc(&lpMalloc) != NOERROR)
-
{
-
return FALSE;
-
}
-
-
TCHAR szDisplayName[_MAX_PATH];
-
TCHAR szBuffer[_MAX_PATH];
-
BROWSEINFO browseInfo;
-
browseInfo.hwndOwner = hParent;
-
browseInfo.pidlRoot = NULL;
-
browseInfo.pszDisplayName = szDisplayName;
-
browseInfo.lpszTitle = _T("请选择一个文件夹:\nPlease select a folder:");
-
browseInfo.ulFlags = BIF_RETURNFSANCESTORS|BIF_RETURNONLYFSDIRS;
-
browseInfo.lpfn = NULL;
-
browseInfo.lParam = NULL;
-
-
LPITEMIDLIST lpItemIDList;
-
if ((lpItemIDList = ::SHBrowseForFolder(&browseInfo)) != NULL)
-
{
-
if (::SHGetPathFromIDList(lpItemIDList, szBuffer))
-
{
-
if (szBuffer[0] != ‘\0‘)
-
{
-
strFolder = szBuffer;
-
bRet = TRUE;
-
}
-
}
-
lpMalloc->Free(lpItemIDList);
-
lpMalloc->Release();
-
}
-
return bRet;
-
}
但是,这样没有“新建文件夹”的按钮,也没有选择文件夹的编辑框显示,如下图。

如果需要新建文件夹的按钮,需要给BROWSEINFO的表示位ulFlags添加一个标志BIF_USENEWUI 。这个标志在VC6.0没有给出,可以自己定义:
#ifndef BIF_USENEWUI
#define BIF_NEWDIALOGSTYLE 0x00000040 // Use the new dialog layout with the ability to resize
#define BIF_USENEWUI (BIF_NEWDIALOGSTYLE | BIF_EDITBOX) // Caller needs to call OleInitialize() before using this API
#endif
然后把上面函数稍加修改, browseInfo.ulFlags = BIF_RETURNFSANCESTORS|BIF_RETURNONLYFSDIRS|BIF_USENEWUI; 这样就有了“新建文件夹”按钮了。
但是,这样仍不完美。因为每次打开该对话框时,都是默认选择同样的目录,想要找到自己想要的目的文件夹就要多次点击鼠标才行。如果能够指定一个默认选择的文件夹就好了。而幸运的是,Windows提供了这样的接口。但需要通过回调的方式实现,如下:
-
int CALLBACK BrowserCallbackProc(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
-
{
-
switch(uMsg)
-
{
-
case BFFM_INITIALIZED:
-
::SendMessage(hWnd, BFFM_SETSELECTION, 1, lpData);
-
break;
-
default:
-
break;
-
}
-
return 0;
-
}
-
-
BOOL WINAPI SelFolder(HWND hParent, CString &strFolder)
-
{
-
BOOL bRet = FALSE;
-
LPMALLOC lpMalloc;
-
if (::SHGetMalloc(&lpMalloc) != NOERROR)
-
{
-
return FALSE;
-
}
-
-
TCHAR szDisplayName[_MAX_PATH];
-
TCHAR szBuffer[_MAX_PATH];
-
BROWSEINFO browseInfo;
-
browseInfo.hwndOwner = hParent;
-
browseInfo.pidlRoot = NULL;
-
browseInfo.pszDisplayName = szDisplayName;
-
browseInfo.lpszTitle = _T("请选择一个文件夹:\n\nPlease select a folder:");
-
browseInfo.ulFlags = BIF_RETURNFSANCESTORS|BIF_RETURNONLYFSDIRS|BIF_USENEWUI;
-
browseInfo.lpfn = BrowserCallbackProc;
-
browseInfo.lParam = (LPARAM)(const char*)strFolder;
-
-
LPITEMIDLIST lpItemIDList;
-
if ((lpItemIDList = ::SHBrowseForFolder(&browseInfo)) != NULL)
-
{
-
if (::SHGetPathFromIDList(lpItemIDList, szBuffer))
-
{
-
if (szBuffer[0] != ‘\0‘)
-
{
-
strFolder = szBuffer;
-
bRet = TRUE;
-
}
-
}
-
lpMalloc->Free(lpItemIDList);
-
lpMalloc->Release();
-
}
-
return bRet;
-
}
这样就能达到想要的效果。
但是仍不完美,一个功能本来应该一个函数就实现的,却写了两个函数,看起来真是膈应。复制的时候,仅复制下面的函数是用不了的,程序的可读性、可移植性都大打折扣。如果能写在同一个函数中,再精简一下就完美了。VC6.0是不行了,VS2010也力不从心。
而VS2013用几个C++11的新特性就能轻松是实现:

使用VC++2013写出短小精悍的函数,布布扣,bubuko.com
使用VC++2013写出短小精悍的函数
原文:http://blog.csdn.net/gao_zilai/article/details/23736117