c# - 在 Windows 资源管理器中将文件从(例如)iPhone 拖放到 WPF 应用程序中

标签 c# iphone wpf drag-and-drop usb

我有一个 C# WPF 应用程序,它允许用户通过将文件从 Windows 资源管理器拖放到主应用程序窗口来导入文件。

从物理磁盘拖动文件时它工作正常,但是当从连接的设备(如 iPhone 或通过 USB 连接的相机)拖动文件时,我无法识别 dragEventArgs.Data.GetFormats() 返回的任何数据格式窗口的 Drop 处理程序。

有人愿意分享一些技巧或给我指出一个很好的例子或演练如何以这种方式在 C#/.NET 中从“虚拟”文件系统读取/导入文件吗?

谢谢,

迪伦

最佳答案

获取文件名

获取文件名很容易。只需调用:

dragEventArgs.Data.GetData("FileGroupDescriptorW")

这将返回一个包含 FILEGROUPDESCRIPTORA 结构的 MemoryStream。这可以被解析以获取文件名。 Herehere是指向 CodeProject 上的项目的链接,这些项目向您展示了在 C# 中解析 FILEGROUPDESCRIPTORA 的两种不同方法,因此我不会在这里详细介绍。我可能会使用第一个项目中描述的技术。

获取实际数据

要获取实际数据,您可以使用FileContents 格式。不幸的是,您要么必须使用反射来访问私有(private)方法,要么自己编写一些 COM 互操作。问题在于,要获取数据,您必须使用 FORMATETC 结构调用 System.Runtime.InteropServices.ComTypes.IDataObject 接口(interface),该结构的 lindex 设置为项目索引。不幸的是,System.Windows.DataObject 的实现总是使用 lindex=-1 调用它。

最简单的解决方案可能是使用反射来调用 WPF 的 DataObject 的私有(private)成员。但是请注意,这可能会破坏您在未来 NET Framework 版本中的代码。如果这完全不能接受,您的另一个选择是调用 ole32.dll 中的 RegisterDragDrop 函数来注册自定义 IOleDropTarget,然后直接与传入的 COM IDataObject。这不是很难,但反射解决方案要容易得多,并且可能适用于许多版本的 NET Framework,因此这是我将重点关注的。

以下是检索特定索引的 FileContent 的方法:

  1. 反射(reflection)数据对象的实际类,找到一个名为“GetData”的方法,该方法接受四个参数
  2. 如果没有找到该方法,则再次反射找到System.Windows.IDataObject类型的字段,获取其值,并返回步骤1(这里递归是安全的)
  3. 使用 MethodInfo.Invoke 调用您找到的带有参数的“GetData”:“FileContents”、false、ComTypes.DVASPECT、lindex
  4. 从返回的MemoryStream中读取文件数据

以下是检索给定索引的文件内容的代码要点:

public MemoryStream GetFileContents(IDataObject dataObject, int index)
{
  MethodInfo getData = (
    from method in dataObject.GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
    where method.Name=="GetData" && method.GetParameters().Length==4
    select method
  ).FirstOrDefault();

  if(getData==null)
  {
    FieldInfo innerField = (
      from field in dataObject.GetType().GetFields()
      where field.FieldType == typeof(IDataObject)
      select field
    ).FirstOrDefault();
    if(innerField==null) throw new Exception("Cannot get FileContents from DataObject of type" + dataObject.GetType());
    return GetFileContents((IDataObject)innerField.GetValue(dataObject), index);
  }

  return (MemoryStream)getData.Invoke(dataObject, new object[]
  {
    "FileContents", false,
    System.Runtime.InteropServices.ComTypes.DVASPECT.DVASPECT_CONTENT,
    index
  });
}

关于c# - 在 Windows 资源管理器中将文件从(例如)iPhone 拖放到 WPF 应用程序中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2052916/

相关文章:

iphone - iOS 一次触发电子邮件和短信

c# - 从 WPF 保存到 SQL Server 数据库

c# - 绑定(bind)到属性不起作用

c# - 具有异步套接字的C#游戏客户端

c# - 发生类型为 'System.StackOverflowException' 的未处理异常

c# - 带有制表符自动完成的用户输入文件路径

iphone - UIAlertView 不显示键盘

iphone - 检测用户的旋转运动

WPF 绑定(bind) IsSelected 到 ViewModel 不会设置列表中未显示的项目

c# - OutOfMemory Exception C# 使用线程时