Use*_*123 2 c++ winapi mfc visual-studio-2015
我试图弄清楚是否可以使用OR重新创建CFolderPickerDialog对话而不使用MFC,或者是否有尝试.到目前为止,我没有找到很多提示.这个老问题似乎对我没有帮助.
我目前打开正常的文件夹对话框SHBrowseForFolder.但我需要一个资源管理器风格的对话框.
这是来自另一个应用程序的资源管理器样式对话框(MFC):
#include <afxdlgs.h>需要MFC.我不能在这个特定的项目中使用MFC.
有没有办法在不使用MFC的情况下执行此操作?
老实说,我甚至不知道MFC已经包装了这个.我的类库有自己的实现.而且,正如巴马克所指出的那样,MFC实现甚至可能是错误的,当然还有一些使用警告,如果你没有仔细阅读文档就不会明显.
也就是说,一般来说,使用已经包含在库中的功能是一个很好的建议,因为这会让您的生活更轻松.如果您不想使用整个库,但仍希望了解它如何实现特定功能,则可以检查库的源代码.MFC提供了参考源,因此您可以轻松地执行此操作(也可以调试它).虽然它可能违反了直接从MFC复制和粘贴代码的许可(它也几乎不可能,因为它使用了很多特定于MFC的习惯用法),你可以查看代码来查看它们的内容.重新做,然后回到Windows SDK文档,找出如何自己编写代码.
在这种情况下,相关的SDK文档就在这里.现代版本的Windows(自Vista以来)使用Common Item Dialog API来显示打开/保存文件/文件夹对话框.API包含碱的IFileDialog接口,具有两个子接口,IFileOpenDialog和IFileSaveDialog.这里有很多灵活性; 详细信息在文档中,以及示例代码.
请注意,Common Item Dialog仅适用于Windows Vista及更高版本.如果您需要支持较旧的操作系统(我仍然支持Windows XP),您需要一个后备.该SHBrowseForFolder对话框是后备.它当然有它的设计缺陷,但总比没有好.
如果你想要的只是一个简单的文件夹选择器对话框,这里是我使用的代码的近似值.它使用了几个ATL/MFC类型,比如CString和CComPtr包装类,但是你可以将它转换为你自己选择的替代类(例如std::wstring和_com_ptr_t).它显示一个简单的文件夹浏览对话框,适用于当前操作系统,具有调用者指定的标题和起始路径.如果成功,则返回包含用户选择的文件夹路径的字符串; 否则,它返回一个空字符串.
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("");
}
Run Code Online (Sandbox Code Playgroud)
该对话框仅显示文件系统中的实际文件夹.虽然Common Item Dialog API支持其他类型的特殊文件夹和命名空间,但我不需要在我的应用程序中使用它,因此我的代码不会处理复杂性.如果您需要更多功能,请将此作为起点以及文档.最值得注意的方面可能是使用SHCreateItemFromParsingName(我已经在动态调用中包含以便代码继续在较旧的操作系统上运行)将调用者指定的起始路径(字符串)转换为Shell项目对象(根据Common Item Dialog API的要求).