Я использую кодовый пакет 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);
}
}