在上节内容(c#使用wpd读取便携式设备信息一)中,我们已经获取到了设备名称,容量等信息,本节进行读写设备的存储内容操作。WPD对设备的操作都是基于对象的ID的,例如文件夹和文件都有各自的objectId,首先获取到要进行操作的对象的objectId,然后再进行读写。
这里以我的小米note手机为例,要对Android目录下的文件进行读取
需要用到的方法如下:
/// <summary>
/// 获取设备ID
/// </summary>
/// <returns></returns>
public string GetDeviceId()
{
uint devicesCount = 1;
PortableDeviceManagerClass devMgr = new PortableDeviceManagerClass();
string deviceID = string.Empty;
//此处devicesCount为大于0的数,且只能获取一个便携式设备,如何获取多个设备会在之后的文章展现
devMgr.GetDevices(ref deviceID, ref devicesCount);
return deviceID;
}
/// <summary>
/// 获取设备信息
/// </summary>
/// <param name="deviceId"></param>
/// <returns></returns>
public IPortableDeviceContent GetDeviceContent(string deviceId)
{
IPortableDeviceValues clientInfo = (IPortableDeviceValues)new PortableDeviceTypesLib.PortableDeviceValuesClass();
PortableDeviceClass portableDevice = new PortableDeviceClass();
portableDevice.Open(deviceId, clientInfo);
IPortableDeviceContent content;
portableDevice.Content(out content);
return content;
}
/// <summary>
/// 获取设备或设备下文件夹的所有对象(文件、文件夹)的ObjectId
/// </summary>
/// <param name="deviceId"></param>
/// <param name="parentId"></param>
/// <returns></returns>
public List<string> GetChildrenObjectIds(IPortableDeviceContent content, string parentId)
{
IEnumPortableDeviceObjectIDs objectIds;
content.EnumObjects(0, parentId, null, out objectIds);
List<string> childItems = new List<string>();
uint fetched = 0;
do
{
string objectId;
objectIds.Next(1, out objectId, ref fetched);
// Check if anything was retrieved.
if (fetched > 0)
{
childItems.Add(objectId);
}
} while (fetched > 0);
return childItems;
}
/// <summary>
/// 获取名称属性
/// </summary>
/// <param name="deviceValues"></param>
/// <returns></returns>
public string GetNameProperty(IPortableDeviceValues deviceValues)
{
_tagpropertykey nameKey = new _tagpropertykey();
nameKey.fmtid= new Guid("EF6B490D-5CD8-437A-AFFC-DA8B60EE4A3C");//guid唯一值
nameKey.pid = 4;//索引
string nameProperty = null;
deviceValues.GetStringValue(ref nameKey, out nameProperty);
return nameProperty;
}
要将数据写入到设备中,首先需要创建符合要求的文件或文件夹
/// <summary>
/// 创建符合要求的文件
/// </summary>
/// <param name="sourcePath"></param>
/// <param name="parentId"></param>
/// <returns></returns>
private static IPortableDeviceValues GetRequiredPropertiesForContentType(string sourcePath,string parentId)
{
IPortableDeviceValues values = new PortableDeviceTypesLib.PortableDeviceValues() as IPortableDeviceValues;
_tagpropertykey WPD_OBJECT_PARENT_ID = new _tagpropertykey();
WPD_OBJECT_PARENT_ID.fmtid = new Guid(0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C);
WPD_OBJECT_PARENT_ID.pid = 3;
values.SetStringValue(ref WPD_OBJECT_PARENT_ID, parentId);
_tagpropertykey WPD_OBJECT_SIZE = new _tagpropertykey();
WPD_OBJECT_SIZE.fmtid = new Guid(0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C);
WPD_OBJECT_SIZE.pid = 11;
FileInfo fileInfo = new FileInfo(sourcePath);
values.SetUnsignedLargeIntegerValue(WPD_OBJECT_SIZE, (ulong)fileInfo.Length);
_tagpropertykey WPD_OBJECT_ORIGINAL_FILE_NAME = new _tagpropertykey();
WPD_OBJECT_ORIGINAL_FILE_NAME.fmtid = new Guid(0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C);
WPD_OBJECT_ORIGINAL_FILE_NAME.pid = 12;
values.SetStringValue(WPD_OBJECT_ORIGINAL_FILE_NAME, Path.GetFileName(sourcePath));
_tagpropertykey WPD_OBJECT_NAME = new _tagpropertykey();
WPD_OBJECT_NAME.fmtid = new Guid(0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C);
WPD_OBJECT_NAME.pid = 4;
values.SetStringValue(WPD_OBJECT_NAME, Path.GetFileName(sourcePath));
return values;
}
/// <summary>
/// 创建符合要求的文件夹
/// </summary>
/// <param name="parentId"></param>
/// <param name="folderName"></param>
/// <returns></returns>
private IPortableDeviceValues GetRequiredPropertiesForFolder(string parentId, string folderName)
{
IPortableDeviceValues values = new PortableDeviceTypesLib.PortableDeviceValues() as IPortableDeviceValues;
_tagpropertykey WPD_OBJECT_PARENT_ID = new _tagpropertykey();
WPD_OBJECT_PARENT_ID.fmtid = new Guid(0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C);
WPD_OBJECT_PARENT_ID.pid = 3;
values.SetStringValue(ref WPD_OBJECT_PARENT_ID, parentId);
_tagpropertykey WPD_OBJECT_NAME = new _tagpropertykey();
WPD_OBJECT_NAME.fmtid = new Guid(0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C);
WPD_OBJECT_NAME.pid = 4;
values.SetStringValue(WPD_OBJECT_NAME, folderName);
_tagpropertykey WPD_OBJECT_ORIGINAL_FILE_NAME = new _tagpropertykey();
WPD_OBJECT_ORIGINAL_FILE_NAME.fmtid = new Guid(0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C);
WPD_OBJECT_ORIGINAL_FILE_NAME.pid = 12;
values.SetStringValue(WPD_OBJECT_ORIGINAL_FILE_NAME, folderName);
_tagpropertykey WPD_OBJECT_CONTENT_TYPE = new _tagpropertykey();
WPD_OBJECT_CONTENT_TYPE.fmtid = new Guid(0xEF6B490D, 0x5CD8, 0x437A, 0xAF, 0xFC, 0xDA, 0x8B, 0x60, 0xEE, 0x4A, 0x3C);
WPD_OBJECT_CONTENT_TYPE.pid = 12;
values.SetStringValue(WPD_OBJECT_ORIGINAL_FILE_NAME, folderName);
return values;
}
创建完毕后,进行数据的写入
最后写入数据
/// <summary>
/// 写入数据
/// </summary>
/// <param name="sourceFile"></param>
/// <param name="portableDevice"></param>
/// <param name="parentId"></param>
public void TransferContentToDevice(string sourceFile, PortableDeviceClass portableDevice,string parentId)
{
IPortableDeviceContent content;
portableDevice.Content(out content);
IPortableDeviceValues values = GetRequiredPropertiesForContentType(sourceFile, parentId);
IStream tempStream;
uint optimalTransferSizeBytes = 0;
content.CreateObjectWithPropertiesAndData(values, out tempStream, ref optimalTransferSizeBytes, null);
System.Runtime.InteropServices.ComTypes.IStream targetStream = (System.Runtime.InteropServices.ComTypes.IStream)tempStream;
try
{
using (FileStream sourceStream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read))
{
int bytesRead = 0;
do
{
int count = 1024 * 1024;
byte[] buffer = new byte[count];
bytesRead = sourceStream.Read(buffer, 0, count);
IntPtr pcbWritten = IntPtr.Zero;
targetStream.Write(buffer, bytesRead, pcbWritten);
}
while (bytesRead > 0);
}
targetStream.Commit(0);
}
finally
{
Marshal.ReleaseComObject(tempStream);
}
}
整理上述方法,调用顺序如下
private void button2_Click(object sender, EventArgs e)
{
string deviceId = GetDeviceId();
IPortableDeviceContent content = GetDeviceContent(deviceId);
IPortableDeviceProperties properties;
content.Properties(out properties);
IPortableDeviceValues deviceValues;
properties.GetValues("DEVICE", null, out deviceValues);
List<string> storagesId = GetChildrenObjectIds(content, "DEVICE");//这里小米note手机由于没有外置sd卡,所以storagesId只有一个,即为内置存储
foreach (string storageId in storagesId)
{
List<string> objectsId = GetChildrenObjectIds(content, storageId);
string androidId = null;
foreach (string objectId in objectsId)
{
IPortableDeviceValues objectValues;
properties.GetValues(objectId, null, out objectValues);
string objectName = GetNameProperty(objectValues);
if (objectName == "Android")
{
androidId = objectId;
break;
}
}
TransferContentToDevice(@"C:\Users\Administrator\Desktop\tmp.png", content, androidId);
}
}
最后结果
最后再奉上拷贝设备上的数据到PC的代码
public void TransferContentFromDevice(string destPath,IPortableDeviceContent deviceContent,string objectId)
{
// TODO: Clean this up.
IPortableDeviceResources resources;
deviceContent.Transfer(out resources);
IStream wpdStream = null;
uint optimalTransferSize = 0;
_tagpropertykey property = new _tagpropertykey { fmtid = new Guid("E81E79BE-34F0-41BF-B53F-F1A06AE87842"), pid = 0 };
System.Runtime.InteropServices.ComTypes.IStream sourceStream = null;
try
{
resources.GetStream(objectId, ref property, 0, ref optimalTransferSize, out wpdStream);
sourceStream = (System.Runtime.InteropServices.ComTypes.IStream)wpdStream;
FileStream targetStream = new FileStream(destPath, FileMode.Create, FileAccess.Write);
unsafe
{
try
{
var buffer = new byte[1024];
int bytesRead;
do
{
sourceStream.Read(buffer, 1024, new IntPtr(&bytesRead));
targetStream.Write(buffer, 0, 1024);
} while (bytesRead > 0);
}
finally
{
targetStream.Close();
}
}
}
finally
{
Marshal.ReleaseComObject(sourceStream);
Marshal.ReleaseComObject(wpdStream);
}
}