Drag And Drop C# Windows Form Application From another Application

2

I am trying to drag from another windows application (EM Client, thunderbird or outlook) onto my form. When an email is dragged from the other application to windows explore it will drop as a file. If the user drags onto my application I would like to get the file contents as a file stream.

I was able to get this working with a UWP app, but I need to get it working in a Windows Form app so it will work in Windows 7.

I have found lots of examples of going the other way (dragging from App to windows).

The thing that makes this so annoying is it is easy in the UWP app. Here is how I did it in the UWP app, the results of which is I get a new file saved in the roaming folder at name "email.eml":

XAML

 <Grid AllowDrop="True" DragOver="Grid_DragOver" Drop="Grid_Drop"
      Background="LightBlue" Margin="10,10,10,353">
        <TextBlock>Drop anywhere in the blue area</TextBlock>
 </Grid>

XAML.CS

namespace App1
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }
        private void Grid_DragOver(object sender, DragEventArgs e)
        {
            e.AcceptedOperation = DataPackageOperation.Copy;
        }
        private async void Grid_Drop(object sender, DragEventArgs e)
        {
            if (e.DataView.Contains(StandardDataFormats.StorageItems))
            {
                var items = await e.DataView.GetStorageItemsAsync();
                if (items.Count > 0)
                {
                    var storageFile = items[0] as StorageFile;
                    var reader = (await storageFile.OpenAsync(FileAccessMode.Read));
                    IBuffer result = new byte[reader.Size].AsBuffer();
                    var test = await reader.ReadAsync(result, result.Length,Windows.Storage.Streams.InputStreamOptions.None);
                    Windows.Storage.StorageFolder storageFolder =
                    Windows.Storage.ApplicationData.Current.LocalFolder;
                    Windows.Storage.StorageFile sampleFile = await storageFolder.CreateFileAsync("email.eml",Windows.Storage.CreationCollisionOption.ReplaceExisting);

                    await Windows.Storage.FileIO.WriteBufferAsync(sampleFile, test);


                }
            }
        }
    }

}

I have read every article that that is listed on this answer, plus more: Trying to implement Drag and Drop gmail attachment from chrome

Basically no matter how I attack it I end up with one of 3 results:

  1. a exception for "Invalid FORMATETC structure (Exception from HRESULT: 0x80040064(DV_E_FORMATETC))"
  2. my MemoryStream is null
  3. I get a security violation

This is the Code that gets a security violation:

 MemoryStream ClipboardMemoryStream = new MemoryStream();

 BinaryFormatter bft = new BinaryFormatter();

 bft.Serialize(ClipboardMemoryStream, e.Data.GetData("FileGroupDescriptorW", false));

 byte[] byteArray = ClipboardMemoryStream.ToArray();

My guess is that I need to implement the e.Data.GetData("FileGroupDesciptorW") is returning a IStorage Class, and I need to implement that class, but I am loss on how to do it, plus I am not sure that is the case

e.Data.GetType shows its a marshalbyrefobject, I have attempted to do the Remoting manually, but I got stuck on not having an open channel.

https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nn-objidl-istorage https://docs.microsoft.com/en-us/windows/desktop/shell/datascenarios#dragging-and-dropping-shell-objects-asynchronously

c#
uwp
drag-and-drop
asked on Stack Overflow Aug 3, 2018 by BigShedBuilder • edited Aug 13, 2018 by BigShedBuilder

1 Answer

0

So After reaching out to a professional for help I have a working example. The trick was to get "FileDescriptorW" working in the Custom ComObject class. You will find a version of this class in the Drag from Outlook example but it does not work when dragging from EM Client, this does.

Here is the Code: Code is too Big to post

Then You can use it like this:

        MyDataObject obj = new MyDataObject(e.Data);
        string[] fileNames = { };
        //ThunderBird Does a FileDrop
        if (obj.GetDataPresent(DataFormats.FileDrop, true))
        {
            string[] tempFileNames = (string[])obj.GetData(DataFormats.FileDrop);
            List<string> tempFileNameList = new List<string>();
            foreach(string f in tempFileNames)
            {
                tempFileNameList.Add(Path.GetFileName(f));
            }
            fileNames = tempFileNameList.ToArray();

        } else if (fileNames.Length == 0)
        {
            //EM Client uses "FileGroupDescriptorW"
            fileNames = (string[])obj.GetData("FileGroupDescriptorW");
        }else if (fileNames.Length == 0)
        {  
                //Outlook Uses "FileGroupDescriptor"
                fileNames = (string[])obj.GetData("FileGroupDescriptor");
        }


        int index = 0;
        foreach (string f in fileNames)
        {
            File.WriteAllBytes("C:\\FilePath\\"+f, obj.GetData("FileContents", index).ToArray());

            index++;
        } 
answered on Stack Overflow Aug 13, 2018 by BigShedBuilder • edited Aug 13, 2018 by BigShedBuilder

User contributions licensed under CC BY-SA 3.0