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

我开始尝试使用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数组是指向CIDA structure的指针.这个CIDA结构然后包含PIDL的数量,以及它们的偏移列表.那究竟是什么PIDL?经过一些搜索后,this page意味着它是一个指向ITEMIDLIST的指针,它本身包含一个SHITEMID列表的成员.

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

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

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

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

我现在的问题是:

>什么是SHITEMID的有效“abID”成员?这些虚拟文件仅与我的程序一起存在;他们被拖动的东西会在以后执行GetData时传回“abID”吗?他们必须是系统独特的吗?
>我如何管理WinSCP执行的中止和重做后续拖放操作?
>如果我必须为此实现shell扩展,我怎么会这样做呢?我确信我可以轻松找到shell扩展理论的解释,但我如何支持自定义PIDL或其他什么?

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

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

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

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

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

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

最佳答案
免责声明:我既不是Windows Shell编程专家也不是COM编程专家,特别是在使用.NET的COM编程中.

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

这是我能回答你的问题:

> SHITEMID的abID值由包含相应项的文件夹确定.因此,没有有效或无效的信息,因为此数据仅对该文件夹有用. Windows资源管理器将传递此数据以标识特定项目. abID不能是系统唯一的,但它在包含文件夹中可能是唯一的(虽然这不能保证).在某些情况下,SHITEMID可能会被持久化,因此在某些情况下它必须在重新启动后有效(因为应该避免在abID中使用此内存引用).
>根据我的理解,只有在需要实际数据时才会调用IDataObject :: GetData(我可能错了).所以它应该没问题,如果你将数据提取到GetData中的临时文件并将PIDL返回到该文件(参见http://support.microsoft.com/kb/132750/en-us,虽然我记得有一个方便的方法,但是我不记得其名称).不幸的是,我无法看到何时删除临时文件的好方法(作为最后的手段,你可以在销毁IDataObject时执行此操作,但这将导致可能不再需要的临时文件).
>您可能需要支持自定义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

转载注明原文:如何创建“Shell IDList Array”以支持将虚拟文件从C#拖放到Windows资源管理器? - 代码日志