我可以在 windows 便携式设备 (WPD) api 中使用 Shell 对象解析名称的一部分来获取文件流吗?
Can I use part of a Shell Object parsing name in the windows portable device (WPD) api to get a file stream?
使用来自 windows api 代码包 ShellObject 解析名称的最后一个 guid 的第一部分是否始终有效,表示 USB 连接的路径 android 或 iphone 设备将文件传输到 windows 便携式设备 (WPD) 中的本地存储 api?
例如。来自 ShellObject 的解析名称的示例获取解析名称调用:
::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\?\usb#vid_22b8&pid_2e82#zy322kldjb#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\{00000009-0001-0001-0000-000000000000}\{00000009-0001-0001-0000-000000000000}\{00005461-0001-0001-0000-000000000000}
据我所知,这代表:
- My Computer ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\
- USB device \?\usb#vid_22b8&pid_2e82#zy322kldjb#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\
- Root folder SID-{10001,,26401026048}\
- Folder 1 {00000009-0001-0001-0000-000000000000}\
- Folder 2 {00000075-0001-0001-0000-000000000000}\
- File {00005461-0001-0001-0000-000000000000}
使用 WPD api 在设备上枚举 Folder 2
的内容,我可以看到同一个文件的文件 ID 类似于 o5461
- 这看起来像是 File
以上部分。
这个假设是否总是正确的 - 我可以像下面的代码一样使用它,将一个文件从 android phone 复制到 c 盘上的本地存储吗?或者有时会出现不匹配?另外,文件ID中的"o"是什么意思?
这似乎可行,但我犹豫要不要在生产就绪代码中使用它。
using System.IO;
using PortableDeviceApiLib;
public class Copier
{
public void PerformCopy()
{
var deviceId = @"\?\usb#vid_22b8&pid_2e82#zy322kldjb#{6ac27878-a6fa-4155-ba85-f98f491d4f33}";
var sourceItemGuidString = "{00005461-0001-0001-0000-000000000000}";
var destinationPath = @"C:\Test\";
var fileName = "Testing.jpg";
var size = 3738545;
// get "o5461" from the parsing path from the Shell libraries
var fileId = "o" + sourceItemGuidString.Replace("{", string.Empty).Replace("}", string.Empty).Split('-')[0].TrimStart('0');
this.TransferContentFromDevice(deviceId, fileId, size, destinationPath, fileName);
}
private void TransferContentFromDevice(string deviceId, string fileId, long length, string saveToPath, string fileName)
{
PortableDeviceClass device;
try
{
device = SomehowGetOnePortableDeviceAndConnectToIt(deviceId);
// Make sure that the target dir exists.
Directory.CreateDirectory(saveToPath);
device.Content(out var content);
content.Transfer(out var resources);
var property = new _tagpropertykey
{
fmtid = new Guid(0xE81E79BE, 0x34F0, 0x41BF, 0xB5, 0x3F, 0xF1, 0xA0, 0x6A, 0xE8, 0x78, 0x42),
pid = 0
};
uint optimalTransferSize = 0;
resources.GetStream(fileId, ref property, 0, ref optimalTransferSize, out IStream wpdStream);
var sourceStream = (System.Runtime.InteropServices.ComTypes.IStream)wpdStream;
using (var targetStream = new FileStream(Path.Combine(saveToPath, fileName), FileMode.Create, FileAccess.Write))
{
// Get the total size.
long written = 0;
long lPCt = 0;
unsafe
{
var buffer = new byte[1024];
int bytesRead;
do
{
sourceStream.Read(buffer, 1024, new IntPtr(&bytesRead));
targetStream.Write(buffer, 0, bytesRead);
written += 1024;
long PCt = length > 0 ? (100 * written) / length : 100;
if (PCt != lPCt)
{
lPCt = PCt;
Console.WriteLine("Progress: " + lPCt);
}
} while (bytesRead > 0);
}
}
}
finally
{
Disconnect(device);
}
}
}
如果 item
具有如下所示的解析名称,我在最终 guid 的 5461
部分之后:
::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\?\usb#vid_22b8&pid_2e82#zy322kldjb#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,,26401026048}\{00000009-0001-0001-0000-000000000000}\{00000075-0001-0001-0000-000000000000}\{00005461-0001-0001-0000-000000000000}
我们可以使用以下代码从 ShellObject
中获取 WPD_OBJECT_ID
属性。有关此属性和相关属性的更多信息 here:
string GetFileId(ShellObject item)
{
const int WPD_OBJECT_ID = 2;
var property = item.Properties.GetProperty(new PropertyKey(new Guid("{ef6b490d-5cd8-437a-affc-da8b60ee4a3c}"), WPD_OBJECT_ID));
return property.ValueAsObject as string;
}
这个 returns 文件 ID o5641
,然后可以直接在我的 TransferContentFromDevice
方法中使用。
感谢@SimonMourier 为我指明了正确的方向。
使用来自 windows api 代码包 ShellObject 解析名称的最后一个 guid 的第一部分是否始终有效,表示 USB 连接的路径 android 或 iphone 设备将文件传输到 windows 便携式设备 (WPD) 中的本地存储 api?
例如。来自 ShellObject 的解析名称的示例获取解析名称调用:
::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\?\usb#vid_22b8&pid_2e82#zy322kldjb#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\{00000009-0001-0001-0000-000000000000}\{00000009-0001-0001-0000-000000000000}\{00005461-0001-0001-0000-000000000000}
据我所知,这代表:
- My Computer ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\
- USB device \?\usb#vid_22b8&pid_2e82#zy322kldjb#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\
- Root folder SID-{10001,,26401026048}\
- Folder 1 {00000009-0001-0001-0000-000000000000}\
- Folder 2 {00000075-0001-0001-0000-000000000000}\
- File {00005461-0001-0001-0000-000000000000}
使用 WPD api 在设备上枚举 Folder 2
的内容,我可以看到同一个文件的文件 ID 类似于 o5461
- 这看起来像是 File
以上部分。
这个假设是否总是正确的 - 我可以像下面的代码一样使用它,将一个文件从 android phone 复制到 c 盘上的本地存储吗?或者有时会出现不匹配?另外,文件ID中的"o"是什么意思?
这似乎可行,但我犹豫要不要在生产就绪代码中使用它。
using System.IO;
using PortableDeviceApiLib;
public class Copier
{
public void PerformCopy()
{
var deviceId = @"\?\usb#vid_22b8&pid_2e82#zy322kldjb#{6ac27878-a6fa-4155-ba85-f98f491d4f33}";
var sourceItemGuidString = "{00005461-0001-0001-0000-000000000000}";
var destinationPath = @"C:\Test\";
var fileName = "Testing.jpg";
var size = 3738545;
// get "o5461" from the parsing path from the Shell libraries
var fileId = "o" + sourceItemGuidString.Replace("{", string.Empty).Replace("}", string.Empty).Split('-')[0].TrimStart('0');
this.TransferContentFromDevice(deviceId, fileId, size, destinationPath, fileName);
}
private void TransferContentFromDevice(string deviceId, string fileId, long length, string saveToPath, string fileName)
{
PortableDeviceClass device;
try
{
device = SomehowGetOnePortableDeviceAndConnectToIt(deviceId);
// Make sure that the target dir exists.
Directory.CreateDirectory(saveToPath);
device.Content(out var content);
content.Transfer(out var resources);
var property = new _tagpropertykey
{
fmtid = new Guid(0xE81E79BE, 0x34F0, 0x41BF, 0xB5, 0x3F, 0xF1, 0xA0, 0x6A, 0xE8, 0x78, 0x42),
pid = 0
};
uint optimalTransferSize = 0;
resources.GetStream(fileId, ref property, 0, ref optimalTransferSize, out IStream wpdStream);
var sourceStream = (System.Runtime.InteropServices.ComTypes.IStream)wpdStream;
using (var targetStream = new FileStream(Path.Combine(saveToPath, fileName), FileMode.Create, FileAccess.Write))
{
// Get the total size.
long written = 0;
long lPCt = 0;
unsafe
{
var buffer = new byte[1024];
int bytesRead;
do
{
sourceStream.Read(buffer, 1024, new IntPtr(&bytesRead));
targetStream.Write(buffer, 0, bytesRead);
written += 1024;
long PCt = length > 0 ? (100 * written) / length : 100;
if (PCt != lPCt)
{
lPCt = PCt;
Console.WriteLine("Progress: " + lPCt);
}
} while (bytesRead > 0);
}
}
}
finally
{
Disconnect(device);
}
}
}
如果 item
具有如下所示的解析名称,我在最终 guid 的 5461
部分之后:
::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\?\usb#vid_22b8&pid_2e82#zy322kldjb#{6ac27878-a6fa-4155-ba85-f98f491d4f33}\SID-{10001,,26401026048}\{00000009-0001-0001-0000-000000000000}\{00000075-0001-0001-0000-000000000000}\{00005461-0001-0001-0000-000000000000}
我们可以使用以下代码从 ShellObject
中获取 WPD_OBJECT_ID
属性。有关此属性和相关属性的更多信息 here:
string GetFileId(ShellObject item)
{
const int WPD_OBJECT_ID = 2;
var property = item.Properties.GetProperty(new PropertyKey(new Guid("{ef6b490d-5cd8-437a-affc-da8b60ee4a3c}"), WPD_OBJECT_ID));
return property.ValueAsObject as string;
}
这个 returns 文件 ID o5641
,然后可以直接在我的 TransferContentFromDevice
方法中使用。
感谢@SimonMourier 为我指明了正确的方向。