我们经常需要用到“选择文件夹”对话框,相应的API已经很好用,但稍嫌麻烦,
所以我专门将其封装了一下,力求一步到位。
函数封装如下:
/*****************************************************************
** 函数名:GetPath
** 输 入: 无
** 输 出: CString strPath
** strPath非空, 表示用户选择的文件夹路径
** strPath为空, 表示用户点击了“取消”键,取消选择
** 功能描述:显示“选择文件夹”对话框,让用户选择文件夹
****************************************************************/
CString GetPath()
{
CString strPath = "";
BROWSEINFO bInfo;
ZeroMemory(&bInfo, sizeof(bInfo));
bInfo.hwndOwner = m_hWnd;
bInfo.lpszTitle = _T("请选择路径: ");
bInfo.ulFlags = BIF_RETURNONLYFSDIRS;
LPITEMIDLIST lpDlist; //用来保存返回信息的IDList
lpDlist = SHBrowseForFolder(&bInfo) ; //显示选择对话框
if(lpDlist != NULL) //用户按了确定按钮
{
TCHAR chPath[255]; //用来存储路径的字符串
SHGetPathFromIDList(lpDlist, chPath);//把项目标识列表转化成字符串
strPath = chPath; //将TCHAR类型的字符串转换为CString类型的字符串
}
return strPath;
}
调用时只需要用到以下代码:
CString strPath = GetPath();
则strPath为用户选择的文件夹路径。如果用户点击了对话框的取消键,则strPath为空字符串("");
//-----------------------------------------------------
FolderDialog.h
C/C++ code#ifndef FolderDialog_H_
#define FolderDialog_H_
class CFolderDialog
{
public:
CFolderDialog(int rootDirFlag = CSIDL_DESKTOP, \
const CString &focusDir = _T(""), \
const CString &title = _T(""), \
DWORD browseInfoFlag = 0);
int DoModal();
inline const CString &GetPath()const
{
return finalPath_;
}
private:
const int rootDirFlag_;
const CString focusDir_;
const CString title_;
const DWORD browseInfoFlag_;
HWND hDialog_;
CString finalPath_;
TCHAR tmpPath_[MAX_PATH];
friend int CALLBACK BrowseDirectoryCallback(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
};
#endif // FolderDialog_H_
FolderDialog.cpp
C/C++ code#include "stdafx.h"
#include "FolderDlg.h"
static int CALLBACK BrowseDirectoryCallback(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
ASSERT(hWnd != NULL);
CFolderDialog *lpDialog = ((CFolderDialog*)lpData);
if (uMsg == BFFM_INITIALIZED)
{
lstrcpy(lpDialog->tmpPath_, lpDialog->focusDir_);
::SendMessage(hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)lpDialog->tmpPath_);
}
return 0;
}
//-------------------------------------------------------------------------
//
//-------------------------------------------------------------------------
CFolderDialog::CFolderDialog(int rootDirFlag, \
const CString &focusDir, \
const CString &title, \
DWORD browseInfoFlag): \
rootDirFlag_(rootDirFlag), \
focusDir_(focusDir), \
title_(title), \
browseInfoFlag_(browseInfoFlag), \
hDialog_(NULL), \
finalPath_(_T(""))\
{
::memset(tmpPath_, 0, sizeof(tmpPath_));
}
int CFolderDialog::DoModal()
{
LPITEMIDLIST rootLoation;
SHGetSpecialFolderLocation(NULL, rootDirFlag_, &rootLoation);
if (rootLoation == NULL)
{
throw new CException();
}
BROWSEINFO browseInfo;
ZeroMemory(&browseInfo, sizeof(browseInfo));
browseInfo.pidlRoot = rootLoation;
browseInfo.ulFlags = browseInfoFlag_;
browseInfo.lpszTitle = title_;
browseInfo.lpfn = BrowseDirectoryCallback;
browseInfo.lParam = (LPARAM)this;
LPITEMIDLIST targetLocation = SHBrowseForFolder(&browseInfo);
if (targetLocation == NULL)
{
return IDCANCEL;
}
TCHAR targetPath[MAX_PATH] = {_T('\0')};
SHGetPathFromIDList(targetLocation, targetPath);
finalPath_ = targetPath;
return IDOK;
}
我前两天刚用的..加入工程..直接调用..可以指定初始目录
CFileDialog fileDialog(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,
L"Key文件 (*.afpkey)|*.afpkey||");
if(IDOK!=fileDialog.DoModal())
{
return ;
}
Assembly codeinclude ole32.inc
includelib ole32.lib
_szDirInfo db "temp"
_BrowseFolderCallBack proc hWnd,uMsg,lParam,lpData
local @szBuffer[260]:byte
mov eax,uMsg
.if eax == BFFM_INITIALIZED
invoke SendMessage,hWnd,BFFM_SETSELECTION,\
TRUE,_BrowseFolderTmp
.elseif eax == BFFM_SELCHANGED
invoke SHGetPathFromIDList,lParam,addr @szBuffer
invoke SendMessage,hWnd,BFFM_SETSTATUSTEXT,\
0,addr @szBuffer
.endif
xor eax,eax
ret
_BrowseFolderCallBack endp
BROWSEINFO STRUCT
HwndOwner dd ? ;对话框的父窗口
PidlRoot dd ? ;用来表示起始目录的ITEMIDLIST目录
PszDisplayName dd ? ;用来接收用户选择目录的缓冲区
LpszTitle dd ? ;对话框中的用户定义文字
ulFlags dd ? ;标志
lpfn dd ? ;回调函数地址
lParam dd ? ;传给回调函数的参数
iImage dd ? ;用来接收选中目录的图像
BROWSEINFO ENDS
Assembly codelocal lpbi: BROWSEINFO
szPath db MAX_PATH dup (?)
mov lpbi.lpfn,offset _BrowseFolderCallBack
mov lpbi.lpszTitle,offset _szDirInfo
mov lpbi.ulFlags,\
BIF_RETURNONLYFSDIRS or BIF_STATUSTEXT
invoke SHBrowseForFolder,lpbi ;返回一个ITEMIDLIST结构指针
invoke SHGetPathFromIDList,lpItemIDList,addr szPath;转换ITEMIDLIST结构为全目录的字符串
不翻译了,罗云逼汇编中的这段大量宏的asm应该很简单。自己使用时需初始化COM以及释放所占用的COM
● ulFlags——用来定义对话框类型的标志,下面是一些重要的标志:
■ BIF_BROWSEFORPRINTER——对话框中只能选择打印机。
■ BIF_BROWSEINCLUDEFILES——同时显示目录中的文件。
■ BIF_RETURNONLYFSDIRS——只返回文件系统中的目录。
■ BIF_STATUSTEXT——对话框中显示一个状态栏。
■ BIF_EDITBOX——显示一个编辑框供用户手工输入目录。
■ BIF_VALIDATE——显示编辑框的时候检测用户输入目录的合法性。
当函数执行后,将显示对话框,当对话框初始化以及每当用户选择不同的目录的时候,函数调用lpfn指定的回调函数,回调函数的参数有4个,分别是父窗口句柄hWnd、消息类型uMsg、消息参数lParam和自定义数据lpData
回调函数可能收到的消息有3种:
● BFFM_INITIALIZED——在对话框初始化的时候收到。
● BFFM_SELCHANGED——在用户选择了一个目录的时候收到,这时lParam参数指向一个表示当前被选择目录的ITEMIDLIST结构。
所以我专门将其封装了一下,力求一步到位。
函数封装如下:
/*****************************************************************
** 函数名:GetPath
** 输 入: 无
** 输 出: CString strPath
** strPath非空, 表示用户选择的文件夹路径
** strPath为空, 表示用户点击了“取消”键,取消选择
** 功能描述:显示“选择文件夹”对话框,让用户选择文件夹
****************************************************************/
CString GetPath()
{
CString strPath = "";
BROWSEINFO bInfo;
ZeroMemory(&bInfo, sizeof(bInfo));
bInfo.hwndOwner = m_hWnd;
bInfo.lpszTitle = _T("请选择路径: ");
bInfo.ulFlags = BIF_RETURNONLYFSDIRS;
LPITEMIDLIST lpDlist; //用来保存返回信息的IDList
lpDlist = SHBrowseForFolder(&bInfo) ; //显示选择对话框
if(lpDlist != NULL) //用户按了确定按钮
{
TCHAR chPath[255]; //用来存储路径的字符串
SHGetPathFromIDList(lpDlist, chPath);//把项目标识列表转化成字符串
strPath = chPath; //将TCHAR类型的字符串转换为CString类型的字符串
}
return strPath;
}
调用时只需要用到以下代码:
CString strPath = GetPath();
则strPath为用户选择的文件夹路径。如果用户点击了对话框的取消键,则strPath为空字符串("");
//-----------------------------------------------------
FolderDialog.h
C/C++ code#ifndef FolderDialog_H_
#define FolderDialog_H_
class CFolderDialog
{
public:
CFolderDialog(int rootDirFlag = CSIDL_DESKTOP, \
const CString &focusDir = _T(""), \
const CString &title = _T(""), \
DWORD browseInfoFlag = 0);
int DoModal();
inline const CString &GetPath()const
{
return finalPath_;
}
private:
const int rootDirFlag_;
const CString focusDir_;
const CString title_;
const DWORD browseInfoFlag_;
HWND hDialog_;
CString finalPath_;
TCHAR tmpPath_[MAX_PATH];
friend int CALLBACK BrowseDirectoryCallback(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
};
#endif // FolderDialog_H_
FolderDialog.cpp
C/C++ code#include "stdafx.h"
#include "FolderDlg.h"
static int CALLBACK BrowseDirectoryCallback(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
ASSERT(hWnd != NULL);
CFolderDialog *lpDialog = ((CFolderDialog*)lpData);
if (uMsg == BFFM_INITIALIZED)
{
lstrcpy(lpDialog->tmpPath_, lpDialog->focusDir_);
::SendMessage(hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)lpDialog->tmpPath_);
}
return 0;
}
//-------------------------------------------------------------------------
//
//-------------------------------------------------------------------------
CFolderDialog::CFolderDialog(int rootDirFlag, \
const CString &focusDir, \
const CString &title, \
DWORD browseInfoFlag): \
rootDirFlag_(rootDirFlag), \
focusDir_(focusDir), \
title_(title), \
browseInfoFlag_(browseInfoFlag), \
hDialog_(NULL), \
finalPath_(_T(""))\
{
::memset(tmpPath_, 0, sizeof(tmpPath_));
}
int CFolderDialog::DoModal()
{
LPITEMIDLIST rootLoation;
SHGetSpecialFolderLocation(NULL, rootDirFlag_, &rootLoation);
if (rootLoation == NULL)
{
throw new CException();
}
BROWSEINFO browseInfo;
ZeroMemory(&browseInfo, sizeof(browseInfo));
browseInfo.pidlRoot = rootLoation;
browseInfo.ulFlags = browseInfoFlag_;
browseInfo.lpszTitle = title_;
browseInfo.lpfn = BrowseDirectoryCallback;
browseInfo.lParam = (LPARAM)this;
LPITEMIDLIST targetLocation = SHBrowseForFolder(&browseInfo);
if (targetLocation == NULL)
{
return IDCANCEL;
}
TCHAR targetPath[MAX_PATH] = {_T('\0')};
SHGetPathFromIDList(targetLocation, targetPath);
finalPath_ = targetPath;
return IDOK;
}
我前两天刚用的..加入工程..直接调用..可以指定初始目录
CFileDialog fileDialog(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,
L"Key文件 (*.afpkey)|*.afpkey||");
if(IDOK!=fileDialog.DoModal())
{
return ;
}
Assembly codeinclude ole32.inc
includelib ole32.lib
_szDirInfo db "temp"
_BrowseFolderCallBack proc hWnd,uMsg,lParam,lpData
local @szBuffer[260]:byte
mov eax,uMsg
.if eax == BFFM_INITIALIZED
invoke SendMessage,hWnd,BFFM_SETSELECTION,\
TRUE,_BrowseFolderTmp
.elseif eax == BFFM_SELCHANGED
invoke SHGetPathFromIDList,lParam,addr @szBuffer
invoke SendMessage,hWnd,BFFM_SETSTATUSTEXT,\
0,addr @szBuffer
.endif
xor eax,eax
ret
_BrowseFolderCallBack endp
BROWSEINFO STRUCT
HwndOwner dd ? ;对话框的父窗口
PidlRoot dd ? ;用来表示起始目录的ITEMIDLIST目录
PszDisplayName dd ? ;用来接收用户选择目录的缓冲区
LpszTitle dd ? ;对话框中的用户定义文字
ulFlags dd ? ;标志
lpfn dd ? ;回调函数地址
lParam dd ? ;传给回调函数的参数
iImage dd ? ;用来接收选中目录的图像
BROWSEINFO ENDS
Assembly codelocal lpbi: BROWSEINFO
szPath db MAX_PATH dup (?)
mov lpbi.lpfn,offset _BrowseFolderCallBack
mov lpbi.lpszTitle,offset _szDirInfo
mov lpbi.ulFlags,\
BIF_RETURNONLYFSDIRS or BIF_STATUSTEXT
invoke SHBrowseForFolder,lpbi ;返回一个ITEMIDLIST结构指针
invoke SHGetPathFromIDList,lpItemIDList,addr szPath;转换ITEMIDLIST结构为全目录的字符串
不翻译了,罗云逼汇编中的这段大量宏的asm应该很简单。自己使用时需初始化COM以及释放所占用的COM
● ulFlags——用来定义对话框类型的标志,下面是一些重要的标志:
■ BIF_BROWSEFORPRINTER——对话框中只能选择打印机。
■ BIF_BROWSEINCLUDEFILES——同时显示目录中的文件。
■ BIF_RETURNONLYFSDIRS——只返回文件系统中的目录。
■ BIF_STATUSTEXT——对话框中显示一个状态栏。
■ BIF_EDITBOX——显示一个编辑框供用户手工输入目录。
■ BIF_VALIDATE——显示编辑框的时候检测用户输入目录的合法性。
当函数执行后,将显示对话框,当对话框初始化以及每当用户选择不同的目录的时候,函数调用lpfn指定的回调函数,回调函数的参数有4个,分别是父窗口句柄hWnd、消息类型uMsg、消息参数lParam和自定义数据lpData
回调函数可能收到的消息有3种:
● BFFM_INITIALIZED——在对话框初始化的时候收到。
● BFFM_SELCHANGED——在用户选择了一个目录的时候收到,这时lParam参数指向一个表示当前被选择目录的ITEMIDLIST结构。
● BFFM_VALIDATEFAILED——用户输入了一个不合法的目录名。