使用 .NET 4.5 或更高版本从 Outlook 中进行 C# 拖放

LMS*_*LMS 3 .net c# outlook drag-and-drop winforms

有人有任何 C# 代码可以接受从 Outlook 拖放到在.Net Framework 4.5或更高版本下工作的 Winforms 应用程序吗?

我有一些代码已经使用了大约 12 年,其中包括拖放项目的功能,包括来自 Outlook 的电子邮件。

当将目标框架设置为.Net Framework 4进行编译时,代码可以完美运行,但是我一直在开发的一些新功能需要.Net Framework 4.5或更高版本。但是,这会阻止从 Outlook 进行拖放操作。

代码非常复杂,它做了很多与问题无关的事情来确定文件的去向,以及它为谁显示等,所以我不会包括所有这些,但它中断的点很好并且简单的...

public string ImportEmail(DragEventArgs e)
    {
        string strResult = string.Empty;
        var dataObject = new OutlookDataObject(e.Data);
        var filenames = (string[]) dataObject.GetData("FileGroupDescriptor");
Run Code Online (Sandbox Code Playgroud)

.NET 4下,上面的最后一行按预期返回文件名。

.NET 4.5 或更高版本中,上面的最后一行返回null

我在.NET 4.5、4.5.1、4.5.2、4.6、4.6.1、4.6.2和4.7.2(我安装的所有版本)下测试了它,它不适用于其中任何一个。

我已经花了几天时间尝试所有我能找到的拖放代码,但似乎都无法在 .Net 4.5 或更高版本下工作。

下面是我所做的测试表单的完整代码,使用了我从这里和其他地方挖掘的代码。无论您从 Outlook 拖放文件还是电子邮件,此代码都可以在 .Net Framework 4 下完美运行,但在 .Net Framework 4.5 或更高版本下都不起作用(再次测试所有相同版本)。

using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using System.Reflection;
using System.Windows.Forms;

namespace OutlookDragNDropTest
{
    public partial class OutlookDragNDropTest : Form
    {
        public OutlookDragNDropTest()
        {
            InitializeComponent();
        }

        private void Form1_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effect = DragDropEffects.Copy;
            }
            //    or this tells us if it is an Outlook attachment drop
            else if (e.Data.GetDataPresent("FileGroupDescriptor"))
            {
                e.Effect = DragDropEffects.Copy;
            }
            //    or none of the above
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void Form1_DragDrop(object sender, DragEventArgs e)
        {
            try
            {
                //wrap standard IDataObject in OutlookDataObject
                OutlookDataObject dataObject = new OutlookDataObject(e.Data);

                //get the names and data streams of the files dropped
                string[] filenames = (string[])dataObject.GetData("FileGroupDescriptor");
                MemoryStream[] filestreams = (MemoryStream[])dataObject.GetData("FileContents");

                string tempPath = Path.GetTempPath();

                for (int fileIndex = 0; fileIndex < filenames.Length; fileIndex++)
                {
                    //use the fileindex to get the name and data stream
                    string filename = tempPath + filenames[fileIndex];
                    MemoryStream filestream = filestreams[fileIndex];

                    //save the file stream using its name to the application path
                    FileStream outputStream = File.Create(filename);
                    filestream.WriteTo(outputStream);
                    outputStream.Close();
                    MessageBox.Show("Output to " + filename);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error : " + ex.ToString());
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

(好吧,对于一篇文章来说代码似乎太长了,OutlookDataObject 类将在下面的回复中)...

唯一的另一件事是表单本身,它只是一个空白的 Winforms 表单,设置了以下属性:-

允许丢弃:真

DragEnter 事件:Form1_DragEnter

拖放事件:Form1_DragDrop

如果相关的话,我使用的是 Visual Studio 2017 Professional,并在 Windows 10 上运行,尽管运行 Windows 7 的客户端也报告了拖放不起作用。

LMS*_*LMS 6

解决了!

事实证明,问题是 .Net Framework 4 及更低版本使用32 位指针,而 .Net Framework 4.5 及更高版本使用64 位指针。

我拥有的古老代码和我提供的示例代码都是基于指针仅为 32 位的假设编写的。

更改OutlookDataObject类中的以下两行(并在我的代码中进行类似的更改)修复了它:-

从:-

IntPtr fileDescriptorPointer = (IntPtr)((int)fileGroupDescriptorAPointer + Marshal.SizeOf(fileGroupDescriptor.cItems));

fileDescriptorPointer = (IntPtr)((int)fileDescriptorPointer + Marshal.SizeOf(fileDescriptor));
Run Code Online (Sandbox Code Playgroud)

到:-

IntPtr fileDescriptorPointer = (IntPtr)((long)fileGroupDescriptorAPointer + Marshal.SizeOf(fileGroupDescriptor.cItems));

fileDescriptorPointer = (IntPtr)((long)fileDescriptorPointer + Marshal.SizeOf(fileDescriptor));
Run Code Online (Sandbox Code Playgroud)

不知道为什么我的 Visual Studio 在碰到这些线时没有发出晃动的声音,但是哦,好吧。

通过上述更改,我提供的示例代码可以同时处理文件和 Outlook 电子邮件(单个项目和多个项目)的拖放