Перетащите файлы с (например) iPhone в проводнике Windows в приложение WPF - PullRequest
3 голосов
/ 13 января 2010

У меня есть приложение C # WPF, которое позволяет пользователям импортировать файлы, перетаскивая их из Windows Explorer и перетаскивая их в главное окно приложения.

Отлично работает при перетаскивании файлов с физических дисков, но при перетаскивании файлов с подключенного устройства, такого как iPhone или камера, подключенная через USB, я не распознаю ни один из форматов данных, возвращаемых dragEventArgs.Data.GetFormats () в обработчик Drop окна.

Кто-нибудь хочет поделиться некоторыми советами или указать мне хороший пример или пошаговое руководство о том, как таким образом читать / импортировать файлы из «виртуальной» файловой системы в C # /. NET?

Спасибо

Dylan

1 Ответ

5 голосов
/ 13 января 2010

Получение имен файлов

Получить имена файлов легко. Просто позвоните:

dragEventArgs.Data.GetData("FileGroupDescriptorW")

это вернет MemoryStream, который содержит FILEGROUPDESCRIPTORA структуру. Это может быть проанализировано, чтобы получить имена файлов. Здесь и здесь - это ссылки на проекты в CodeProject, которые показывают два различных способа анализа FILEGROUPDESCRIPTORA в C #, поэтому я не буду вдаваться в подробности. Я бы, вероятно, использовал технику, описанную в первом проекте.

Получение фактических данных

Чтобы получить фактические данные, вы используете формат FileContents. К сожалению, вы должны либо использовать отражение для доступа к закрытым методам, либо написать какое-нибудь COM-взаимодействие самостоятельно. Проблема заключается в том, что для получения данных необходимо вызвать интерфейс System.Runtime.InteropServices.ComTypes.IDataObject со структурой FORMATETC, для которой lindex установлен в индекс элемента. К сожалению, реализация System.Windows.DataObject всегда вызывает его с lindex = -1.

Самым простым решением, вероятно, является использование рефлексии для вызова частных членов WPF DataObject. Однако предупредите, что это может привести к поломке вашего кода в будущих версиях NET Framework. Если это совершенно неприемлемо, другой вариант - вызвать функцию RegisterDragDrop в ole32.dll, чтобы зарегистрировать пользовательский IOleDropTarget, а затем напрямую поговорить с COM IDataObject, который передается. Это не очень сложно, но решение для отражения намного проще и, вероятно, будет работать для многих версий NET Framework, поэтому на этом я остановлюсь.

Вот что нужно сделать, чтобы получить FileContent для определенного индекса:

  1. Отобразите фактический класс объекта данных, чтобы найти метод с именем "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
  });
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...