c#使用WPD读取便携式设备信息一(枚举设备、连接设备及读取设备信息)
2016-04-20 21:36
465 查看
手机或其他电子设备通过USB插入电脑上,并且以MTP(媒体传输协议)方式连接时,可在“计算机”中看到类似计算机盘符的便携式设备文件夹显示,但是这并不是一个计算机盘符,并不能通过常规读取文件的方式读取其中的数据。那么如何才能读取便携式设备(如只能手机)的数据呢?通常读取IOS设备是通过调用iTunesMobileDevice.dll里面写好的服务来进行的,而安卓设备则是通过ADB命令或者自己写服务来操作,前者ADB命令bug太多,windows下的命令行程序及其难用,而后者由于难度太大导致开发周期延长也不是较好的方法,本篇则介绍通过使用WPD的方式读取便携式设备。主要包括以下几个部分内容:
什么是MTP模式
什么是WPD
调用WPD
修改InteropPortableDeviceApiLibdll
使用WPD读取设备基础信息
枚举所有设备
连接与断开
读取设备
MTP模式是微软制订的一套媒体传输协议(Media Transfer Protocol),由微软公司制定的在设备之间进行多媒体文件交换的通信协议,它实现的是把简单的文件复制变成一种协议性的传输方式。MTP既可以实现在USB协议上,也可以实现在TCP/IP协议上,它属于上层的应用协议,而不关心底层传输协议。目前大部分设备的应用都是基于USB协议。
将Interop.PortableDeviceApiLib.dll拷贝到桌面,打开C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin目录下的反汇编工具ildasm.exe。
打开刚才拷贝到桌面上的Interop.PortableDeviceApiLib.dll,并转储为Interop.PortableDeviceApiLib.il
编辑刚才转储的.il文件,修改GetDevices 方法
修改前 instance void GetDevices([in][out] string& marshal( lpwstr) pPnPDeviceIDs,
修改后 instance void GetDevices([in][out] string[] marshal( lpwstr[]) pPnPDeviceIDs,
打开控制台程序,执行命令
c:\windows\microsoft.net\framework\v4.0.30319\ilasm.exe /dll/resource=Interop.PortableDeviceApiLib.res Interop.PortableDeviceApiLib.il进行编译,然后得到了修改后的Interop.PortableDeviceApiLib.dll文件了。
重新添加对修改后的Interop.PortableDeviceApiLib.dll的引用,并修改嵌入式互操作类型为false。
连接和断开设备
调用顺序
最后附上结果
对比资源管理器中
什么是MTP模式
什么是WPD
调用WPD
修改InteropPortableDeviceApiLibdll
使用WPD读取设备基础信息
枚举所有设备
连接与断开
读取设备
什么是MTP模式
媒体传输协议,是基于PTP(Picture Transfer Protocol)协议的扩展,主要用于传输媒体文件。MTP模式是微软制订的一套媒体传输协议(Media Transfer Protocol),由微软公司制定的在设备之间进行多媒体文件交换的通信协议,它实现的是把简单的文件复制变成一种协议性的传输方式。MTP既可以实现在USB协议上,也可以实现在TCP/IP协议上,它属于上层的应用协议,而不关心底层传输协议。目前大部分设备的应用都是基于USB协议。
什么是WPD
Windows Portable Devices译作Windows 便携设备 (WPD) 是一种驱动程序技术,可支持广泛的可移动设备,比如移动电话、数码相机和便携媒体播放器。WPD 提供了标准化的基础结构,以实现应用程序和连接到正在运行 Windows 的 PC 上的便携设备之间的数据传输。WPD 还可为应用程序提供设备及其内容的统一视图以及标准化机制,从而获得访问数据的权限并对数据进行传输。调用WPD
c#程序使用WPD需要添加对Interop.PortableDeviceApiLib.dll和Interop.PortableDeviceTypesLib.dll两个COM组件的引用。但是由于其是用c++编译的,对于有些方法的调用并不能得到正确的结果,因此在使用这两个组件之前需要对Interop.PortableDeviceApiLib.dll组件进行修改再重新编译。修改Interop.PortableDeviceApiLib.dll
首先创建一个窗体程序,添加上述两个引用,生成程序,然后就可以在程序的DEBUG目录中找到上述两个dll。将Interop.PortableDeviceApiLib.dll拷贝到桌面,打开C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin目录下的反汇编工具ildasm.exe。
打开刚才拷贝到桌面上的Interop.PortableDeviceApiLib.dll,并转储为Interop.PortableDeviceApiLib.il
编辑刚才转储的.il文件,修改GetDevices 方法
修改前 instance void GetDevices([in][out] string& marshal( lpwstr) pPnPDeviceIDs,
修改后 instance void GetDevices([in][out] string[] marshal( lpwstr[]) pPnPDeviceIDs,
打开控制台程序,执行命令
c:\windows\microsoft.net\framework\v4.0.30319\ilasm.exe /dll/resource=Interop.PortableDeviceApiLib.res Interop.PortableDeviceApiLib.il进行编译,然后得到了修改后的Interop.PortableDeviceApiLib.dll文件了。
重新添加对修改后的Interop.PortableDeviceApiLib.dll的引用,并修改嵌入式互操作类型为false。
使用WPD读取设备基础信息
枚举所有设备
/// <summary> /// 枚举所有便携式设备(MTP模式) /// </summary> /// <returns>返回设备id数组</returns> public string[] EnumerateDevices() { string[] devicesIds = null; PortableDeviceManagerClass deviceManager = new PortableDeviceManagerClass(); uint deviceCount = 1;//设备数目初始值必须大于0 deviceManager.GetDevices(null, ref deviceCount);//获取设备数目必须置第一个参数为null if (deviceCount > 0) { devicesIds = new string[deviceCount]; deviceManager.GetDevices(devicesIds, ref deviceCount); } return devicesIds; }
连接与断开
连接便携式设备并读取基本信息。利用刚才枚举设备获得的设备Id号,可以对设备进行一系列的操作。连接和断开设备
/// <summary> /// 连接设备 /// </summary> /// <param name="DeviceId"></param> /// <param name="portableDevice"></param> /// <param name="deviceContent"></param> /// <returns></returns> public IPortableDeviceValues Connect(string DeviceId,out PortableDevice portableDevice,out IPortableDeviceContent deviceContent) { IPortableDeviceValues clientInfo = (IPortableDeviceValues)new PortableDeviceTypesLib.PortableDeviceValuesClass(); portableDevice = new PortableDeviceClass(); portableDevice.Open(DeviceId, clientInfo); portableDevice.Content(out deviceContent); IPortableDeviceProperties deviceProperties; deviceContent.Properties(out deviceProperties); IPortableDeviceValues deviceValues; deviceProperties.GetValues("DEVICE", null, out deviceValues); return deviceValues; } /// <summary> /// 断开设备 /// </summary> /// <param name="portableDevice"></param> public void Disconnect(PortableDevice portableDevice) { portableDevice.Close(); }
读取设备
连接设备返回IPortableDeviceValues,根据返回的IPortableDeviceValues读取设备信息/// <summary> /// 设备类型 /// </summary> public enum DeviceType { Generic = 0, Camera = 1, MediaPlayer = 2, Phone = 3, Video = 4, PersonalInformationManager = 5, AudioRecorder = 6 }; /// <summary> /// 获取设备类型 /// </summary> /// <param name="DeviceValues"></param> /// <returns></returns> public DeviceType GetDeviceType(IPortableDeviceValues DeviceValues) { _tagpropertykey deviceTypeKey = new _tagpropertykey() { fmtid = new Guid("26d4979a-e643-4626-9e2b-736dc0c92fdc"), pid = 15 }; uint propertyValue; DeviceValues.GetUnsignedIntegerValue(ref deviceTypeKey, out propertyValue); DeviceType deviceType = (DeviceType)propertyValue; return deviceType; } /// <summary> /// 获取设备名 /// </summary> /// <param name="DeviceValues"></param> /// <returns></returns> public string GetDeviceName(IPortableDeviceValues DeviceValues) { _tagpropertykey property = new _tagpropertykey() { fmtid = new Guid("ef6b490d-5cd8-437a-affc-da8b60ee4a3c"), pid = 4 }; string name; DeviceValues.GetStringValue(ref property, out name); return name; } /// <summary> /// 获取固件版本 /// </summary> /// <param name="DeviceValues"></param> /// <returns></returns> public string GetFirmwareVersion(IPortableDeviceValues DeviceValues) { _tagpropertykey deviceTypeKey = new _tagpropertykey() { fmtid = new Guid("26d4979a-e643-4626-9e2b-736dc0c92fdc"), pid = 3 }; string firmwareVersion; DeviceValues.GetStringValue(ref deviceTypeKey, out firmwareVersion); return firmwareVersion; } /// <summary> /// 获取制造商 /// </summary> /// <param name="DeviceValues"></param> /// <returns></returns> public string GetManufacturer(IPortableDeviceValues DeviceValues) { _tagpropertykey property = new _tagpropertykey() { fmtid = new Guid("26d4979a-e643-4626-9e2b-736dc0c92fdc"), pid = 7 }; string manufacturer; DeviceValues.GetStringValue(ref property, out manufacturer); return manufacturer; } /// <summary> /// 获取型号 /// </summary> /// <param name="DeviceValues"></param> /// <returns></returns> public string GetModel(IPortableDeviceValues DeviceValues) { _tagpropertykey property = new _tagpropertykey() { fmtid = new Guid("26d4979a-e643-4626-9e2b-736dc0c92fdc"), pid = 8 }; string model; DeviceValues.GetStringValue(ref property, out model); return model; } /// <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); if (fetched > 0) { childItems.Add(objectId); } } while (fetched > 0); return childItems; } /// <summary> /// 获取总容量和可用容量 /// </summary> /// <param name="deviceContent"></param> /// <param name="storageId"></param> /// <param name="freeSpace"></param> /// <param name="storageCapacity"></param> public void GetStorageCapacityAnFreeSpace(IPortableDeviceContent deviceContent, string storageId, out ulong freeSpace, out ulong storageCapacity) { IPortableDeviceProperties deviceProperties; deviceContent.Properties(out deviceProperties); IPortableDeviceKeyCollection keyCollection = (IPortableDeviceKeyCollection)new PortableDeviceTypesLib.PortableDeviceKeyCollectionClass(); _tagpropertykey freeSpaceKey = new _tagpropertykey(); freeSpaceKey.fmtid = new Guid("01a3057a-74d6-4e80-bea7-dc4c212ce50a"); freeSpaceKey.pid = 5; _tagpropertykey storageCapacityKey = new _tagpropertykey(); storageCapacityKey.fmtid = new Guid("01a3057a-74d6-4e80-bea7-dc4c212ce50a"); storageCapacityKey.pid = 4; keyCollection.Add(freeSpaceKey); keyCollection.Add(storageCapacityKey); IPortableDeviceValues deviceValues; deviceProperties.GetValues(storageId, keyCollection, out deviceValues); deviceValues.GetUnsignedLargeIntegerValue(ref freeSpaceKey, aba7 out freeSpace); deviceValues.GetUnsignedLargeIntegerValue(ref storageCapacityKey, out storageCapacity); }
调用顺序
string[] deviceIds = EnumerateDevices(); PortableDevice portableDevice; IPortableDeviceContent deviceContent; IPortableDeviceValues deviceValues = Connect(deviceIds[0], out portableDevice,out deviceContent); string deviceName = GetDeviceName(deviceValues); DeviceType deviceType = GetDeviceType(deviceValues); string firmwareVersion = GetFirmwareVersion(deviceValues); string manufacturer = GetManufacturer(deviceValues); string model = GetModel(deviceValues); List<string> storagesIds = GetChildrenObjectIds(deviceContent, "DEVICE"); StringBuilder storagesSb = new StringBuilder(); foreach (string storageId in storagesIds) { ulong freeSpace; ulong storageCapacity; GetStorageCapacityAnFreeSpace(deviceContent, storageId, out freeSpace, out storageCapacity); storagesSb.AppendFormat("可用容量为{0}GB,总容量为{1}GB", Math.Round((double)freeSpace / 1024 / 1024 / 1024, 3), Math.Round((double)storageCapacity / 1024 / 1024 / 1024, 3)); } Disconnect(portableDevice); textBox1.AppendText(string.Format("当前设备数目:{0}个\r\n", deviceIds.Length)); textBox1.AppendText(string.Format("连接的设备名称:{0}\r\n", deviceName)); textBox1.AppendText(string.Format("连接的设备类型:{0}\r\n", deviceType.ToString())); textBox1.AppendText(string.Format("连接的设备固件版本:{0}\r\n", firmwareVersion)); textBox1.AppendText(string.Format("连接的设备制造厂商:{0}\r\n", manufacturer)); textBox1.AppendText(string.Format("连接的设备型号:{0}\r\n", model)); textBox1.AppendText(storagesSb.ToString());
最后附上结果
对比资源管理器中
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories