[英]cannot get the path for the virtual folder on windows 7 C++(shell namespace extension related)
By using Microsoft windows SDK 7.0, explorerDataProvider, I installed a virtual folder on windows 7. 通过使用Microsoft Windows SDK 7.0,explorerDataProvider,我在Windows 7上安装了一个虚拟文件夹。
When I open the file browse dialog from an application, 当我从应用程序打开文件浏览对话框时,
CFileDialog dlg(TRUE, NULL, 0, OFN_ENABLESIZING | OFN_ALLOWMULTISELECT, L"all(*.*)|*.*||", this);
INT_PTR result = dlg.DoModal();
if (result == IDOK)
{
.
.
.
//some actions
}
it can also display the virtual folder: 它也可以显示虚拟文件夹:
But when I select the file, like "Zero" can then clicks "Open", 但是当我选择文件时,例如“零”可以单击“打开”,
I tried to add breakpoints to 我试图添加断点
INT_PTR result = dlg.DoModal();
But it seems that this error happens inside DoModal()
. 但是似乎此错误发生在
DoModal()
内部。
I doing some research and revise the code of virtual folder: 我进行了一些研究并修改了虚拟文件夹的代码:
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;
}
And return the path in GetDisplayNameOf()
并在
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;
}
But it still stats error message of "Path does not exist" in the application. 但是它仍会在应用程序中统计错误消息“路径不存在”。 I add breakpoints in
GetDisplayNameOf
, but it is never triggered when the application opens a file browse dialog. 我在
GetDisplayNameOf
添加了断点,但是当应用程序打开文件浏览对话框时,它永远不会触发。 But if I open a regular folder just by double click "Computer", it will be triggered. 但是,如果我仅通过双击“计算机”打开常规文件夹,就会触发该文件夹。
The error message of "Path does not exist" seems cannot be deprecated or covered. 错误消息“路径不存在”似乎无法被弃用或覆盖。 Any way that I can revise the virtual folder to return the correct path ?
我可以修改虚拟文件夹以返回正确路径的任何方法吗?
Update : I tried IFileDialog
, I copied the code from the MSDN sample, code, and add breakpoints to see what will happen. 更新 :我尝试了
IFileDialog
,我从MSDN示例中复制了代码,代码,并添加了断点以查看会发生什么。 However, 然而,
// 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
}
}
When I click "Open" button, the error message box of "Path does not exist, check the path and try again" still show up. 当我单击“打开”按钮时,仍然显示“路径不存在,请检查路径并重试”的错误消息框。 And it never comes out of
pfd->Show(NULL)
after I click Open" button. 单击“打开”按钮后,它永远不会从
pfd->Show(NULL)
中pfd->Show(NULL)
。
Based on the comments in the sample code, it should come out of hr = pfd->Show(NULL);
根据示例代码中的注释,它应该来自
hr = pfd->Show(NULL);
and reach to the next line.but the error message happens inside the hr = pfd->Show(NULL);
并到达下一行。但是错误消息发生在
hr = pfd->Show(NULL);
. 。
Update : 更新 :
In the IFileDialog
, I tried 在
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();
}
}
}
I also tried 我也试过
hr = pfd->SetOptions(dwFlags);//delete FOS_FORCEFILESYSTEM
And tried 并尝试
DWORD dwFlags = 0;
if (SUCCEEDED(hr))
{
// overwrite options completely
hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS);
I also tried to return the whole name in namespace extension code: 我还尝试在名称空间扩展代码中返回全名:
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);
}
Update : 更新 :
hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE);
This works for me!! 这对我有用!
With the help of @RemyLebeau, I did some tests in my code. 在@RemyLebeau的帮助下,我在代码中进行了一些测试。 Finally, I found the working solution for me: I copied the code from MSDN for
IFileDialog
: https://msdn.microsoft.com/en-us/library/windows/desktop/bb776913.aspx#file_types and then revise it a little bit: 最后,我找到了适合我的解决方案:我从MSDN复制了
IFileDialog
的代码: https : IFileDialog
,然后进行了一些修改位:
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;
}
The key point is to overwrite the options by SetOptions
. 关键是通过
SetOptions
覆盖选项。 Based on the MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/dn457282(v=vs.85).aspx , 基于MSDN: https : //msdn.microsoft.com/zh-cn/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.
These flags are default values which prevent it returns. 这些标志是阻止其返回的默认值。 So I set it to :
所以我将其设置为:
hr = pfd->SetOptions(dwFlags | FOS_ALLNONSTORAGEITEMS | FOS_NOVALIDATE);
These flags mean: 这些标志意味着:
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.
and 和
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.
Then it finally works! 然后终于可以了!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.