【问题标题】:How to use IFileOperation with relative and absolute paths?如何将 IFileOperation 与相对路径和绝对路径一起使用?
【发布时间】:2020-10-16 11:12:51
【问题描述】:

IFileOperation 相当于什么

SHFILEOPSTRUCTW op = {hDlg, FO_COPY, directoryFrom, directoryTo, 0, FALSE, NULL, NULL};
int status = SHFileOperationW(&op);

directoryFrom 是相对于我的工作目录的目录路径,directoryTo 是绝对路径?

  1. 我可以直接将我的绝对路径传递给SHCreateItemFromParsingName 以获得IShellItem 吗?什么是解析名称和显示名称?
  2. 如果SHCreateItemFromParsingName 适用于绝对路径,我应该将它与GetFullPathNameW 结合使用来解析相对路径还是有更简单的替代方法?

我发现关于这些主题的文档可能会更好。

【问题讨论】:

  • IFileOperation 适用于IShellItem 接口。您不能单独为相对路径创建IShellItem,只能为绝对路径创建。通过使用GetCurrentDirectory() 或等效项然后将您的相对路径附加到它来创建绝对路径并不难。否则,您可以先为您的工作目录获取一个IShellItem,然后使用SHCreateItemFromRelativeName() 为相对于工作目录的路径创建一个IShellItem。但实际上,您不应该一开始就依赖工作目录。始终使用绝对路径。
  • 外壳项并不总是对应于物理文件。因此需要支持虚拟项目的 IFileDialog。 Shell Item 的解析名称在父 Shell 文件夹中应该是唯一的,用于获取 IShellItem。显示名称仅用于显示并且可以是不明确的(两个项目在给定的外壳文件夹中可以具有相同的显示名称)。对于物理文件或文件夹,解析和显示名称是相同的。 SHCreateItemFromParsingName 适用于物理文件和文件夹的绝对路径。
  • @RemyLebeau 我也考虑过使用SHCreateItemFromRelativeName,感谢您确认它应该可以工作。虽然我也许可以取消工作目录来解决我当前的问题,但我仍然认为工作目录是无价的并且可以简化很多事情——尽管在我看来它们可能不应该改变。
  • @SimonMourier 这可以解释为什么 SHCreateItemFromParsingName 可能使用显示名称,但官方文档通过指定它仅使用使其不必要地混淆显示名称没有任何解释。尽管如此,我还是不太了解物理和非物理文件和文件夹之间的区别,以及它们如何与解析和显示名称交互。我是否正确假设物理文件或文件夹将是文件系统中实际存在的文件或文件夹? SHCreateItemFromParsingName 是否不适用于不存在的路径?
  • 如果你能详细解释这些路径和名称以及它们与 shelll 项目和 SHCreateItem... 函数的关系,我会接受这个答案,因为这是我最挣扎的一点.

标签: winapi com windows-shell


【解决方案1】:

Windows Shell 被组织成一个名为 Shellnamespace 的层次结构:Introduction to the Shell Namespace:

Shell 命名空间组织文件系统和其他对象 由 Shell 管理成一个单一的树结构层次结构。 从概念上讲,它是文件的更大、更具包容性的版本 系统。

这意味着,在 Shell 命名空间中,有文件系统(或者我称之为“物理”,考虑到可能的内核文件系统也是物理的)项和虚拟项。虚拟物品示例如下:

  • “这台电脑”文件夹
  • 回收站(其中项目链接到文件系统)
  • 控制面板(完全虚拟)
  • 搜索文件夹(其中项目是指向其他项目的链接)
  • 自定义命名空间扩展(您可以extend the Shell namespace 使用自定义 Shell 命名空间扩展来连接数据库、云存储等)

所有这些项目都使用同一系统识别:PIDLsPIDL 之于 Shell 项就像完整文件路径之于(物理)文件或文件夹。

如果包含文件夹支持,也可以使用它们的解析名称来识别项目,该名称由 IShellFolder::GetDisplayNameOf method_SHGDNF enumeration 间接定义。请注意,PIDL 是严格强制的(每个项目都有一个),而解析名称则不是。

从 Windows Vista 开始,建议使用基于 IShellItem 的 API。并且还推荐IFileDialog,因为它支持 PIDL(=> 虚​​拟项),而不仅仅是文件系统路径。

SHCreateItemFromParsingName 的伪代码或多或少:

  1. 调用SHParseDisplayName(name) => PIDL(旧的基于 PIDL 的 API)
  2. 调用 SHCreateItemFromIDList(pidl) => 一个 IShellItem

这确实证明SHCreateItemFromParsingName 可以被称为SHCreateItemFromDisplayName...

在内部,SHParseDisplayName的代码或多或少:

  1. 获取桌面的IShellFolder(桌面是Shell命名空间的根)
  2. call IShellFolder::ParseDisplayName(name) => 一个 PIDL(相对于桌面,它与绝对相同,因为桌面是命名空间根目录)

IShellFolderall 命名空间文件夹实现的接口:标准 Windows 提供的和自定义的,服务文件系统项或虚拟项。

现在,IShellFolder::ParseDisplayName 的实现有所不同。自定义 Shell 文件夹可以选择以它喜欢的方式实现它(这可能会导致问题)。

但是桌面的IShellFolder 实现相当复杂,并且可以理解文件系统路径来代替显示名称doc 是这样说的:

带有显示名称的以 null 结尾的 Unicode 字符串。因为每个 Shell文件夹定义了自己的解析语法,这个字符串的形式可以 采取可能会有所不同。例如,桌面文件夹接受以下路径 “C:\我的文档\我的 File.txt”。它还将接受对项目的引用 具有与其关联的 GUID 的命名空间,使用 "::{GUID}" 语法。例如,要检索完全限定的 桌面文件夹中控制面板的标识符列表,您可以 使用以下内容:

::{控制面板的CLSID}\::{打印机文件夹的CLSID}

【讨论】:

  • 感谢您提供如此详细的文章。但是,我仍然不确定显示名称和解析名称在哪里彼此不同。例如,我应该能够将 ::{CLSID for Control Panel}\::{CLSID for printers folder} 传递给SHCreateItemFromParsingNameSHParseDisplayName,对吗?但是,解析名称和显示名称又是一回事了?你能举一个这两者实际上不同的例子吗?
  • @purefanatic - 如果您仔细阅读包括链接,您应该能够理解。恐怕你找不到更多解释了。
  • 抱歉耽搁了。我阅读了所有内容,现在变得更聪明了。我认为我的大部分困惑来自于显示名称和解析名称不被认为是不相交的事实:解析名称更像是显示名称的子集,即那些可以被IShellFolder::ParseDisplayName等成功解析的显示名称。只有这样我认为这是有道理的。我觉得这在您的答案文本中可能更清楚。 _SHGDNF 文档在提供实际示例时对我帮助最大。读取的 shell 命名空间扩展相当不相关。
  • @purefanatic - 只有在编写命名空间扩展时,您才能了解 IShellFolder 的真正工作原理。所有 IShellFolder 实现在某种程度上都是“扩展”。甚至是内置的。
猜你喜欢
  • 1970-01-01
  • 2012-01-11
  • 2018-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-15
  • 2012-01-10
相关资源
最近更新 更多