从SHGetPathFromIDList返回的文件夹位置不正确

时间:2015-07-23 11:16:05

标签: windows shell winapi visual-c++

我试图限制用户访问某个位置(Windows,Program Files等)并通过实现IFolderFilter接口来实现这一点。

一切似乎都很好,直到ShouldShow函数被调用,然后它们似乎都崩溃了。我们传入的初始文件夹是C:\ ProgramData \ Company \ App \ Year,我们看到了,但文件对话框显示它挂在桌面上,这就是为什么当我检查pidl中包含的文件夹时,就像C: \ Users \ Graham.Reeds \ Desktop \ Windows,C:\ Users \ Graham.Reeds \ Desktop \ Program Files等。这似乎阻止了它们与我希望阻止用户选择的CSIDL_变量相匹配。 / p>

我尝试使用SHGetPathFromIDListExSHGetKnownFolderIDList,但VS2010给了我'标识符X未定义'但我包含了shlobj并链接到Shell32.lib。

HRESULT STDMETHODCALLTYPE ShouldShow(IShellFolder* sf, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlItem)  
{  
    HRESULT resultCode = S_OK;  
    ULONG attributes = 0UL;  

    if (SUCCEEDED(sf->GetAttributesOf(1, &pidlItem, &attributes)))  
    {
        char szPath[_MAX_PATH];
        BOOL f = SHGetPathFromIDList(pidlItem, szPath);
//      BOOL f = SHGetPathFromIDListEx(pidlItem, szPath, _MAX_PATH, 0);

        // FOLDERID_Windows / CSIDL_WINDOWS
        PIDLIST_ABSOLUTE pidl;
//      if (SUCCEEDED(SHGetKnownFolderIDList(FOLDERID_Windows, 0, 0, &pidl)))
        if (SUCCEEDED(SHGetFolderLocation(0, CSIDL_WINDOWS, 0, 0, &pidl)))
        {
            HRESULT hres = sf->CompareIDs(0, pidlItem, pidl);
            if ((short)HRESULT_CODE(hres) == 0)
            {
                resultCode = S_FALSE;
            }
            ILFree(pidl);
        }
    }
    return resultCode;  
}

我需要做的是能够阻止某些文件夹出现在浏览文件夹中。我怎么能这样做?

2 个答案:

答案 0 :(得分:0)

SHGetPathFromIDList需要一个绝对PIDL(一个从名称空间层次结构顶部的桌面开始向下工作),但是你传递的是pidlItem,它是一个单独的子PIDL({{1} }}相对于pidlItem,而不是桌面。

您可以使用带有pidlFolder标记的SHGetPathFromIDList代替使用IShellFolder::GetDisplayNameOf来获取商品的完整路径(例如SHGDN_FORPARSING)。

您的sf->GetDisplayNameOf(pidlItem, ...)电话也会出现同样的问题。 CompareIDs需要两个相对于指定文件夹的PIDL,但是您尝试使用一个相对PIDL和一个绝对值来调用它。

一种解决方案是使用IShellFolder::CompareIDspidlFolderpidlItem创建绝对PIDL并将其传递给ILCombine,但您需要使用桌面文件夹进行比较(从CompareIDs获得)而不是使用SHGetDesktopFolder

答案 1 :(得分:0)

您正在将苹果(文件夹相对PIDL)与橙子(绝对PIDL)进行比较。您需要将相对PIDL转换为绝对PIDL,然后才能将其与位于Shell命名空间的不同文件夹中的另一个项目进行比较。

尝试更像这样的事情:

bool ArePIDLsTheSameItem(PCIDLIST_ABSOLUTE pidl1, PCIDLIST_ABSOLUTE pidl2)
{
    if (ILIsEqual(pidl1, pidl2))
        return true;

    IShellFolder *sfDesktop = NULL;
    if (SHGetDesktopFolder(&sfDesktop) == S_OK)
    {
        HRESULT hres = sfDesktop->CompareIDs(0, pidl1, pidl2);
        sfDesktop->Release();

        if (HRESULT_CODE(hres) == 0)
            return true;
    }    

    return false;
}

HRESULT STDMETHODCALLTYPE ShouldShow(IShellFolder* sf, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlItem)  
{  
    HRESULT resultCode = S_OK;

    PIDLIST_ABSOLUTE pidlWindows = NULL;
    //if (SUCCEEDED(SHGetKnownFolderIDList(FOLDERID_Windows, 0, 0, &pidlWindows)))
    if (SUCCEEDED(SHGetFolderLocation(0, CSIDL_WINDOWS, 0, 0, &pidlWindows)))
    {
        if (ArePIDLsTheSameItem(pidlWindows, pidlFolder))
        {
            // ignore anything inside the Windows folder itself...
            resultCode = S_FALSE;
        }
        else if (ILIsParent(pidlWindows, pidlFolder, FALSE))
        {
            // ignore anything inside a subfolder of the Windows folder...
            resultCode = S_FALSE;
        }
        else
        {
            PIDLIST_ABSOLUTE pidlFolderAndItem = ILCombine(pidlFolder, pidlItem);
            if (pidlFolderAndItem)
            {
                if (ArePIDLsTheSameItem(pidlFolderAndItem, pidlWindows))
                {
                    // ignore the Windows folder itself...
                    resultCode = S_FALSE;
                }

                ILFree(pidlFolderAndItem);
            }
        }

        ILFree(pidlWindows);
    }

    return resultCode;  
}