与 USB 设备通信,从开始到完成(UWP 应用)

本文提供一个端到端演练,用于创建与 USB 设备对话的 UWP 应用。

使用Windows 运行时 API 编写 UWP 应用,使用户能够访问其外围 USB 设备。 此类应用可以根据用户指定的条件连接到设备,获取有关设备的信息,将数据发送到设备,并相反地从设备获取数据流,并轮询设备以获取中断数据。

在这里,我们将介绍 UWP 应用如何实现这些任务,并链接到演示如何使用 Windows.Devices.Usb 中包含的类的示例。 我们将介绍应用清单中所需的设备功能,以及如何在设备连接时启动应用。 我们将演示如何在后台运行数据传输任务,即使应用暂停以节省电池使用时间。

演练 - 为 USB 设备编写 UWP 应用

按照本文中的步骤操作,或者直接跳到 自定义 USB 设备访问示例。 配套示例实现此处的所有步骤,但为了保持移动,我们不演练代码。 某些步骤在示例部分中提供了“查找”,可帮助你快速查找代码。 示例源文件的结构简单且简单,因此可以轻松查找代码,而无需向下钻取多个源文件层。 但你可能更喜欢以不同的方式分解和组织自己的项目。

安装 Microsoft WinUSB 驱动程序

安装Microsoft提供的 WinUSB 驱动程序作为设备的函数驱动程序。

快速入门:WinUSB (Winusb.sys) 安装

可以通过以下方式安装Winusb.sys:

  • 连接设备时,你可能会注意到 Windows 会自动加载Winusb.sys,因为设备是 WinUSB 设备
  • 通过在 设备管理器 中指定系统提供的设备类来安装驱动程序。
  • 使用自定义 INF 安装驱动程序。 可通过以下两种方式之一获取 INF:
    • 从硬件供应商那里获取 INF。
    • 编写引用Microsoft提供的 Winusb.inf 文件的自定义 INF。 有关详细信息,请参阅 WinUSB (Winusb.sys) 安装

获取有关设备的信息

获取有关设备的设备接口 GUID、硬件 ID 和设备类信息。

可以从设备制造商获取该信息。

  • 供应商和产品标识符

    在设备管理器中,查看设备属性。 在 “详细信息 ”选项卡上,查看 硬件 ID 属性值。 该值是这两个标识符的组合。 例如,对于 SuperMUTT 设备, 硬件 ID 为“USB\VID_045E&PID_F001”;供应商 ID 为“0x045E”,产品 ID 为“0xF001”。

  • 设备类、子类和协议代码

  • 设备接口 GUID

或者,可以查看注册表的信息。 有关详细信息,请参阅 USB 设备注册表项

确定 USB API 集是否允许设备类、子类和协议

如果设备的设备类、子类和协议代码位于以下列表中,则可以编写 UWP 应用:

  • name:cdcControl, classId:02 * *
  • name:physical, classId:05 * *
  • name:personalHealthcare, classId:0f 00 00
  • name:activeSync, classId:ef 01 01
  • name:palmSync, classId:ef 01 02
  • name:deviceFirmwareUpdate, classId:fe 01 01
  • name:irda, classId:fe 02 00
  • name:measurement, classId:fe 03 *
  • name:vendorSpecific, classId:ff * *

创建基本的 Visual Studio 项目

创建可在本教程中扩展的基本 Visual Studio 项目。

有关详细信息,请参阅 UWP 应用入门。

将 USB 设备功能添加到应用清单

了解如何将 USB 设备功能添加到应用清单。

快速入门:如何将 USB 设备功能添加到应用清单

在文本编辑器中打开 Package.appxmanifest 文件,并将 Name 属性设置为“usb”的 DeviceCapability 元素添加,如以下示例所示。

注意

无法在 Visual Studio 中修改 USB 设备功能。 必须在解决方案资源管理器中右键单击 Package.appxmanifest 文件,然后选择“打开方式...”,然后选择“XML(文本)编辑器”。 该文件以纯 XML 打开。

<Capabilities>
  <!--When the device's classId is FF * *, there is a predefined name for the class.
      You can use the name instead of the class id.
      There are also other predefined names that correspond to a classId.-->
  <m2:DeviceCapability Name="usb">
    <!--SuperMutt Device-->
    <m2:Device Id="vidpid:045E 0611">
      <!--<wb:Function Type="classId:ff * *"/>-->
      <m2:Function Type="name:vendorSpecific"/>
    </m2:Device>
  </m2:DeviceCapability>
</Capabilities>

在示例中找到它: USB 设备功能位于 Package.appxmanifest 文件中。

打开设备进行通信

扩展应用以打开设备进行通信。

快速入门:如何连接到 USB 设备(UWP 应用)

  1. 通过生成高级查询语法(AQS)字符串来查找设备,该字符串包含用于在枚举设备集合中查找设备的搜索条件。
  2. 通过以下两种方式之一打开设备:
  3. DeviceInformation.Id 属性获取设备实例。
  4. 通过传递设备实例字符串并获取 UsbDevice 对象来调用 FromIdAsync。

在示例中找到它: 查看名为Scenario1_DeviceConnect的文件。

研究 USB 设备布局

研究 USB 设备布局

查看有关配置设备和执行数据传输的基本 USB 概念: 适用于所有 USB 开发人员的概念。

查看设备配置描述符、每个支持的备用设置的接口描述符及其终结点描述符。 通过使用 USBView,可以浏览所有 USB 控制器和连接到它们的 USB 设备,并检查设备配置。

在 UI 中获取和显示 USB 描述符

扩展应用以在 UI 中获取和显示 USB 描述符。

快速入门:如何获取 USB 描述符(UWP 应用)

在示例中找到它: 请参阅名为Scenario5_UsbDescriptors的文件。

发送供应商定义的 USB 控制传输

扩展应用以发送供应商定义的 USB 控制传输。

快速入门:如何发送 USB 控制传输请求(UWP 应用)

  1. 从设备的硬件规范获取供应商命令。
  2. 创建 UsbSetupPacket 对象,并通过设置各种属性来填充设置数据包。
  3. 根据传输的方向,启动一个异步操作,通过这些方法发送控制传输:

在示例中找到它: 请参阅名为Scenario2_ControlTransfer的文件。

读取或写入大容量数据

扩展应用以读取或写入大容量数据。

快速入门:如何发送 USB 大容量传输请求(UWP 应用)

  1. 获取大容量管道对象(UsbBulkOutPipeUsbBulkInPipe)。
  2. 配置大容量管道以设置策略参数。
  3. 使用 DataReaderDataWriter 对象设置数据流。
  4. 通过调用 DataReader.LoadAsync 或 DataWriter.StoreAsync 启动异步传输操作。
  5. 获取传输操作的结果。

在示例中找到它: 请参阅名为Scenario4_BulkPipes的文件。

获取硬件中断数据

扩展应用以获取硬件中断数据。

快速入门:如何发送 USB 中断传输请求(UWP 应用)

  1. 获取中断管道对象(UsbInterruptInPipeUsbInterruptOutPipe)。
  2. 实现 DataReceived 事件的中断处理程序。
  3. 注册事件处理程序以开始接收数据。
  4. 取消注册事件处理程序以停止接收数据。

在示例中找到它: 请参阅名为Scenario3_InterruptPipes的文件。

选择当前未处于活动状态的接口设置

扩展应用以选择当前未处于活动状态的接口设置。

快速入门:如何选择 USB 接口设置(UWP 应用)

当设备打开通信时,将选择默认接口及其第一个设置。 如果要更改此设置,请执行以下步骤:

  1. 使用 UsbInterfaceSetting.Selected 值获取 USB 接口的活动设置。
  2. 通过调用 UsbInterfaceSetting.SelectSettingAsync 启动异步操作来设置 USB 接口设置。

关闭设备

扩展应用以关闭设备。

快速入门:如何连接到 USB 设备(UWP 应用)

使用完 UsbDevice 对象后,关闭设备。

C++应用必须使用 delete 关键字释放引用。 C#/VB 应用必须调用 UsbDevice.Dispose 方法。 JavaScript 应用必须调用 UsbDevice.Close

在示例中找到它: 查看名为Scenario1_DeviceConnect的文件。

创建设备元数据包

为应用创建设备元数据包。

工具:设备元数据创作向导

  • 如果已安装 Windows 驱动程序工具包(WDK),请打开驱动程序>设备元数据>创作。
  • 如果已安装独立 SDK,该工具位于 <install_path>\bin\x86\DeviceMetadataWizardexe。

按照向导中的步骤将应用与设备相关联。 输入有关设备的信息:

  • “设备信息 ”页上,输入 型号名称制造商说明
  • “硬件信息 ”页上,输入设备的硬件 ID。

若要将应用声明为设备的特权应用,请按照以下说明操作:

  1. “应用信息”页上的“特权应用程序”组中,输入包名称、发布服务器名称和 UWP 应用 ID

    Visual Studio 的屏幕截图,其中显示了特权应用的设备元数据。

    注意

    不要检查 Access 自定义驱动程序 选项。

  2. 打开“ 完成 ”选项卡。选中 “将包复制到系统的本地元数据存储 ”复选框。

  3. 在控制面板中连接设备,打开“查看设备和打印机”,并验证设备的图标是否正确。

在示例中找到它: 请参阅 DeviceMetadata 文件夹。

实现自动播放激活

通过实现自动播放激活来扩展应用,以在设备连接到系统时启动应用。

快速入门:为自动播放设备注册应用

可以添加自动播放功能,以便在设备连接到系统时应用启动。 可以为所有 UWP 应用(特权或其他)启用自动播放。

  1. 在设备元数据包中,必须指定设备应如何响应自动播放通知。 在 Windows 信息 选项卡上,选择 UWP 设备应用 选项并输入应用信息,如下所示:

  2. 在应用清单中,添加 自动播放设备 声明和启动信息,如下所示:

    显示应用清单的屏幕截图,其中选择了“声明”并添加了“自动播放设备”。

  3. 在 App 类的 OnActivated 方法中,检查设备是否已激活应用。 如果是,则该方法接收包含 DeviceInformation.Id 属性值的 DeviceEventArgs 参数值。 这是打开设备进行通信描述的相同值。

在示例中找到它: 查看名为“自动播放”的文件。 有关 JavaScript,请参阅default.js。

实现后台任务

扩展应用以实现可以执行到设备的长度传输的后台任务,例如固件更新,而不会暂停应用。

若要实现后台任务,需要两个类。

后台任务类实现 IBackgroundTask 接口,并包含用于同步或更新外围设备的实际代码。 后台任务类在后台任务触发并从应用的应用程序清单中提供的入口点执行。

注意

Windows 8.1 提供的设备后台任务基础结构。 有关 Windows 后台任务的详细信息,请参阅 使用后台任务支持应用。

后台任务类

  1. 实现 Windows 后台任务基础结构所需的 IBackgroundTask 接口。
  2. 获取在 Run 方法中传递给类的 DeviceUseDetails 实例,并使用此实例将进度报告回 Microsoft Store 应用并注册取消事件。
  3. Run 方法还调用实现后台设备同步代码的专用 OpenDevice 和 WriteToDeviceAsync 方法。

UWP 应用注册并触发 DeviceUseTrigger 后台任务。 应用在后台任务上注册、触发和处理进度。

注意

下面的示例代码可以使用相应的对象应用于 DeviceServicingTrigger 后台任务。 两个触发器对象与其相应 API 之间的唯一区别是 Windows 进行的策略检查。

  1. 创建 DeviceUseTrigger 和 BackgroundTaskRegistration 对象。
  2. 检查此示例应用程序以前是否已注册任何后台任务,并通过对任务调用 Unregister 方法取消这些任务。
  3. 注册与设备同步的后台任务。 下一步从 SyncWithDeviceAsync 方法调用 SetupBackgroundTask 方法。
    1. 初始化 DeviceUseTrigger 并将其保存供以后使用。
    2. 创建 BackgroundTaskBuilder 对象,并使用其 Name、TaskEntryPoint 和 SetTrigger 属性和方法注册应用的 DeviceUseTrigger 对象和后台任务名称。 BackgroundTaskBuilder 对象的 TaskEntryPoint 属性设置为在触发后台任务时将运行的后台任务类的全名。
    3. 从后台任务注册完成和进度事件,以便Microsoft应用商店应用可以向用户提供完成和进度更新。
  4. 专用 SyncWithDeviceAsync 方法注册将与设备同步并启动后台同步的后台任务。
    1. 从上一步调用 SetupBackgroundTask 方法,并注册将与设备同步的后台任务。

    2. 调用启动后台任务的专用 StartSyncBackgroundTaskAsync 方法。

    3. 关闭应用的句柄,以确保后台任务能够在设备启动时打开设备。

      注意

      后台任务需要打开设备才能执行更新,以便Microsoft应用商店应用必须在调用 RequestAsync 之前关闭与设备的连接

    4. 调用 DeviceUseTrigger 对象的 RequestAsync 方法,该方法开始触发后台任务,并从 RequestAsync 返回 DeviceTriggerResults 对象,用于确定是否成功启动后台任务。

      注意

      Windows 检查,以确保已完成所有必要的任务启动策略检查。 如果完成所有策略检查,更新操作现在作为后台任务在 Microsoft 应用商店应用外部运行,则允许在操作正在进行时安全地暂停应用。 如果不再满足这些要求,Windows 还将强制实施任何运行时要求,并取消后台任务。

    5. 使用从 StartSyncBackgroundTaskAsync 返回的 DeviceTriggerResults 对象来确定后台任务是否已成功启动。 switch 语句用于检查 DeviceTriggerResults 的结果。

  5. 实现专用 OnSyncWithDeviceProgress 事件处理程序,该事件处理程序将使用后台任务的进度更新应用 UI。
  6. 实现专用 OnSyncWithDeviceCompleted 事件处理程序,以便在后台任务完成时处理从后台任务到前台应用的转换。
    1. 使用 BackgroundTaskCompletedEventArgs 对象的 CheckResults 方法来确定后台任务是否引发了任何异常。
    2. 应用重新打开供前台应用使用的设备,现在后台任务已完成并更新 UI 以通知用户。
  7. 实现 UI 中的专用按钮单击事件处理程序以启动和取消后台任务。
    1. 专用Sync_Click事件处理程序调用前面步骤中所述的 SyncWithDeviceAsync 方法。
    2. 专用CancelSync_Click事件处理程序调用专用 CancelSyncWithDevice 方法以取消后台任务。
  8. 专用 CancelSyncWithDevice 方法取消注册并取消任何活动设备同步,以便可以在 BackgroundTaskRegistration 对象上使用 Unregister 方法重新打开设备。

在示例中找到它: 查看名为Scenario7_Sync文件的文件。 后台类在 IoSyncBackgroundTask 中实现。

运行 Windows 应用认证工具包

运行 Windows 应用认证工具包。

使用 Windows 应用认证工具包

推荐。 运行 Windows 应用认证工具包有助于确保应用满足Microsoft应用商店要求。 每当向应用添加主要功能时,都应运行它。

UWP 应用 UI,开始完成 (XAML)

详细了解如何设计 UWP 应用 UI。

使用 C# 和 Visual Basic 的 UWP 应用的路线图,以及 使用 C++ 的 UWP 应用的路线图

详细了解如何使用 C++、C# 或 Visual Basic 创建 UWP 应用。

异步编程(UWP 应用)

了解如何在应用执行可能需要较长时间的工作时保持响应。

重要的 API