vc选择路径(SHBrowseForFolder函数)

来源:互联网 发布:c语言网站 编辑:程序博客网 时间:2024/06/07 21:02
   一般的OpenDialog,得到的是文件夹名称,如果要想实现下面的效果,得到选择的路径,这个时候SHBrowseForFolder就派上用场了。

      下面的例子中返回路径,如果没有选,返回"",选择了路径,则返回选择的路径。

    char  *GetPath(HWND   hWnd,char   *pBuffer)  

  {  

    BROWSEINFO   bf;  

    LPITEMIDLIST   lpitem;  

    memset(&bf,0,sizeof   BROWSEINFO);  

    bf.hwndOwner=hWnd;  

    bf.lpszTitle="选择路径";  

    bf.ulFlags=BIF_RETURNONLYFSDIRS;     //属性你可自己选择  

    lpitem=SHBrowseForFolder(&bf);  

    if(lpitem==NULL)     //如果没有选择路径则返回   0  

        return   "";  

   

    //如果选择了路径则复制路径,返回路径长度  

   

    SHGetPathFromIDList(lpitem,pBuffer);  

    return   pBuffer;

  }   

  下面我们来解释一下这个函数用到的一些值的含义。

   1.  BROWSEINFO

      它是一个结构, 原型是

    typedef struct _browseinfo { 

    HWND hwndOwner;          // 弹出的dialog的父窗体的句柄

    LPCITEMIDLIST pidlRoot;  // 指向一个ITEMIDLIST的指针,我们会在后边介绍ITEMIDLIST结构,可空

    LPSTR pszDisplayName;    // 指向一个buffer,这个buffer用来存放用户选中的目录,buffer的size为MAX_PATH  

    LPCSTR lpszTitle;        //指向一个非空的string,用来显示树目录之上的指示信息

    UINT ulFlags;            // 指出了显示的文件夹的类型

    BFFCALLBACK lpfn;        //简单的记为NULL    

    LPARAM lParam;           // 当lpfn不为空时,把dialogbox的值传给回调函数lpfn

    int iImage;              // 系统的图标list的索引,当用户选中目录的时候,得到这个索引

} BROWSEINFO, *PBROWSEINFO, *LPBROWSEINFO;

    ulFlags的可能取值为:

    BIF_BROWSEFORCOMPUTER  ——只返回"我的电脑",当选中"我的电脑"之外的目录时,OK键为灰色

    BIF_BROWSEFORPRINTER       ——只返回"打印机",当选中"打印机"之外的目录时,OK键为灰色

    BIF_DONTGOBELOWDOMAIN   ——不包括"网上邻居"

    BIF_RETURNFSANCESTORS    ——只返回"我的文件",当选中"我的文件"之外的目录时,OK键为灰色

    BIF_RETURNONLYFSDIRS        ——同上

    BIF_STATUSTEXT                         ——Includes a status area in the dialog box. The callback can set the status text by sending messages to the dialog box.

2.  ITEMIDLIST 

   是一个结构,指明了默认浏览的根文件夹的位置,可以为空,那样的话,默认为桌面文件夹的文件目录.

   原型为

  typedef struct _ITEMIDLIST

  {  

    SHITEMID mkid;  // list of item identifers 

  } ITEMIDLIST, * LPITEMIDLIST;

  typedef const ITEMIDLIST * LPCITEMIDLIST;

3.  SHGetPathFromIDList函数

   原型是

   WINSHELLAPI BOOL WINAPI SHGetPathFromIDList(

    LPCITEMIDLIST pidl,  

    LPSTR pszPath 

   );

  反正记住配套使用就行了,哈哈~~

  如果是在bcb环境中使用,那么如果提示不能识别BROWSEINFO,则需加入头文件#i nclude <ShellAPI.h>

,然后在对应的.cpp的include之前#define   NO_WIN32_LEAN_AND_MEAN

 

另一解析:

SHBrowseForFolder

 

LPITEMIDLIST Dir2Pidl(AnsiString &str)
{
HRESULT   hres;
IShellLink   *psl;
ITEMIDLIST   *pidl;
IPersistFile   *ppf;
//用下面这个函数先初始化COM库,
//并把当前线程设为单线程模式(single-thread   apartment(STA)),
//以便后面使用COM库函数
CoInitialize(NULL);        
   
//获得IShellLink接口的指针,放在psl中
hres = CoCreateInstance(
CLSID_ShellLink,   NULL,   CLSCTX_INPROC_SERVER,    
IID_IShellLink, (LPVOID*)&psl);    
if (SUCCEEDED(hres))
{
//   设置目标文件
psl->SetPath(str.c_str());
///   获得目标文件的ITEMIDLIST
psl->GetIDList(&pidl);
//获得IPersistFile接口的指针,放在ppf中
hres = psl->QueryInterface(IID_IPersistFile,   (void**)&ppf);
if (SUCCEEDED(hres))
{
WCHAR   wsz[MAX_PATH];
//<=========下面三行代码完成字符串转为Unicode
#ifdef   _UNICODE
wcscpy(wsz,   str);
#else //把字符串转为Unicode
MultiByteToWideChar(CP_ACP,   0,   str.c_str(),   -1,   wsz,   MAX_PATH);
#endif
//   Load   the   shortcut.
hres   =   ppf->Load(wsz,   STGM_READ);
if   (SUCCEEDED(hres))
   {
   ///   获得快捷方式的ITEMIDLIST
   psl->GetIDList(&pidl);
   }
ppf->Release();
}
psl->Release();
}
CoUninitialize();
return   pidl;
}

short int __fastcall SelectDir(HANDLE HDL, AnsiString &S)
{
LPMALLOC lpMalloc;
if (::SHGetMalloc(&lpMalloc) != NOERROR) return 0;
char szDisplayName[_MAX_PATH];
char szBuffer[_MAX_PATH];
BROWSEINFO browseInfo;
browseInfo.hwndOwner = (void*)(HDL);
browseInfo.pidlRoot = NULL;//NULL; // set root at Desktop
browseInfo.pszDisplayName = S.c_str();//szDisplayName;
browseInfo.lpszTitle = "请选择安装路径";
browseInfo.ulFlags = BIF_RETURNFSANCESTORS|BIF_RETURNONLYFSDIRS;
browseInfo.lpfn = NULL;
browseInfo.lParam = 0;
LPITEMIDLIST lpItemIDList;
if ((lpItemIDList = ::SHBrowseForFolder(&browseInfo)) != NULL)
{ // Get the path of the selected folder from the item ID list.
if (::SHGetPathFromIDList(lpItemIDList, szBuffer))
{ // At this point, szBuffer contains the path the user chose.
if (szBuffer[0] == '/0')
   {
   lpMalloc->Free(lpItemIDList); lpMalloc->Release();
   return 0;  
   }
// We have a path in szBuffer! Return it.
S = szBuffer;
lpMalloc->Free(lpItemIDList); lpMalloc->Release();
return 1;
}
else
{
S = szBuffer;
lpMalloc->Free(lpItemIDList); lpMalloc->Release();
return 1;
}
}
lpMalloc->Free(lpItemIDList); lpMalloc->Release();
return 1;
}

void __fastcall TForm1::Button3Click(TObject *Sender)
{
AnsiString S;
S=Edit1->Hint;
SelectDir(this->Handle, S);
if (Trim(S)!="")
{
if (S[S.Length()]=='//')
Edit1->Hint=S;
else
Edit1->Hint=S+"//";
Edit1->Text=Edit1->Hint+"NNTECH";
}

 

总结:

显示一个用于选择文件夹的对话框.


语法

    PIDLIST_ABSOLUTE SHBrowseForFolder(      
        LPBROWSEINFO lpbi
    );

参数

    lpbi
        [in]  一个指向BROWSEINFO结构的指针,该指针包含了文件夹选择对话框显示的信息。

返回值

    Returns a pointer to an item identifier list (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.

    It is possible that the PIDL returned is that of a folder shortcut rather than a folder. For a full discussion of this case, see the Remarks section.
===========================我的源码======================================================
 
CString CDlgLocalConfig::GetDirectoryPath()
{
 LPITEMIDLIST pidlRoot=NULL;
 SHGetSpecialFolderLocation(m_hWnd,CSIDL_DRIVES,&pidlRoot);
 BROWSEINFO bi;   //必须传入的参数,下面就是这个结构的参数的初始化
 CString strDisplayName;   //用来得到,你选择的活页夹路径,相当于提供一个缓冲区
 bi.hwndOwner=GetSafeHwnd();   //得到父窗口Handle值
 bi.pidlRoot=pidlRoot;   //这个变量就是我们在上面得到的.
 bi.pszDisplayName=strDisplayName.GetBuffer(MAX_PATH+1);   //得到缓冲区指针
 char szLan[32] = {0};
 g_StringLanType(szLan, "文件夹", "Directory");
 bi.lpszTitle=szLan;   //设置标题
 bi.ulFlags=BIF_RETURNONLYFSDIRS;   //设置标志
 bi.lpfn=NULL;
 bi.lParam=0;
 bi.iImage=0;   //上面这个是一些无关的参数的设置,最好设置起来,
 LPITEMIDLIST lpIDList= SHBrowseForFolder(&bi); //打开对话框
 strDisplayName.ReleaseBuffer();   //和上面的GetBuffer()相对应
 char pPath[MAX_PATH];
 CString Str;
 if (lpIDList)
 {
  SHGetPathFromIDList (lpIDList, pPath);
  Str=pPath;
 }
 return Str;
}

SHGetPathFromIDList
功能是把项目标志符列表转换为文件系统路径:
BOOL SHGetPathFromIDList(
   LPCITEMIDLIST pidl,
   LPSTR pszPath
);

参数:
pidl---相对 namespace 的根指定一个文件或目录地点的一张项目标识符表的地址 ( 桌面 ) ;
pszPath---接收文件系统路径的缓冲地址,大小至少是MAX_PATH的字符长度

原创粉丝点击