Используя Microsoft Windows SDK 7.0, explorerDataProvider, я установил виртуальную папку на Windows 7.
Когда я открываю диалог просмотра файлов из приложения,
CFileDialog dlg(TRUE, NULL, 0, OFN_ENABLESIZING | OFN_ALLOWMULTISELECT, L"all(*.*)|*.*||", this);
INT_PTR result = dlg.DoModal();
if (result == IDOK)
{
.
.
.
//some actions
}
он также может отображать виртуальную папку:
Но когда я выбираю файл, например «Ноль», то нажимает «Открыть»,
Я пытался добавить точки останова в
INT_PTR result = dlg.DoModal();
Но похоже, что эта ошибка происходит внутри DoModal()
,
Я провожу некоторые исследования и пересматриваю код виртуальной папки:
HRESULT CFolderViewImplFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, ULONG *rgfInOut)
{
// If SFGAO_FILESYSTEM is returned, GetDisplayNameOf(SHGDN_FORPARSING) on that item MUST
// return a filesystem path.
HRESULT hr = E_INVALIDARG;
DWORD dwAttribs = 0;
dwAttribs |= SFGAO_BROWSABLE;
if (1 == cidl)
{
int nLevel = 0;
hr = _GetLevel(apidl[0], &nLevel);
if (SUCCEEDED(hr))
{
BOOL fIsFolder = FALSE;
hr = _GetFolderness(apidl[0], &fIsFolder);
if (SUCCEEDED(hr))
{
if (fIsFolder)
{
dwAttribs |= SFGAO_FOLDER;
dwAttribs |= SFGAO_FILESYSANCESTOR;
}
else
{
dwAttribs |= SFGAO_SYSTEM;
dwAttribs |= SFGAO_FILESYSTEM;
}
if (nLevel < g_nMaxLevel)
{
dwAttribs |= SFGAO_HASSUBFOLDER;
}
}
}
}
*rgfInOut &= dwAttribs;
return hr;
}
И вернуть путь вGetDisplayNameOf()
HRESULT CFolderViewImplFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, SHGDNF shgdnFlags, STRRET *pName)
{
HRESULT hr = S_OK;
if (shgdnFlags & SHGDN_FORPARSING)
{
WCHAR szDisplayName[MAX_PATH];
if (shgdnFlags & SHGDN_INFOLDER)
{
// This form of the display name needs to be handled by ParseDisplayName.
hr = _GetName(pidl, szDisplayName, ARRAYSIZE(szDisplayName));
}
else
{
PWSTR pszThisFolder = L"Computer\\Jerry";
StringCchCopy(szDisplayName, ARRAYSIZE(szDisplayName), pszThisFolder);
StringCchCat(szDisplayName, ARRAYSIZE(szDisplayName), L"\\");
WCHAR szName[MAX_PATH];
hr = _GetName(pidl, szName, ARRAYSIZE(szName));
if (SUCCEEDED(hr))
{
StringCchCat(szDisplayName, ARRAYSIZE(szDisplayName), szName);
}
}
if (SUCCEEDED(hr))
{
hr = StringToStrRet(szDisplayName, pName);
}
}
else
{
PWSTR pszName;
hr = _GetName(pidl, &pszName);
if (SUCCEEDED(hr))
{
hr = StringToStrRet(pszName, pName);
CoTaskMemFree(pszName);
}
}
return hr;
}
Но это все-таки статистика ошибок сообщения «Путь не существует» в приложении.
Я добавляю точки останова в GetDisplayNameOf
, но он никогда не запускается, когда приложение открывает диалог просмотра файлов. Но если я открою обычную папку, просто дважды щелкнув «Компьютер», она будет запущена.
Сообщение об ошибке «Путь не существует», по-видимому, не может быть признано устаревшим или скрыто. Любой способ, которым я могу пересмотреть виртуальную папку, чтобы вернуть правильный путь?
Обновить: Я старался IFileDialog
Я скопировал код из примера MSDN, добавил код и добавил точки останова, чтобы посмотреть, что произойдет. Тем не мение,
// Show the dialog
hr = pfd->Show(NULL);//the breakpoint is added here
if (SUCCEEDED(hr))
{
// Obtain the result once the user clicks
// the 'Open' button.
// The result is an IShellItem object.
IShellItem *psiResult;
hr = pfd->GetResult(&psiResult);
if (SUCCEEDED(hr))
{
//do something
}
}
Когда я нажимаю кнопку «Открыть», появляется сообщение об ошибке «Путь не существует, проверьте путь и повторите попытку». И это никогда не выходит из pfd->Show(NULL)
после того, как я нажму кнопку «Открыть».
Основываясь на комментариях в примере кода, он должен выходить из hr = pfd->Show(NULL);
и добраться до следующей строки. но сообщение об ошибке происходит внутри hr = pfd->Show(NULL);
,
Обновить:
в IFileDialog
, Я старался
hr = pfd->GetOptions(&dwFlags);
if (SUCCEEDED(hr))
{
hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS);
if (SUCCEEDED(hr))
{
// Show the dialog
hr = pfd->Show(NULL);
if (SUCCEEDED(hr))
{
// Obtain the result once the user clicks
// the 'Open' button.
// The result is an IShellItem object.
IShellItem *psiResult;
hr = pfd->GetResult(&psiResult);
if (SUCCEEDED(hr))
{
// We are just going to print out the
// name of the file for sample sake.
PWSTR pszFilePath = NULL;
hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH,
&pszFilePath);
if (SUCCEEDED(hr))
{
TaskDialog(NULL,
NULL,
L"CommonFileDialogApp",
pszFilePath,
NULL,
TDCBF_OK_BUTTON,
TD_INFORMATION_ICON,
NULL);
CoTaskMemFree(pszFilePath);
}
psiResult->Release();
}
}
}
Я тоже пробовал
hr = pfd->SetOptions(dwFlags);//delete FOS_FORCEFILESYSTEM
И попробовал
DWORD dwFlags = 0;
if (SUCCEEDED(hr))
{
// overwrite options completely
hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS);
Я также попытался вернуть все имя в коде расширения пространства имен:
WCHAR szDisplayName[MAX_PATH];
if (shgdnFlags & SHGDN_INFOLDER)
{
// This form of the display name needs to be handled by ParseDisplayName.
hr = _GetName(pidl, szDisplayName, ARRAYSIZE(szDisplayName));
}
else
{
PWSTR pszThisFolder;// = L"Computer\\Jerry";
hr = SHGetNameFromIDList(m_pidl, (shgdnFlags & SHGDN_FORADDRESSBAR) ? SIGDN_DESKTOPABSOLUTEEDITING : SIGDN_DESKTOPABSOLUTEPARSING, &pszThisFolder);
if (SUCCEEDED(hr))
{
StringCchCopy(szDisplayName, ARRAYSIZE(szDisplayName), pszThisFolder);
StringCchCat(szDisplayName, ARRAYSIZE(szDisplayName), L"\\");
WCHAR szName[MAX_PATH];
hr = _GetName(pidl, szName, ARRAYSIZE(szName));
if (SUCCEEDED(hr))
{
StringCchCat(szDisplayName, ARRAYSIZE(szDisplayName), szName);
}
CoTaskMemFree(pszThisFolder);
}
}
if (SUCCEEDED(hr))
{
hr = StringToStrRet(szDisplayName, pName);
}
Обновить:
hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE);
Это работает для меня!
С помощью @RemyLebeau я провел несколько тестов в своем коде. Наконец, я нашел рабочее решение для меня:
Я скопировал код из MSDN для IFileDialog
: https://msdn.microsoft.com/en-us/library/windows/desktop/bb776913.aspx#file_types
а затем немного пересмотреть:
HRESULT BasicFileOpen()
{
// CoCreate the File Open Dialog object.
IFileDialog *pfd = NULL;
HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&pfd));
if (SUCCEEDED(hr))
{
// Create an event handling object, and hook it up to the dialog.
IFileDialogEvents *pfde = NULL;
hr = CDialogEventHandler_CreateInstance(IID_PPV_ARGS(&pfde));
if (SUCCEEDED(hr))
{
// Hook up the event handler.
DWORD dwCookie;
hr = pfd->Advise(pfde, &dwCookie);
if (SUCCEEDED(hr))
{
// Set the options on the dialog.
DWORD dwFlags = 0;
if (SUCCEEDED(hr))
{
// the default flag is FOS_PATHMUSTEXIST and FOS_FILEMUSTEXIST, so I set overwrite it with these two flags.
hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE);
if (SUCCEEDED(hr))
{
// Show the dialog
hr = pfd->Show(NULL);
if (SUCCEEDED(hr))
{
// Obtain the result once the user clicks
// the 'Open' button.
// The result is an IShellItem object.
IShellItem *psiResult;
hr = pfd->GetResult(&psiResult);
if (SUCCEEDED(hr))
{
// We are just going to print out the
// name of the file for sample sake.
PWSTR pszFilePath = NULL;
hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH,
&pszFilePath);
if (SUCCEEDED(hr))
{
TaskDialog(NULL,
NULL,
L"CommonFileDialogApp",
pszFilePath,
NULL,
TDCBF_OK_BUTTON,
TD_INFORMATION_ICON,
NULL);
CoTaskMemFree(pszFilePath);
}
psiResult->Release();
}
}
}
}
// Unhook the event handler.
pfd->Unadvise(dwCookie);
}
pfde->Release();
}
pfd->Release();
}
return hr;
}
Ключевым моментом является перезапись опций SetOptions
, На основании MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/dn457282(v=vs.85).aspx ,
FOS_PATHMUSTEXIST
The item returned must be in an existing folder. This is a default value.
FOS_FILEMUSTEXIST
The item returned must exist. This is a default value for the Open dialog.
Эти флаги являются значениями по умолчанию, которые предотвращают его возврат.
Поэтому я установил его на:
hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE);
Эти флаги означают:
FOS_NOVALIDATE
Do not check for situations that would prevent an application from opening the selected file, such as sharing violations or access denied errors.
а также
FOS_ALLNONSTORAGEITEMS
Enables the user to choose any item in the Shell namespace, not just those with SFGAO_STREAM or SFAGO_FILESYSTEM attributes. This flag cannot be combined with FOS_FORCEFILESYSTEM.
Тогда это наконец работает!
Других решений пока нет …