“选择文件夹”对话框的封装

我们经常需要用到“选择文件夹”对话框,相应的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结构。

● BFFM_VALIDATEFAILED——用户输入了一个不合法的目录名。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值