DeviceWatcher
编写与 USB 设备交互的 UWP 应用时,应用可以发送控制命令、获取设备信息,以及向/从批量和中断终结点读取和写入数据。 在完成所有这些操作之前,必须找到设备并建立连接。
开始之前...
这是系列中的第一个主题。 在开始本教程之前,必须已创建一个可在本教程中扩展的基本Visual Studio项目。 有关详细信息
,请阅读 UWP 应用入门
。
代码示例基于 CustomUsbDeviceAccess 示例。 可以从此代码库页下载完整的示例。
本教程中使用的 USB 设备是 SuperMUTT 设备。
为了使用
Windows。Devices.Usb
命名空间要编写与 USB 设备交互的Windows应用,设备必须加载Winusb.sys驱动程序作为其功能驱动程序。 Winusb.sys由 Microsoft 提供,包含在
\Windows\System32\drivers
文件夹中Windows。
流程图:查找设备
若要连接到 USB 设备,必须先根据各种发现模式查找设备,然后连接到该设备:
连接具有特定设备接口 GUID 的任何 USB 设备。
连接具有特定供应商 ID 和产品 ID 且具有特定设备接口 GUID 的 USB 设备。
连接具有特定供应商 ID 和产品 ID 的 USB 设备,而无需知道设备接口 GUID。
连接具有已知设备类的 USB 设备。
什么是设备接口 GUID?
内核模型驱动程序在初始化期间注册并公开名为
设备接口 GUID 的 GUID
。 通常,应用使用公开的 GUID 查找关联的驱动程序及其设备,然后打开设备的句柄。 检索的句柄用于后续读取和写入操作。
但是,如果Winusb.sys,而不是公开设备接口 GUID 的驱动程序,可以通过以下两种方式之一提供:
在设备的 MS OS 描述符中。 设备制造商在设备的扩展属性描述符中将
DeviceInterfaceGUID
设置为自定义属性。 有关详细信息,请参阅
Microsoft OS 描述符
中的“扩展属性描述符”文档。
如果通过自定义 INF 手动安装Winusb.sys,则 INF 在 INF 中注册了 GUID。 请参阅
WinUSB (Winusb.sys) 安装
。
如果为设备找到了设备接口 GUID,则 UWP 应用可以找到与该设备接口 GUID 匹配的所有设备。
USB 设备标识如何在Windows中显示?
每个 USB 设备必须有两条信息:供应商 ID 和产品 ID。
USB-IF 分配这些标识符,设备制造商必须在设备中公开这些标识符。 那么,如何获取该信息?
即使设备没有加载设备驱动程序,也就是说,Windows检测到它为“未知设备”,你仍然可以在
硬件 ID
属性值的设备管理器中查看标识符。 该值是这两个标识符的组合。 例如,对于 SuperMUTT 设备,
硬件 ID
为“USB\VID_045E PID_F001”;供应商 ID 为“0x045E&”,产品 ID 为“0xF001”。
如果设备有 INF,请从
“模型”
部分获取该字符串。
可以检查各种注册表设置。 最简单的方法是查看
<HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Enum\USB\硬件 ID>
有关详细信息,请参阅
USB 设备注册表项
。
应用清单使用硬件 ID 来标识设备。
<Device Id=“vidpid:045e f001”>
UWP 应用可以找到与特定供应商和产品 ID 匹配的所有设备。 可以通过指定设备接口 GUID 来缩小搜索结果范围。
什么是 USB 设备类?
大多数 USB 设备都符合 USB-IF 批准的设备类规范。 通过使用这些规范,具有相似性质的设备可以通过标准方式展示其功能。 此方法的最大优点是设备可以使用 Microsoft 提供的内置类驱动程序或通用Winusb.sys驱动程序。
某些设备可能不遵循 USB-IF 规范。 而是公开
供应商定义的
功能。 对于此类设备,供应商必须提供设备驱动程序,也可以使用Winusb.sys。
无论设备是供应商定义的还是符合设备类,它都必须描述此设备类相关信息:
类代码:指示设备所属的设备类。
子类代码:在设备类中,指示设备的子类。
协议代码:设备使用的协议。
例如,SuperMUTT 设备是供应商定义的设备,类代码指示该信息是 FF。 如果设备将类代码显示为 FEh、子类代码为 02h 和协议代码 00h,则可以得出结论,设备是符合类的 IrDA 桥设备。
UWP 应用可以与属于这些设备类的设备通信:
ActiveSync
CdcControl
DeviceFirmwareUpdate
PalmSync
PersonalHealthcare
VendorSpecific
UWP 应用可以找到与特定类、子类和协议代码集匹配的所有设备。
获取设备的 AQS) 字符串 (高级查询语法
(AQS) 生成高级查询字符串,其中包含有关要检测的设备标识信息。 可以通过指定供应商/产品 ID、设备接口 GUID 或设备类来生成字符串。
如果要提供供应商 ID/产品 ID 或设备接口 GUID,请调用
GetDeviceSelector
的任何重载。
在 SuperMUTT 设备的示例中,
GetDeviceSelector
检索类似于以下字符串的 AQS 字符串:
"System.Devices.InterfaceClassGuid:="{DEE824EF-729B-4A0E-9C14-B7117D33A817}" AND System.Devices.InterfaceEnabled:=System.StructuredQueryType.Boolean#True AND System.DeviceInterface.WinUsb.UsbVendorId:=1118 AND System.DeviceInterface.WinUsb.UsbProductId:=61441"
注意
请注意,字符串中显示的设备接口 GUID 不是指定的设备接口 GUID。 该 GUID 是由 UWP 应用Winusb.sys注册的实际设备接口 GUID。
如果知道设备的设备类或其类、子类和协议代码,请调用
GetDeviceClassSelector
来生成 AQS 字符串。
通过指定
ClassCode
、
SubclassCode
和
ProtocolCode
属性值创建
UsbDeviceClass
对象。 或者,如果知道设备的设备类,可以通过指定特定的
UsbDeviceClasses
属性来调用构造函数。
查找设备 - 基本方式
这是查找 USB 设备的最简单方法。 有关详细信息,请参阅
快速入门:枚举常用设备
。
将检索到的 AQS 字符串传递给
FindAllAsync
。 调用检索
DeviceInformationCollection
对象。
通过集合Loop。 每次迭代都会获取
DeviceInformation
对象。
获取
DeviceInformation.Id
属性值。 字符串值是设备实例路径。 例如,“\\\\?\\USB#VID_045E& PID_078F#61b8ff02605&&&#{dee824ef-729b-4a0e-9c14-b7117d33a817}”。
通过传递设备实例字符串并获取
UsbDevice
对象来调用
FromIdAsync
。 然后,可以使用
UsbDevice
对象执行其他操作,例如发送控件传输。 当应用使用
UsbDevice
对象完成后,应用必须通过调用
Close
释放它。
注意
UWP 应用挂起时,设备会自动关闭。 为了避免将过时句柄用于将来的操作,应用必须释放
UsbDevice
引用。
private async void OpenDevice()
UInt32 vid = 0x045E;
UInt32 pid = 0x0611;
string aqs = UsbDevice.GetDeviceSelector(vid, pid);
var myDevices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(aqs);
usbDevice = await UsbDevice.FromIdAsync(myDevices[0].Id);
catch (Exception exception)
ShowStatus(exception.Message.ToString());
finally
ShowStatus("Opened device for communication.");
查找设备 - 使用 DeviceWatcher
或者,可以动态枚举设备。 然后,如果添加或删除设备,或者设备属性发生更改,应用可以接收通知。 有关详细信息,请参阅 如何在添加、删除或更改设备时获取通知。
DeviceWatcher 对象使应用能够在从系统中添加和删除设备时动态检测设备。
创建 DeviceWatcher 对象,以检测设备何时添加到系统或从系统中删除。 必须通过调用 CreateWatcher 并指定 AQS 字符串来创建对象。
为 DeviceWatcher 对象上的“已添加”和“已删除”事件实现和注册处理程序。 当系统添加或删除具有相同标识信息) 的设备 (时,将调用这些事件处理程序。
启动和停止 DeviceWatcher 对象。
应用必须通过调用 Start 来启动 DeviceWatcher 对象,以便它可以在添加或删除设备时开始检测设备。 相反,当不再需要检测设备时,应用必须通过调用 Stop 来停止 DeviceWatcher。 该示例有两个按钮,允许用户启动和停止 DeviceWatcher。
此代码示例演示如何创建和启动设备观察程序来查找 SuperMUTT 设备的实例。
void CreateSuperMuttDeviceWatcher(void)
UInt32 vid = 0x045E;
UInt32 pid = 0x0611;
string aqs = UsbDevice.GetDeviceSelector(vid, pid);
var superMuttWatcher = DeviceInformation.CreateWatcher(aqs);
superMuttWatcher.Added += new TypedEventHandler<DeviceWatcher, DeviceInformation>
(this.OnDeviceAdded);
superMuttWatcher.Removed += new TypedEventHandler<DeviceWatcher, DeviceInformationUpdate>
(this.OnDeviceRemoved);
superMuttWatcher.Start();
若要打开设备,应用必须通过调用静态方法 FromIdAsync 并传递从 DeviceInformation.Id) 获取的设备实例路径 (来启动异步操作。 该操作获取的结果是 UsbDevice 对象,该对象用于与设备的未来通信,例如执行数据传输。
使用 完 UsbDevice 对象后,必须释放它。 通过释放对象,将取消所有挂起的数据传输。 这些操作的完成回调例程仍会调用,并显示已取消的错误或已完成的操作。
C++ 应用必须使用 delete 关键字释放引用。 C#/VB应用必须调用 UsbDevice.Dispose 方法。 JavaScript 应用必须调用 UsbDevice.Close。
如果设备正在使用或找不到, FromIdAsync 将失败。