如何创建“Shell IDList Array”以支持将虚拟文件从C#拖放到Windows资源管理器?

时间:2010-05-29 22:56:48

标签: c# wpf com drag-and-drop windows-explorer

我开始尝试使用this codeproject tutorial实现虚拟文件(来自C#4 / WPF应用程序)的拖放。花了一些时间trying to figure out a DV_E_FORMATETC错误后,我发现我需要支持“Shell IDList Array”数据格式。但是关于这种格式实际上做了什么,似乎只有零文档。

经过一番搜索后,我发现this page on advanced data transfer表示Shell IDList Array是指向CIDA structure的指针。然后,此CIDA结构包含PIDL的数量以及它们的偏移列表。那究竟是什么PIDL?经过一些搜索后,this page表示它是指向ITEMIDLIST的指针,SHITEMID本身包含一个this page列表的成员。

我做了一些阅读,我仍然无法分辨多个PIDL是什么,但路径中的每个“级别”都有一个SHITEMID。至少这是一个谜团。

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

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

似乎WinSCP只使用shell扩展来处理在资源管理器上的丢弃,这是我真的不想诉诸的东西。但是,它有一个替代模式,它会中止dragdrop,直到它转移到临时文件夹 - 这对我来说是可以接受的,但我不知道如何做到这一点。

我现在的问题是:

  1. 什么是SHITEMID的有效“abID”成员?这些虚拟文件仅与我的程序一起存在;他们被拖动的东西会在以后执行GetData时传回“abID”吗?他们必须是系统独特的吗?
  2. 如何管理WinSCP执行的中止 - 重做 - 后续拖放操作?
  3. 如果我必须为此实现一个shell扩展,我怎么能这样做呢?我确信我可以轻松找到shell扩展理论的解释,但我如何支持自定义PIDL或其他什么?
  4. 任何帮助甚至可以解释我应该做什么的链接都将不胜感激。

    编辑:所以这就是我最终实际做到的方式:

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

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

    • 它试图寻求,尽管这堂课有CanSeek是假的。
    • 它忽略了我在FileGroupDescriptor中发送的大小,只是立即下载流中的任何内容

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

3 个答案:

答案 0 :(得分: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,但我怀疑微软是否添加了对Shell / COM接口的任何额外支持。)

额外的东西

发现它!

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

答案 1 :(得分:2)

免责声明:我既不是Windows Shell编程专家也不是COM编程专家,特别是使用.NET的COM编程专家。

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

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

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

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

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

答案 2 :(得分:0)

你看过这篇文章吗? How to drag a virtual file from your app into Windows Explorer源代码是用c ++编写的,但它可以帮助您了解所有内容的工作原理。