невозможно получить путь к виртуальной папке в Windows 7 C ++ (связано расширение пространства имен оболочки)

Используя 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);

Это работает для меня!

0

Решение

С помощью @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.

Тогда это наконец работает!

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]