Как я могу скопировать файлы из USB-хранилища на локальный диск, используя windows API codepack или com inter? - PullRequest
0 голосов
/ 18 февраля 2020

Я использую кодовый пакет API windows для создания диалогового окна выбора файлов, которое позволяет выбирать несколько файлов из виртуальных файловых систем - например, с подключенных по USB устройств android.

Я могу получить список файлов, который я использую после элемента управления ExplorerBrowser, который возвращает список ShellObject, но теперь я хочу получить доступ либо к байту файла, либо к потоку.

Моя конечная цель - выгрузить файлы в HTTP API, и я сначала подумал о том, чтобы передавать их напрямую из источника, но теперь я подозреваю, что лучшей стратегией будет копирование их во временное хранилище на локальном диске и потоковая передача оттуда (удаление передачи через USB как узкое место).

Я пытался выяснить, как копировать или перемещать, используя кодовый пакет API, но я не смог найти подходящую функцию Copy или Move, и после большого количества поисков, Я собрал код ниже, который разрешает доступ к потоку файла на локальном диске (например, имя синтаксического анализа начинается как C:\), но это не работает для файлов на моем android устройство (например, имя синтаксического анализа начинается как ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\\?\usb#vid_)

Используя приведенный ниже код, SHCreateItemFromParsingName не выполняется для элементов на USB-накопителе, возвращая значение -2147024809.

У меня вопрос, как копировать список известных файлов из usb-хранилища на локальный диск с использованием либо windows api codepack, либо COM-взаимодействия? Является ли код ниже хорошим способом сделать это, или есть лучший способ?

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;

[Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport]
public interface IShellItem
{
  void BindToHandler(IntPtr pbc,
    [MarshalAs(UnmanagedType.LPStruct)]Guid bhid,
    [MarshalAs(UnmanagedType.LPStruct)]Guid riid,
    out IntPtr ppv);
};

public static class FileOperations
{
  [DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
  internal static extern int SHCreateItemFromParsingName(
    [MarshalAs(UnmanagedType.LPWStr)] string path, 
    IntPtr pbc, ref Guid riid, 
    [MarshalAs(UnmanagedType.Interface)] out IShellItem shellItem);

  public static void DoStuff(string parsingName)
  {
    var bhidStream = new Guid("{1CEBB3AB-7C10-499a-A417-92CA16C4CB83}");

    var item = CreateIShellItem(parsingName);
    item.BindToHandler(IntPtr.Zero, bhidStream, typeof(IStream).GUID, out var pIStream);
    var stream = (IStream)Marshal.GetObjectForIUnknown(pIStream);

    // doing stuff with a stream here, eg. copy to temp storage or something...

    Marshal.ReleaseComObject(stream);
    Marshal.ReleaseComObject(item);
  }

  internal static IShellItem CreateIShellItem(string parsingName)
  {
    if (string.IsNullOrEmpty(parsingName))
    {
      throw new ArgumentNullException(nameof(parsingName));
    }

    var riid = new Guid("7E9FB0D3-919F-4307-AB2E-9B1860310C93"); //IShellItem2
    //var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); // IShellItem

    var itemFromParsingName = SHCreateItemFromParsingName(parsingName, IntPtr.Zero, ref riid, out var shellItem);
    if (itemFromParsingName >= 0)
    {
      return shellItem;
    }

    var exception = Marshal.GetExceptionForHR(itemFromParsingName);
    throw new ApplicationException("Unable to create item", exception);
  }
}
...