从另一个应用程序中拖放C#Windows窗体应用程序

时间:2018-08-03 19:54:13

标签: c# uwp drag-and-drop

我正在尝试从另一个Windows应用程序(EM Client,Thunderbird或Outlook)拖到我的表单上。将电子邮件从其他应用程序拖到Windows浏览时,它将作为文件删除。如果用户拖动到我的应用程序上,我希望将文件内容作为文件流获取。

我能够在UWP应用程序中使用它,但是我需要在Windows Form应用程序中使用它,以便它可以在Windows 7中使用。

我发现了很多使用其他方法的示例(从App拖动到Windows)。

在UWP应用程序中,这很烦人。 这是我在UWP应用程序中执行的操作,其结果是我将一个新文件保存在漫游文件夹中,名称为“ 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);


                }
            }
        }
    }

}

我已经阅读了此答案中列出的每篇文章,以及更多内容: Trying to implement Drag and Drop gmail attachment from chrome

基本上,无论我如何进行攻击,最终我都会得到以下3个结果之一:

  1. “无效的FORMATETC结构(来自HRESULT的异常:0x80040064(DV_E_FORMATETC))”的异常
  2. 我的MemoryStream为空
  3. 我遇到安全违规

这是违反安全性的代码:

 MemoryStream ClipboardMemoryStream = new MemoryStream();

 BinaryFormatter bft = new BinaryFormatter();

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

 byte[] byteArray = ClipboardMemoryStream.ToArray();

我的猜测是我需要实现e.Data.GetData(“ FileGroupDesciptorW”)返回一个IStorage类,并且我需要实现该类,但是我对如何做到这一点迷失了,而且我不是确定是这样

e.Data.GetType显示它的marshalbyrefobject,我尝试手动执行Remoting,但是我陷入了没有开放频道的困境。

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

1 个答案:

答案 0 :(得分:0)

因此,在寻求专业人士的帮助后,我有了一个可行的例子。诀窍是让“ FileDescriptorW”在自定义ComObject类中工作。您可以在从Outlook example拖动中找到该类的版本,但是从EM Client拖动时它不起作用。

代码如下:  Code is too Big to post

然后您可以像这样使用它:

        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++;
        }