简体   繁体   English

无法获取Windows 7 C ++上虚拟文件夹的路径(与外壳名称空间扩展有关)

[英]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);
    }

But the result is: 但是结果是: 在此处输入图片说明

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.

相关问题 Windows Shell名称空间文件夹视图扩展注册为特定文件扩展名 - Registration of windows shell namespace folder view extension for particular file extension 为什么在c ++中使用shell链接查找快捷方式的目标路径时,它指的是windows\\installer文件夹 - Why in finding target path of shortcut with shell link in c++ it refers to windows\installer folder C++ 程序的资产文件夹路径 [windows] - Asset folder path for c++ program [windows] 如何通过外壳名称空间扩展在Windows的文件夹视图中添加背景照片/文本 - How to add background photos/text in the folder view on windows by shell namespace extension 在windows shell命名空间扩展下使用_wopen() - Using _wopen() under windows shell namespace extension 如何在Windows 7上的C ++中为虚拟文件夹创建快捷方式? - How to create shortcut for virtual folder in C++ on windows 7? Shell命名空间扩展。 C#。 C ++,MFC,AT-用什么? - Shell Namespace Extension. C#. C++, MFC, AT—what to use? C ++获取文件扩展名而不在路径中提供扩展 - C++ Get File Extension Without Providing Extension In The Path 获取Windows Explorer C ++的当前路径 - Get current path of windows explorer C++ C ++ Shell函数获取公共库文件夹的CSIDL - C++ Shell function to get CSIDL for a public library folder
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM