c#使用WPD读取便携式设备信息一(枚举设备、连接设备及读取设备信息)

版权声明:本文为转载文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

手机或其他电子设备通过USB插入电脑上,并且以MTP(媒体传输协议)方式连接时,可在“计算机”中看到类似计算机盘符的便携式设备文件夹显示,但是这并不是一个计算机盘符,并不能通过常规读取文件的方式读取其中的数据。那么如何才能读取便携式设备(如只能手机)的数据呢?通常读取IOS设备是通过调用iTunesMobileDevice.dll里面写好的服务来进行的,而安卓设备则是通过ADB命令或者自己写服务来操作,前者ADB命令bug太多,windows下的命令行程序及其难用,而后者由于难度太大导致开发周期延长也不是较好的方法,本篇则介绍通过使用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;
        }
 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
连接与断开
  • 连接便携式设备并读取基本信息。利用刚才枚举设备获得的设备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();
        }
 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
读取设备
  • 连接设备返回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, out freeSpace);
            deviceValues.GetUnsignedLargeIntegerValue(ref storageCapacityKey, out storageCapacity);
        }
 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 调用顺序
            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());
 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 最后附上结果

这里写图片描述

  • 对比资源管理器中

这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值