How to create a "Shell IDList Array" to support drag-and-drop of virtual files from C# to Windows Explorer?

Jus*_*ill 6 c# com wpf drag-and-drop windows-explorer

I started trying to implement drag-and-drop of virtual files (from a C# 4/WPF app) with this codeproject tutorial. After spending some time trying to figure out a DV_E_FORMATETC error, I figured out I need to support the "Shell IDList Array" data format. But there seems to be next to zero documentation on what this format actually does.

After some searching, I found this page on advanced data transfer which said that a Shell IDList Array was a pointer to a CIDA structure. This CIDA structure then contains the number of PIDLs, and a list of offsets to them. So what the hell is a PIDL? After some more searching, this page sort of implies it's a pointer to an ITEMIDLIST, which itself contains a single member that is a list of SHITEMIDs.

I did some more reading, I still can't tell what multiple PIDLs are for, but there's one SHITEMID for each "level" in the path. At least that's one mystery solved.

My next idea was to try dragging a file from another application with virtual files (WinSCP). I just got a MemoryStream back for this format. At least I know what class to provide for the thing, but that doesn't help at all for explaining what to put in it. I tried examining this MemoryStream based on the formats in the links above, but I've had no success. I just got back garbage data, and one of the 'cb' fields told me it was 18000 bytes long when the whole stream was only 539 bytes.

In addition, upon further reading, this page seems to imply that the data contained in a PIDL actually winds up being a path, and examining the contents of said MemoryStream in a hex editor yielded a path inside my local Temp directory (split into parts, anyway).

It seems that WinSCP just uses a shell extension to handle dropping on explorer, something I really don't want to resort to. However, it has an alternate mode where it aborts the dragdrop until after it transfers to a temp folder - this is acceptable to me, but I haven't the faintest idea how to do it.

My questions are now:

  1. What is a valid "abID" member for a SHITEMID? These virtual files only exist with my program; will the thing they are dragged to pass the "abID" back later when it executes GetData? Do they have to be system-unique?
  2. How can I manage the abort-and-redo-later drag and drop thing that WinSCP does?
  3. If I have to implement a shell extension for this, how would I even go about that? I'm sure I can easily find explanations of shell extension theory but how would I support custom PIDLs or whatever?

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

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

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

我尝试传递我在内部使用的PipeStream类进行传输,但是explorer对此不满意:

  • 它试图寻求,尽管这个类有CanSeek是假的.
  • 它忽略了我在FileGroupDescriptor,只是下载任何数据流中的发送大小现在.

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

JPW*_*JPW 2

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

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

我可以提供以下内容来回答您的问题:

  1. SHITEMID 的 abID 值由包含相应项目的文件夹确定。因此,不存在有效或无效的信息,因为该数据仅对文件夹有意义。Windows 资源管理器将传递此数据以便识别特定项目。abID 不能是系统唯一的,但它在其包含的文件夹中可能是唯一的(尽管不能保证这一点)。在某些情况下,SHITEMID 可能会被保留,因此在某些情况下,它必须在重新启动后有效(因为应避免 abID 中的内存引用)。
  2. 据我了解,只有在需要实际数据时才会调用 IDataObject::GetData (我可能是错的)。因此,如果您将数据提取到 GetData 中的临时文件并将 PIDL 返回到该文件(请参阅http://support.microsoft.com/kb/132750/en-us,尽管我记得有应该提供一个方便的方法,但我不记得它的名字)。不幸的是,我看不到何时删除临时文件的好方法(作为最后的手段,您可以在 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