【问题标题】:How to tell if a folder is a subfolder of a special Windows folder?如何判断文件夹是否是特殊 Windows 文件夹的子文件夹?
【发布时间】:2014-06-04 02:30:34
【问题描述】:

如果我有一个特殊文件夹的CSIDL(或其较新的替代品KNOWNFOLDERID)(为了这个例子,我们假设My Documents文件夹)和一个DOS folder path,有什么办法告诉该路径是指特殊文件夹中的子文件夹吗?

编辑1:我在@RemyLebeau 的suggestion 之后实现了以下方法,但它总是将我的nIsParent 设置为0 或not a parent。我错过了什么?

int nCSIDL = CSIDL_PERSONAL;
LPCTSTR pDosPath = L"C:\\Users\\UserName\\Documents\\Subfolder1\\File.txt";

int nIsParent = -1; //-1=error, 0=no, 1=yes

LPITEMIDLIST pidlDocuments = NULL;
if(SUCCEEDED(SHGetFolderLocation(NULL, nCSIDL, NULL, 0, &pidlDocuments)))
{
    LPITEMIDLIST pidl = ILCreateFromPath(pDosPath);
    if(pidl)
    {
        nIsParent = ILIsParent(pidlDocuments, pidl, FALSE) ? 1 : 0;

        ILFree(pidl);
    }

    ILFree(pidlDocuments);
}

编辑 2: 至于他在两个 DOS 路径上使用 SHGetPathFromIDListPathRelativePathTo 的第二个建议,它不适用于以下情况:我的计算机上的文档被重定向到"\\SRVR-A\Home\UserName\Documents",这也是 "R:\Documents" 文件夹,驱动器 R: 映射到该 Home 共享。 PathRelativePathTo 在这些路径上失败。

编辑 3:如果我在 My Documents 中有一个文件夹 Test folder,我可以使用我的映射驱动器 R: 来做到这一点:

subst S: "R:\Documents\Test folder"

从技术上讲,这将使文件夹 "S:\Test folder" 也成为 My Documents 的父级,即 "\\SRVR-A\Home\UserName\Documents\Test folder"

这就是我寻找纯 Shell 或单一 API 解决方案的原因。

【问题讨论】:

  • 如果您使用联结/网络共享/目录链接的全部功能,这将很有趣。即使在一般情况下也无法确定。
  • @Deduplicator:这就是我的意思。这就是为什么我正在寻找一些 Shell API 来为我做这件事(如果有的话。)
  • 我认为您最好的选择是为两者获得规范路径,然后手动解决所有连接点/重解析点/软链接/硬链接/网络挂载等。只有解决了这两个问题,才能得到明确的答案。
  • @Deduplicator: 或者你会得到一个 inifinite 的答案。当心循环结和链接。但我支持你的一般观点。虽然对象管理器会解析名称,但这发生在 KM 中。而且 AFAIK 这些 API 是内部的和/或未记录的,所以他/她不走运。
  • @0xC0000022L 我确信内核中也有无限递归保护。如果触发它,你会得到一个错误。

标签: c++ windows winapi windows-shell


【解决方案1】:

Shell 中的所有内容都由ITEMIDLIST 结构表示,甚至是文件系统路径。使用SHGetFolderLocation()SHGetKnownFolderIDList()检索特殊文件夹的ITEMIDLIST,然后使用SHParseDisplayName()ILCreateFromPath()检索DOS路径的ITEMIDLIST,然后使用ILIsParent()检查特殊文件夹的@987654338 @ 是 DOS 路径的 ITEMIDLIST 的父级。

或者,使用SHGetFolderPath()SHGetKnownFolderPath() 检索特殊文件夹的路径,然后使用PathRelativePathTo 检查是否可以在不使用任何".." 组件的情况下将DOS 路径表示为特殊文件夹路径的相对子文件夹。

【讨论】:

  • 谢谢。我真的对您的纯 Shell 解决方案充满希望,但不幸的是 ILIsParent() 总是返回 FALSE。 (请参阅我的原始帖子。)至于PathRelativePathTo,它不适用于映射驱动器。 (在我的原始帖子中也有详细信息。)
  • 你试过SHParseDisplayName()而不是ILCreateFromPath()吗?在某些路径上,它们可能返回不同的 ITEMIDLIST 值。如果这不起作用,则可以手动遍历 ITEMIDLIST 内容,在每个子级别使用 IShellFolder::CompareIDs()。我希望 ILIsParent() 在内部做类似的事情,但谁知道呢,它可以只做一个原始内存比较。
  • 您可能必须手动将 DOS 路径解析为其真正的目标路径,然后再将其与特殊文件夹进行比较。
  • 我很好奇,为什么ILIsParent() 没有按预期工作——知道吗?
  • 我无法回答这个问题,因为我以前从未做过这种类型的比较。您必须查看 ITEMIDLIST 数据的内部,看看有什么不同。
【解决方案2】:

创建一个获取完整路径、特殊文件夹名称的函数,然后调用 strstr 在带有特殊文件夹名称的完整路径上,如果它不返回 NULL 则它是一个子文件夹。

至于它的 API,我不知道有类似的东西,但有可能。

【讨论】:

  • strstr() 是一种完全匹配的函数。您必须首先规范化这两个字符串。即便如此,改用strcmpi() 会更有意义。类似PathRelativePathTo() 这样的比较会更好。
  • 不谈strstr() 方法:) 这似乎不是一个好主意。它不解决文件夹重定向和映射驱动器。
  • 此外,它是 8 位的,Windows 路径是 UTF-16。您需要应用正确的大小写规则(实际上存储在磁盘上)
  • 我说的是一个总体思路,显然你需要有相同的字符集和大小写,strstr/wcswcs 只是一个小例子。
猜你喜欢
  • 2014-07-28
  • 1970-01-01
  • 2011-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多