首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CFolderPickerDialog -无MFC

CFolderPickerDialog -无MFC
EN

Stack Overflow用户
提问于 2016-07-07 12:32:49
回答 1查看 2K关注 0票数 2

我试图弄清楚,如果不使用MFC就可以使用或重新创建CFolderPickerDialog对话框,或者是否有尝试。到目前为止,我还没有找到多少线索。这个老问题似乎也帮不了我。

我现在用SHBrowseForFolder打开普通文件夹对话框。但我需要一个探索者风格的对话框。

下面是来自另一个应用程序的资源管理器样式对话框(MFC):

#include <afxdlgs.h>需要MFC。我不能在这个特定的项目中使用MFC。

有没有一种不用MFC ?就能做到这一点的方法?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-07-08 10:25:40

老实说,我甚至不知道MFC已经包装了这个。我的类库有自己的实现。而且,作为巴马克指出,MFC实现甚至可能是错误的,如果您不仔细阅读文档,当然也会有一些使用上的警告,这一点并不明显。

总之,使用已经封装在库中的功能是很好的建议,因为这会使您的生活更轻松。如果您不想使用整个库,但仍然希望了解它是如何实现特定功能的,则可以检查库的源代码。MFC提供了引用源,这样您就可以轻松地完成此操作(同时也可以调试它)。虽然直接从MFC复制和粘贴代码可能违反了许可(这也几乎是不可能的,因为它使用了那么多特定于MFC的习惯用法),但是您可以查看代码来查看它们正在做什么,然后返回Windows文档来了解如何自己编写代码。

在本例中,相关的SDK文档是这里。Windows的现代版本(自Vista)使用公共项Dialog API显示打开/保存文件/文件夹对话框。API由一个基本的IFileDialog接口组成,有两个子接口,IFileOpenDialogIFileSaveDialog.这里有很大的灵活性;细节在文档中以及示例代码中。

请注意,“公共项”对话框仅在Windows及更高版本上可用。如果您需要支持旧的操作系统(我仍然支持Windows ),那么您需要一个退路。SHBrowseForFolder对话框就是那个回退。它当然有它的设计缺陷,但它总比什么都没有好。

如果您只需要一个简单的文件夹选择对话框,下面是我使用的代码的近似值。它使用了一些ATL/MFC类型,比如CStringCComPtr包装类,但是您可以将它们转换为自己选择的替代类(比如std::wstring_com_ptr_t)。它显示一个简单的浏览文件夹对话框,适合当前操作系统,具有调用方指定的标题和启动路径.如果成功,则返回一个字符串,其中包含用户选择的文件夹的路径;否则,返回一个空字符串。

代码语言:javascript
复制
namespace
{
   HRESULT Downlevel_SHCreateItemFromParsingName(PCWSTR pszPath, IBindCtx* pbc, REFIID riid, void** ppv)
   {
      _ASSERTE(IsWinVistaOrLater());

      HRESULT hResult = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
      const HINSTANCE hinstLib = GetModuleHandle(TEXT("shell32"));
      if (hinstLib)
      {
         typedef HRESULT (WINAPI * pfSHCreateItemFromParsingName)(PCWSTR, IBindCtx*, REFIID, void**);
         const pfSHCreateItemFromParsingName pf = reinterpret_cast<pfSHCreateItemFromParsingName>(GetProcAddress(hinstLib, _CRT_STRINGIZE(SHCreateItemFromParsingName)));
         if (pf)
         {
            hResult = pf(pszPath, pbc, riid, ppv);
         }
      }
      return hResult;
   }

   int CALLBACK BrowseForFolderCallbackProc(HWND hWnd, UINT uMsg, LPARAM /* lParam */, LPARAM lData)
   {
      if (uMsg == BFFM_INITIALIZED)
      {
         // Start with BFFM_SETSELECTION, which is always available.
         SendMessage(hWnd, BFFM_SETSELECTION, TRUE, lData);

      #ifdef UNICODE
         // If possible, also try to use BFFM_SETEXPANDED, which was introduced with
         // version 6.0 of the shell (Windows XP).
         SendMessage(hWnd, BFFM_SETEXPANDED, TRUE, lData);

         // You can also set the caption for the dialog's "OK" button here, if you like
         // (e.g., by loading a string from a resource).
         //SendMessage(hWnd,
         //            BFFM_SETOKTEXT,
         //            0,
         //            reinterpret_cast<LPARAM>(pszOKBtnCaption));
      #endif  // UNICODE
      }
      return 0;
   }
}

CString ShowFolderBrowserDialog(HWND hwndOwner, const CString& strDlgTitle, const CString& strStartPath)
{
   if (IsWinVistaOrLater())
   {
      CComPtr<IFileOpenDialog> pFileOpenDlg;
      if (SUCCEEDED(pFileOpenDlg.CoCreateInstance(__uuidof(FileOpenDialog))))
      {
        if (SUCCEEDED(pFileOpenDlg->SetTitle(strDlgTitle)))
        {
            FILEOPENDIALOGOPTIONS options;
            if (SUCCEEDED(pFileOpenDlg->GetOptions(&options)))
            {
               if (SUCCEEDED(pFileOpenDlg->SetOptions(options | FOS_PATHMUSTEXIST | FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM)))
               {
                  CComPtr<IShellItem> psiStartPath;
                  if (SUCCEEDED(Downlevel_SHCreateItemFromParsingName(static_cast<const TCHAR*>(strStartPath),
                                                                      NULL,
                                                                      IID_PPV_ARGS(&psiStartPath))))
                  {
                     if (SUCCEEDED(pFileOpenDlg->SetFolder(psiStartPath)))
                     {
                        if (SUCCEEDED(pFileOpenDlg->Show(hwndOwner)))
                        {
                           CComPtr<IShellItem> pShellItemResult;
                           pFileOpenDlg->GetResult(&pShellItemResult);
                           CComHeapPtr<TCHAR> pszSelectedItem;
                           if (SUCCEEDED(pShellItemResult->GetDisplayName(SIGDN_FILESYSPATH, &pszSelectedItem)))
                           {
                              return pszSelectedItem;
                           }
                        }
                     }
                  }
               }
            }
         }
      }
   }
   else
   {
      TCHAR szBuffer[MAX_PATH + 1];
      szBuffer[0] = TEXT('\0');

      BROWSEINFO bi;
      bi.hwndOwner      = hwndOwner;
      bi.pidlRoot       = nullptr;
      bi.pszDisplayName = szBuffer;
      bi.lpszTitle      = strDlgTitle;
      bi.ulFlags        = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_SHAREABLE | BIF_NONEWFOLDERBUTTON;
      bi.lpfn           = BrowseForFolderCallbackProc;
      bi.lParam         = reinterpret_cast<LPARAM>(static_cast<const TCHAR*>(strStartPath));

      CComHeapPtr<ITEMIDLIST> pidl(SHBrowseForFolder(&bi));
      if (pidl && SHGetPathFromIDList(pidl, szBuffer))
      {
         return pszSelectedItem;
      }
   }
   return TEXT("");
}

该对话框只显示文件系统中的实际文件夹。虽然公共项对话框API支持其他类型的特殊文件夹和命名空间,但我的应用程序中不需要这样做,所以我的代码不会处理复杂性。如果您需要更多的功能,请将它与文档一起用作起点。最值得注意的方面可能是使用SHCreateItemFromParsingName (我已经完成了一个动态调用,以便代码继续在旧的操作系统上运行)来将调用方指定的启动路径(即字符串)转换为Shell项对象(公共项对话框API所要求的)。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38245583

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档