6

我开始尝试使用此代码项目教程实现虚拟文件的拖放(来自 C# 4/WPF 应用程序)。在花了一些时间试图找出 DV_E_FORMATETC错误后,我发现我需要支持“Shell IDList Array”数据格式。但是关于这种格式的实际作用似乎几乎为零。

经过一番搜索,我发现这个关于高级数据传输的页面说 Shell IDList Array is a pointer to a CIDA structure。然后,此 CIDA 结构包含 PIDL 的数量以及它们的偏移量列表。那么PIDL到底是什么?经过一番搜索,这个页面有点暗示它是一个指向ITEMIDLIST的指针,它本身包含一个成员,它是一个SHITEMID的列表。

我做了更多的阅读,我仍然无法判断多个 PIDL 的用途,但是路径中的每个“级别”都有一个 SHITEMID。至少这是解决了一个谜。

我的下一个想法是尝试使用虚拟文件 (WinSCP) 从另一个应用程序中拖动文件。我刚刚得到了这种格式的 MemoryStream。至少我知道要为这个东西提供什么类,但这对解释要放什么东西根本没有帮助。我尝试根据上面链接中的格式检查此 MemoryStream,但没有成功。我刚取回垃圾数据,其中一个“cb”字段告诉我,当整个流只有 539 个字节时,它的长度为 18000 个字节。

此外,在进一步阅读后,此页面似乎暗示 PIDL 中包含的数据实际上是一条路径,并且在十六进制编辑器中检查所述 MemoryStream 的内容会在我的本地 Temp 目录中产生一条路径(分成几部分,反正)。

似乎 WinSCP 只是使用一个 shell 扩展来处理资源管理器的丢弃,我真的不想诉诸于此。但是,它有另一种模式,在它传输到临时文件夹之前中止拖放 - 这对我来说是可以接受的,但我一点也不知道该怎么做。

我现在的问题是:

  1. 什么是 SHITEMID 的有效“abID”成员?这些虚拟文件只存在于我的程序中;当它执行GetData时,它们会被拖到后面传递“abID”吗?它们必须是系统唯一的吗?
  2. 我如何管理 WinSCP 所做的中止和稍后重做的拖放操作?
  3. 如果我必须为此实现一个 shell 扩展,我该怎么做呢?我确信我可以很容易地找到 shell 扩展理论的解释,但是我将如何支持自定义 PIDL 或其他什么?

任何帮助甚至解释我应该做什么的链接将不胜感激。

编辑:所以这就是我最终是如何做到的:

我从上面的 CodeProject 教程中删除了大部分代码,保留了用于创建 FileGroupDescriptor 的函数。然后我重新实现了 .Net IDataObject 接口(实际上,我根本不必使用 COM IDataObject 接口)。然后我被迫在后台同步下载文件,并从 GetData() 传回 MemoryStream。方便的是,实际复制在后台,但等待数据在前台。谢谢,探险家。任何相当大的文件都很慢,但现在它“有效”,这比我过去几周所能说的要多。

我确实尝试过传递我在内部用于传输的PipeStream类,但资源管理器对此并不满意:

  • 尽管这个类的 CanSeek 是假的,它还是会尝试寻找。
  • 它忽略了我在 FileGroupDescriptor 中发送的大小,只是立即下载流中的任何内容。

所以,我不确定理想的情况是否真的可行。不过,感谢您的所有帮助。我将赏金给 JPW,因为他的回复最终让我走上了正确的道路。

4

3 回答 3

3

我认为http://www.codeproject.com/KB/miscctrl/FileBrowser.aspx上的C# 文件浏览器是现在最能帮助您的

这些文章是无价的。

Edanmo.ShellExtensions 是绝对必须的。http://www.mvps.org/emorcillo/en/code/shell/shellextensions.shtml

请注意,其中一些 COM 接口已在 .NET 2.0 中定义。(我没有检查 4.0,但我怀疑 Microsoft 是否添加了对 Shell/COM 接口的任何额外支持。)

额外的东西

找到了!

编写命名空间扩展的完整白痴指南 - 第一部分位于http://www.codeproject.com/kb/shell/namespcextguide1.aspx。是你要找的吗?

于 2010-06-02T23:15:39.117 回答
2

免责声明:我既不是 Windows Shell 编程方面的专家,也不是 COM 编程方面的专家,尤其是使用 .NET 进行 COM 编程方面的专家。

免责声明 2:Shell 编程相当复杂,Windows Explorer 可能会崩溃。(请务必阅读 MSDN 上有关调试 shell 扩展的信息。)

这是我可以提供来回答您的问题:

  1. SHITEMID 的 abID 值由包含相应项目的文件夹决定。因此,没有有效或无效的信息,因为此数据仅对文件夹有意义。Windows 资源管理器将传递此数据以识别特定项目。abID 不能是系统唯一的,但它可能在其包含的文件夹中是唯一的(尽管这不能保证)。在某些情况下,SHITEMID 可能会被保留,因此在某些情况下,它必须在重新启动后才有效(因为应避免在 abID 中引用此内存)。
  2. 据我了解,只有在需要实际数据时才会调用 IDataObject::GetData(我可能对此有误)。所以应该没问题,如果您将数据提取到 GetData 中的临时文件并将 PIDL 返回到该文件(请参阅http://support.microsoft.com/kb/132750/en-us,尽管我记得有一个由shall提供的方便的方法,但我不记得它的名字了)。不幸的是,我看不到何时删除临时文件的好方法(作为最后的手段,您可以在 IDataObject 被销毁时执行此操作,但这将导致可能不再需要的临时文件)。
  3. 您可能需要支持自定义 PIDL(包括自定义 PIDL 管理器)并实现自定义 IShellFolder。然而,大多数关于 shell 扩展的文档都是针对 C++ 的,并且许多函数的文档没有很好或根本没有文档。有关 PIDL 的更多信息,我建议阅读http://msdn.microsoft.com/en-us/library/cc144090.aspx。此外,您应该在 Internet 上搜索“Shell 命名空间扩展”,因为可能有一些关于该主题的信息。还可以查看 Windows SDK 提供的关于此主题的示例。

我希望一些信息对你有用。

编辑:您还可以适当地实现 QueryGetData 和 EnumerableFormatEtc 以表明您的对象不支持相关格式。也许 Windows 资源管理器会尝试不同的格式。

编辑 2:虽然您已经确定了一个解决方案,但这里有一些关于如何异步拖放(对于大文件)的更多信息,也许是您(或者至少有人正在寻找一个类似问题的答案,谁读这)觉得它很有用:http: //msdn.microsoft.com/en-us/library/bb776904 (VS.85).aspx#async

于 2010-06-01T19:33:04.593 回答
0

你看过这篇文章吗?如何将虚拟文件从您的应用程序拖到 Windows 资源管理器中 源代码是 c++,但它应该可以帮助您了解所有东西是如何工作的。

于 2010-06-03T08:25:54.843 回答