2

I have an application that allows users to drag and drop files or entire folders into a special "drop area," at which point all files are processed. The application is being developed using WPF, and this particular XAML view sets "AllowDrop" to true and handles the Drop event in code-behind.

Everything is working for normal files and standrard Windows folders. However, if the user drops a special Windows folder (e.g., Pictures, Videos), then the functionality does not work. It would appear this is because the contents of DragEventArgs.Data are not a DataFormats.FileDrop enum. That's not the case with other folders or files.

My code for handling the drop, in part, is:

private void OnDrop(object Sender, DragEventArgs E)
{
    if (E.Data.GetDataPresent(DataFormats.FileDrop))
    {
        var _droppedFilePaths = E.Data.GetData(DataFormats.FileDrop, true) as string[];

        // Process the files....
    }
}

Is there any way to identify that the drop data contains the Windows 7 pictures library and map back to its actual path?

H.B.
  • 166,899
  • 29
  • 327
  • 400
jeffreystrauss
  • 187
  • 1
  • 2
  • 10
  • 1
    [This page](http://groups.google.com/group/microsoft.public.platformsdk.shell/browse_thread/thread/fdeda20d6841f433?pli=1) seems to have an answer by Jim Barry. It doesn't look fun. – Tim Rogers Nov 14 '11 at 17:35

1 Answers1

0

Using the solution described here, I wrote the following method:

const string ShellIdListArrayName = "Shell IDList Array";

static IEnumerable<string> GetPathsFromShellIDListArray(IDataObject data)
{
    if (data.GetDataPresent(ShellIdListArrayName))
    {
        var ms = (MemoryStream)data.GetData(ShellIdListArrayName);
        byte[] bytes = ms.ToArray();

        IntPtr p = Marshal.AllocHGlobal(bytes.Length);
        Marshal.Copy(bytes, 0, p, bytes.Length);
        uint cidl = (uint)Marshal.ReadInt32(p, 0);

        int offset = sizeof(uint);
        IntPtr parentpidl = (IntPtr)((int)p + (uint)Marshal.ReadInt32(p, offset));
        StringBuilder path = new StringBuilder(256);
        SHGetPathFromIDList(parentpidl, path);

        for (int i = 1; i <= cidl; ++i)
        {
            offset += sizeof(uint);
            IntPtr relpidl = (IntPtr)((int)p + (uint)Marshal.ReadInt32(p, offset));
            IntPtr abspidl = ILCombine(parentpidl, relpidl);
            if (SHGetPathFromIDList(abspidl, path) != 0)
            {
                yield return path.ToString();
            }
            ILFree(abspidl);
        }
    }
}

[DllImport("shell32.dll")]
public static extern int SHGetPathFromIDList(IntPtr pidl, StringBuilder pszPath); 

[DllImport("shell32.dll")]
public static extern IntPtr ILCombine(IntPtr pidl1, IntPtr pidl2);

[DllImport("shell32.dll")]
public static extern void ILFree(IntPtr pidl);

You can just pass e.Data from your event handler to this method, and you will get a sequence of paths (assuming the items do have a path of course... for instance, "My computer" doesn't have a path)

Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758