I started trying to implement drag-and-drop virtual files (from a C # 4 / WPF application) with this coding tutorial . After spending some time trying to figure out the DV_E_FORMATETC error , I realized that I needed to support the Shell IDList Array data format. But it seems next to the null documentation about what this format actually does.
After some searching, I found this page in advanced data transfer , which stated that the IDList array of the shell was a pointer to the CIDA Structure . This CIDA structure then contains the number of PIDLs and a list of offsets. So what the hell is this PIDL? After some searching, this page , this means that it is a pointer to ITEMIDLIST , which itself contains one element, which is a SHITEMID list.
I read a little more, I still can’t say what several PIDLs are for, but there is one SHITEMID for each "level" in the path. At least this riddle is solved.
My next idea was to try and drag a file from another application using virtual files (WinSCP). I just got a MemoryStream for this format. At least I know what class a thing should provide, but that doesn't help at all to explain what to put in it. I tried to learn this MemoryStream based on the formats in the links above, but I was not successful. I just returned the garbage data, and one of the “cb” fields informed me that it was 18000 bytes, when the whole stream was only 539 bytes.
In addition, upon further reading, this page apparently implies that the data contained in the PIDL actually ends up being a path, and looking at the contents of the mentioned MemoryStream in a hex editor gave the path inside my local Temp directory (in any case broken into parts).
It seems that WinSCP just uses a shell extension to handle dropping on explorer, which I really don't want to resort to. However, it has an alternative mode in which it interrupts dragdrop until it moves to a temporary folder - this is acceptable to me, but I have no idea how to do this.
Now my questions are:
- What is a valid "abID" member for SHITEMID? These virtual files exist only with my program; Will they be dragged to pass the "abID" later when it executes GetData? Should they be unique in the system?
- How can I control the drag and drop tags that WinCCP does?
- If I need to implement a shell extension for this, how would I even think about it? I'm sure I can easily find explanations for shell extension theory, but how can I support custom PIDL or something else?
Any help or even links explaining what I should do would be greatly appreciated.
Edit: So, as I actually did at the end:
I canceled most of the code from the CodeProject tutorial above, retaining the functions for creating the FileGroupDescriptor. Then I redefined the .Net IDataObject interface (and in general, I did not have to use the IDataObject COM interface at all). Then I have to synchronously download the file in the background and pass the MemoryStream from GetData (). Conveniently, the actual copy is in the background, but waiting for data is in the foreground. Thanks, researcher. Any reasonably large files are slow, but so far this is "working", which is more than I can say in the last few weeks.
I tried passing the PipeStream class, which I use for internal operations, but the researcher does not like this:
- It tries to search even though this class has CanSeek as false.
- It ignores the size that I send to FileGroupDescriptor, and just upload everything in the stream right now.
So, I'm not sure that the perfect case is really possible. However, thanks for your help. I give generosity to JPW because his answers ultimately put me on the right track.