USB 双向扩展程序
重要
新式打印平台是 Windows 与打印机通信的首选方式。 建议使用 Microsoft 的 IPP 收件箱类驱动程序以及打印支持应用 (PSA) 来自定义 Windows 10 和 11 中的打印体验,以便进行打印机设备开发。
有关详细信息,请参阅新式打印平台和打印支持应用设计指南。
Windows 允许制造商使用 Bidi XML 文件和称为 USB Bidi 扩展器的 Javascript 文件的组合来支持 USB 设备的双向通信 (Bidi)。
USB Bidi 扩展器允许应用程序将 Bidi 与 USB 配合使用作为传输机制。 Javascript 实现不支持任何设备流控制,也不支持在打印过程中将控制信息与打印作业进行多路复用。
默认情况下,Bidi 查询和状态请求通过用于打印的 USB 设备接口进行路由。 这允许使用 getSchemas JavaScript 方法进行状态的完整双向通信,并允许使用 setSchema JavaScript 方法执行 Set 操作。 当没有打印作业被发送到打印设备时,可以进行完全双向通信。
在打印过程中,打印作业数据会阻止写入,因此使用 getStatus 方法仅使用读取通道从设备获取未经请求的状态。 但是,如果设备支持辅助 USB 接口,则使用 requestStatus 方法函数在设备打印时从打印机获取状态。
在 Windows 8.1 中,v4 驱动程序模型已扩展为支持基于主机的设备。 除此之外,USBMon 已更新,允许 IHV 使用 JavaScript 代码更好地控制打印路径并执行基于打印作业的操作。 此更新包括添加提供新 Bidi JavaScript 入口点的 API。 这些 API 与 USBMon 中的现有函数保持一致。
startPrintJob。 此新函数与 USBMon 中的 startDocPort 保持一致。 当每个新的 USB 打印作业在连接到基于主机的打印设备的端口上启动时,USBMon 将调用 IHV 提供的 JavaScript,以允许它执行所需的任何作业前处理。 这可能包括在作业属性包中设置作业全局属性,查询设备的当前状态和配置数据,或者什么都不做。 完成的任务完全取决于设备和 IHV。
writePrintData。 此新函数与 USBMon 中的 writePort 保持一致。 当 USBMon 在打印过程中从后台处理程序接收每个 writePort 函数调用时,需要通过 IHV JavaScript 函数将提供的打印数据发送到基于主机的设备。 这允许 IHV JS 决定此时应该向设备发送什么内容。 IHV 可以根据需要删除、添加或保存部分数据缓冲区。 这使得 IHV 可以完全控制何时发送到设备的内容。 一旦从后台处理程序接收到所有数据,IHV 就有机会为打印作业的偶数页保存数据(在一个持久流中),从而有助于实现手动双工等方案。 IHV 还可以使用 printerBidiSchemaResponses 对象在处理作业期间返回打印作业状态或设备状态。
endPrintJob。 此新函数与 USBMon 中的 endDocPort 保持一致。 当 USBMon 在连接到基于主机的打印设备的端口上接收到每个 USB 打印作业的 endDocPort 调用时,USBMon 将调用 IHV 提供的 JavaScript,以允许其进行所需的任何作业后处理。 这可能包括将任何保留的数据发送到设备,返回 Bidi 架构值以启动手动双工或 IHV/设备所需的任何其他操作。
下图提供了 USB Bidi 扩展体系结构的概述,其中显示了使用 getStatus 方法通过 USBPrint 接口从设备获取未经请求的状态的方案。
有关使用 USB 打印机的详细信息,请参阅 USB 打印。
USB Bidi 扩展程序 API 参考
USB Bidi 扩展器中的 JavaScript 代码使用以下函数与打印设备通信:
getSchemas
setSchema
getStatus
requestStatus
startPrintJob
writePrintData
endPrintJob
有关这些 API 的详细信息,请参阅 JavaScript API 参考。
USBMon Bidi 扩展 XML 架构
USBMon Bidi 扩展文件使用与 SNMP Bidi 扩展文件和 WSDMon Bidi 扩展文件相同的基本结构。 XML 架构文件在 Windows 驱动程序工具包中发布,USBMon Bidi 扩展文件将在 INFGate WHCK 测试期间自动进行架构验证。 当开发 Bidi 扩展架构并使用 USB 总线时,请务必注意以下信息:
值可以指定访问类型为 Get、Set 或 GetSet。 这表示 Bidi Get 或 Set 操作类型支持所描述的架构元素的位置。
值可以指定 queryKey。 这应该用于表示从设备获取数据的物理操作。 同一 queryKey 下的所有属性都可在一个 USB 读/写操作中检索。
如果在 Bidi API 调用中请求了 Bidi 值,则会立即轮询它们。 refreshInterval 值是初始值,该值指示何时轮询设备以获取特定 Bidi 架构值的更新。 每次轮询后,refreshInterval 都会增加,直到停止轮询。 以下公式显示了 refreshInterval 的递增方式:
currentRefreshInterval = refreshInterval * (3 * numPolls);
USBMon 和 USB Bidi 扩展文件交互
当创建或打开每个新的 USB 端口时,USBMon 将确定连接的设备和相关驱动程序是否包含新的 Bidi 扩展文件和 Bidi 扩展 JavaScriptfile。 USBMon 搜索 v4 驱动程序清单或驱动程序 INI 文件,并检索文件的名称。 如果 USBMon 找到相关文件,则它将使用它们来确定此设备支持的扩展 Bidi 架构值列表,然后与设备通信以查询它们的值。 此时,USBMon 通过现有的打印后台处理程序 API 支持 IHV 指定的 Bidi 架构操作。
GitHub 上的 Windows 驱动程序示例
USBMon Bidi XML 文件示例 - 这提供了 USBMon Bidi 扩展 XML 文件的示例。 它使用标准 Bidi 架构属性 DeviceInfo、Configuration 和 Memory,还定义了一些自定义扩展。
有关 Bidi 扩展文件的详细信息,请参阅双向通信架构。
USBMon Bidi JavaScript 文件示例。 此示例包含 USBMon Bidi Extender JavaScript 文件。 它演示如何支持 Bidi SET 和 GET 操作,以及如何在打印机打印时侦听事件。
调试
可以通过创建以下注册表项来启用交互式调试。 对于 USB Bidi JavaScript,必须重新启动打印后台处理程序才能启用调试。
键名:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print
值名:EnableJavaScriptDebugging
类型:DWORD
值:1
创建上一部分所示的注册表项,并重新启动托管进程后,可以按如下所示调试脚本:
将调试器附加到托管进程。 对于 USB Bidi JavaScript,这是 spoolsv.exe。
将调试器设置为脚本调试模式。
选择全部中断 (Ctrl + Alt + Break),以便在下次脚本运行时进入该进程。
运行方案以重现你的问题。
一旦调试器进入 JavaScript 函数,设置任何必要的断点,并单步执行代码。