JavaScript 约束

重要

新式打印平台是 Windows 与打印机通信的首选方式。 建议使用 Microsoft 的 IPP 收件箱类驱动程序以及打印支持应用 (PSA) 来自定义 Windows 10 和 11 中的打印体验,以便进行打印机设备开发。

有关详细信息,请参阅新式打印平台打印支持应用设计指南

v4 打印机驱动程序模型支持从 v3 IPrintOemPrintTicketProvider 接口派生的扩展约束和 PrintTicket 处理的新模型。

但是,v4 打印机驱动程序不使用已编译的配置插件,而是使用 JavaScript 来实现称为 JavaScript 约束的 API,并且打印机驱动程序可以根据需要实现其中一个或多个 API。 有关详细信息,请参阅本主题末尾的 JavaScript 约束 API 部分中的函数。

JavaScript 约束可用于增强 PrintCapabilities、验证 PrintTickets,并处理 PrintTicket 到 DEVMODE 的转换,反之亦然。 但是,JavaScript 约束有一些限制。 以下是主要限制的列表:

  • 使用 CompletePrintCapabilities 添加的功能和选项,以及 validatePrintTicket 中指定的约束,不会显示在桌面打印机首选项窗口中。

  • 使用 CompletePrintCapabilities 添加的功能和选项不会保存到公共 DEVMODE 中。

  • JavaScript 约束不能从资源 dll 访问语言资源,来本地化添加的功能、选项或参数。

因此,我们建议仅在适当情况下使用 JavaScript 约束。 应尽可能在 GPD 或 PPD 文件中指定功能和选项,并且只应在 JavaScript 中表示复杂的约束。

调试 JavaScript 文件

通过在基于 Windows 的脚本主机中打开 JavaScript 文件,支持 JavaScript 文件的基本语法验证。 为此,请右键单击 JavaScript 文件,并选择打开方式,然后在列表中选择基于 Windows 的脚本主机条目。 如果未引发错误,则 JavaScript 在语法上有效。 否则,它将指出问题的行号,如以下屏幕截图所示。

javascript 语法错误对话框。

公开提供的 JavaScript 验证工具在评估 JavaScript 文件的风格方面也很有价值。

可以通过创建以下注册表项来启用交互式调试:

键名:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print

值名:EnableJavaScriptDebugging

类型:DWORD

值:1

但是,由于经常加载和卸载 PrintConfig.dll,因此调试打印的应用不是建议的测试/调试策略。 相反,Microsoft 建议制造商生成一个测试应用,使用以下公共 API 调用 JavaScript 约束的每个相关入口点:PTGetPrintCapabilitiesPTConvertDevModeToPrintTicketPTConvertPrintTicketToDevModePTMergeAndValidatePrintTicket

仅测试应用就足以启用调试,但添加单元测试以确保整个驱动程序按预期处理 PrintTicket、PrintCapabilities 和约束也是有益的。 有关如何在 Visual Studio 中生成单元测试的详细信息,请参阅以下主题:

Visual Studio Team Test 的单元测试演练

创建上述文本中显示的注册表项并重新启动托管进程后,可以调试 JavaScript 源文件。

值得注意的是,如果源文件解析失败,则不会调用调试器,调试环境似乎也失败了。 如果源文件解析失败,请参阅 Windows 脚本主机,以获取有关如何继续操作的详细信息。

如果没有错误并且源文件解析成功,请按如下方式调试源文件:

  1. 在测试计算机上安装 Microsoft Visual Studio 2012 或更高版本

  2. 使用具有约束 JavaScript 代码的驱动程序创建打印队列

  3. 将此打印队列设置为默认值。

  4. 启动测试应用程序或打印应用,并开始一个将导致 JavaScript 约束被调用的方案。 应用必须调用 PrintTicket/PrintCapabilities API 才能突破 JavaScript 约束;像记事本这样的旧应用程序不会调用这些 API,但 XPS 查看器应用会调用。 Microsoft 建议在此处使用测试应用,因为可以更轻松地隔离和重现这些方案。

  5. 此时,“Visual Studio 实时调试器”将弹出,指出“<应用>中发生了未经处理的异常”

  6. 启动 Visual Studio 2012 或更高版本的新实例

  7. 选择“调试”,然后选择“附加到进程”

  8. 在“附加到进程”对话框中,确保“附加到:”设置为脚本代码

  9. 现在选择测试应用或应用打印,最后选择“附加”

  10. 单击“全部中断”

  11. 现在返回到“Visual Studio 实时调试器”对话框,然后单击“否”

  12. Visual Studio 将在当前测试调用的位置进入调试器。 现在可以正常调试代码。

JavaScript 约束 API

本节指定了在 JavaScript 约束文件中用作 API 入口点的函数。 以下是函数:

  • validatePrintTicket

  • completePrintCapabilities

  • convertDevModeToPrintTicket

  • convertPrintTicketToDevMode

validatePrintTicket 函数

调用此 API 是为了验证 PrintTicket 对象对特定打印机是否有效。 这在功能上类似于 IPrintOemPrintTicketProvider::ValidatePrintTicket API。

validatePrintTicket 语法

function validatePrintTicket(printTicket, scriptContext)

validatePrintTicket 参数

validatePrintTicket 返回值

返回值 说明
0 指示 printTicket 参数无效,无法更正。 等效于 E_PRINTTICKET_FORMAT
1 指示 printTicket 参数是此打印机的有效 PrintTicket。 等效于 S_PT_NO_CONFLICT
2 表示已修改 printTicket 参数使其有效。 等效于 S_PT_CONFLICT_RESOLVED

completePrintCapabilities 函数

调用此 API 是为了允许修改 PrintCapabilities 对象。 这应用于条件功能(例如,仅在照片纸上支持无边框)或表示无法由 GPD 或 PPD 文件(例如嵌套功能定义)生成的功能。 这在功能上类似于 IPrintOemPrintTicketProvider::CompletePrintCapabilities API。

completePrintCapabilities 语法

function completePrintCapabilities(printTicket, scriptContext, printCapabilities)

completePrintCapabilities 参数

  • printTicket

    [in] IPrintSchemaTicket 对象输入,以限制生成的 PrintCapabilities 文档。

  • scriptContext

    [in] IPrinterScriptContext 对象,提供对驱动程序属性包、队列属性包和用户属性包的访问。

  • printCapabilities

    [in][out] IPrintSchemaCapabilities 对象,表示由配置模块生成的基本 PrintCapabilities 对象。

completePrintCapabilities 返回值

无。

convertDevModeToPrintTicket 函数

调用此 API 是为了将 DEVMODE 属性包中的值转换为 PrintTicket。 这在功能上类似于 IPrintOemPrintTicketProvider::ConvertDevModeToPrintTicket API;只是此实现将 DEVMODE 的私有部分封装到 IPrinterScriptablePropertyBag 对象中,并且不允许访问 DEVMODE 的公共部分。

convertDevModeToPrintTicket 语法

function convertDevModeToPrintTicket(devModeProperties, scriptContext, printTicket)

convertDevModeToPrintTicket 参数

  • devModeProperties

[in] IPrinterScriptablePropertyBag 对象,表示 DEVMODE 属性包。

  • scriptContext

    [in] IPrinterScriptContext 对象,提供对驱动程序属性包、队列属性包和用户属性包的访问。

  • printTicket

    [in][out] IPrintSchemaTicket 对象,表示 PrintTicket。

convertDevModeToPrintTicket 返回值

无。

convertPrintTicketToDevMode 函数

调用此 API 是为了将 PrintTicket 中的值转换为 DEVMODE 属性包。 这在功能上类似于 IPrintOemPrintTicketProvider::ConvertPrintTicketToDevMode API;只是此实现将 DEVMODE 的私有部分封装到 IPrinterScriptablePropertyBag 对象中,并且不允许访问 DEVMODE 的公共部分。

convertPrintTicketToDevMode 语法

function convertPrintTicketToDevMode(printTicket, scriptContext, devModeProperties)

convertPrintTicketToDevMode 参数

  • printTicket

    [in] IPrintSchemaTicket 对象,表示要转换的对象。

  • scriptContext

    [in] IPrinterScriptContext 对象,提供对驱动程序属性包、队列属性包和用户属性包的访问。

  • devModeProperties

    [in][out] IPrinterScriptablePropertyBag 对象,表示 DEVMODE 属性包。

convertPrintTicketToDevMode 返回值

无。

约束最佳做法

Windows 8 打印对话框和打印首选项体验仅支持打印架构关键字命名空间的一个子集。 因此,Microsoft 不建议在 Windows 8 打印对话框支持的功能或打印首选项 UI 中支持的功能与该 UI 中不支持的功能之间使用约束,因为用户将没有机会解决这些约束。

例如,如果名为 Photo 的 PageMediaType 选项仅限于使用 1200dpi 的 PageResolution 值,则用户将永远无法选择照片媒体类型。 在这种情况下,最好符合用户的意图(照片媒体),并调整任何必要的设置来实现这一点。 这些调整可以在 JavaScript 约束代码中进行。

如果驱动程序不使用 JavaScript 约束,则不需要提供文件。 如果一个驱动程序只对一部分入口点(例如,validatePrintTicket)使用 JavaScript 约束,则应该完全从 JavaScript 文件中省略其他入口点。