zoukankan      html  css  js  c++  java
  • 文件夹浏览(SHBrowseForFolder)

    from http://www.cnblogs.com/Clingingboy/archive/2011/04/16/2018284.html

    一.首先要为SHBrowseForFolder准备一个结构体BROWSEINFO

    typedef struct _browseinfoW {
        HWND        hwndOwner;
        PCIDLIST_ABSOLUTE pidlRoot;
        LPWSTR       pszDisplayName;        // Return display name of item selected.
        LPCWSTR      lpszTitle;                     // text to go in the banner over the tree.
        UINT         ulFlags;                       // Flags that control the return stuff
        BFFCALLBACK  lpfn;
        LPARAM       lParam;                        // extra info that's passed back in callbacks
        int          iImage;                        // output var: where to return the Image index.
    } BROWSEINFOW, *PBROWSEINFOW, *LPBROWSEINFOW;
    

    二.获取PIDL

    在BROWSEINFOW结构体中,pidlRoot是最关键的,需要调用一些额外的函数来获取PIDL,然后给pidlRoot赋值

    1.获取特殊的目录地址

    在Windows中有很多特殊的的目录地址,如我的电脑,控件面板,我的图片等,如下定义

    #define CSIDL_DESKTOP                   0x0000        // <desktop>
    #define CSIDL_INTERNET                  0x0001        // Internet Explorer (icon on desktop)
    #define CSIDL_PROGRAMS                  0x0002        // Start MenuPrograms
    #define CSIDL_CONTROLS                  0x0003        // My ComputerControl Panel
    #define CSIDL_PRINTERS                  0x0004        // My ComputerPrinters
    #define CSIDL_PERSONAL                  0x0005        // My Documents
    #define CSIDL_FAVORITES                 0x0006        // <user name>Favorites
    #define CSIDL_STARTUP                   0x0007        // Start MenuProgramsStartup
    #define CSIDL_RECENT                    0x0008        // <user name>Recent
    

    我们可以通过SHGetSpecialFolderLocation来填充一个LPITEMIDLIST,

    BROWSEINFO bi;
    bi.hwndOwner = hDlg;
    TCHAR szTitle[MAX_PATH] = {0};
    TCHAR szPath[MAX_PATH] = {0};
    TCHAR szDisplay[MAX_PATH] = {0};
    LPITEMIDLIST pidl = NULL;
    SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
    bi.pidlRoot = pidl;
    

    然后调用SHBrowseForFolder(&bi);就可以出现以下对话框

    p1

    2.使用IShellFolder获取目录地址

    如果不是特殊目录的,可以使用IShellFolder的ParseDisplayName方法,来获取PIDL

    首先要调用SHGetDesktopFolder函数来获取IShellFolder,ShellFolder代表桌面,表示是根目录,根目录总是有办法找到任意一个子目录的 
    然后调用ParseDisplayName方法来解析目录,最终得到LPITEMIDLIST。 
    下面的步骤还是一样把LPITEMIDLIST填充到BROWSEINFO的pidlRoot 字段,调用SHBrowseForFolder方法

    SHParseDisplayName方法提供了一个便利

    HRESULT SHPathToPIDL(LPCTSTR szPath, LPITEMIDLIST* ppidl)
    {
       LPSHELLFOLDER pShellFolder = NULL;
       OLECHAR wszPath[MAX_PATH] = {0};
       ULONG nCharsParsed = 0;
    
       // Get an IShellFolder interface pointer
       HRESULT hr = SHGetDesktopFolder(&pShellFolder);
       if(FAILED(hr))
          return hr;
    
       // Convert the path name to Unicode
       MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szPath, -1, wszPath, MAX_PATH);
    
       // Call ParseDisplayName() to do the job
       hr = pShellFolder->ParseDisplayName(NULL, NULL, wszPath, &nCharsParsed, ppidl, NULL);
    
       // Clean up
       pShellFolder->Release();
       return hr;
    }
    

    3.获取选择的目录

    当选中目录点击确定之后,就需要获取一个文件系统路径,可以使用SHGetPathFromIDList函数

    SHGetPathFromIDList(pidlFolder, szPath);
    

    szPath就是我们想要的结果

    4.BROWSEINFO的回调方法

    在.net中会声明很多的事件,若Initialized,SelectedChanged等,c++是采用消息的机制,根据消息的不同进行不同处理,当然这些消息都是预先定义好的.

    #define BFFM_INITIALIZED        1
    #define BFFM_SELCHANGED         2
    #define BFFM_VALIDATEFAILEDA    3   // lParam:szPath ret:1(cont),0(EndDialog)
    #define BFFM_VALIDATEFAILEDW    4   // lParam:wzPath ret:1(cont),0(EndDialog)
    #define BFFM_IUNKNOWN           5   // provides IUnknown to client. lParam: IUnknown*
    

    示例如下:

    bi.lpfn = BrowseCallbackProc;
    
    int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM dwData)
    {
       switch(uMsg)
       {
       case BFFM_INITIALIZED:
          {
          
          }
          break;
    
       case BFFM_SELCHANGED:
          {
            
          }
          break;
    
       case BFFM_VALIDATEFAILED:
       
          return 1;
       }
    
       return 0;
    }
    

    三.文件夹选项

    如下图,应该是很熟悉

    image

    SHGetSettings函数可以获取这些选项的信息,存在结构体SHELLFLAGSTATE当中

    typedef struct {
        BOOL fShowAllObjects : 1;
        BOOL fShowExtensions : 1;
        BOOL fNoConfirmRecycle : 1;
        BOOL fShowSysFiles : 1;
        BOOL fShowCompColor : 1;
        BOOL fDoubleClickInWebView : 1;
        BOOL fDesktopHTML : 1;
        BOOL fWin95Classic : 1;
        BOOL fDontPrettyPath : 1;
        BOOL fShowAttribCol : 1;
        BOOL fMapNetDrvBtn : 1;
        BOOL fShowInfoTip : 1;
        BOOL fHideIcons : 1;
    #if (NTDDI_VERSION >= NTDDI_VISTA)
        BOOL fAutoCheckSelect: 1;
        BOOL fIconsOnly: 1;
        UINT fRestFlags : 1; // when adding additional flags keep SHELLSTATE and SHGetSettings in sync.
    
    #else
        UINT fRestFlags : 3; // when adding additional flags keep SHELLSTATE and SHGetSettings in sync.
    #endif
    } SHELLFLAGSTATE, *LPSHELLFLAGSTATE;
    

    必须输入想要获取标识才行,不然就会是默认值(难道是为了性能,为何如此,太麻烦)

    SHELLFLAGSTATE sfs;
    SHGetSettings(&sfs, SSF_DESKTOPHTML | SSF_SHOWALLOBJECTS |
                   SSF_MAPNETDRVBUTTON | SSF_SHOWATTRIBCOL | SSF_SHOWEXTENSIONS);
  • 相关阅读:
    第二十九课 循环链表的实现
    第二十八课 再论智能指针(下)
    第二十七课 再论智能指针(上)
    第二十六课 典型问题分析(Bugfix)
    普通new和placement new的重载
    leetcode 581. Shortest Unsorted Continuous Subarray
    leetcode 605. Can Place Flowers
    leetcode 219. Contains Duplicate II
    leetcode 283. Move Zeroes
    leetcode 217. Contains Duplicate
  • 原文地址:https://www.cnblogs.com/kex1n/p/3945376.html
Copyright © 2011-2022 走看看