渲染打印作业

重要

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

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

打印作业要么在创建时渲染,要么作为 EMF 记录写入后台打印文件。 对于 EMF 记录,当 EMF 打印处理器 (localspl.dll) 播放记录时,会进行渲染。 渲染由对用户模式 GDI 绘图函数的一系列调用组成,从 CreateDC 开始。 对 CreateDC 的调用是一系列应用程序调用中的第一个,这些调用会导致涉及图形渲染引擎(GRE,也称为内核模式 GDI)和打印机图形 DLL 的一系列操作。

下图显示了调用 CreateDC 后内核模式 GDI 与打印机图形 DLL 之间的交互。

说明调用 createdc 后内核模式 gdi 与打印机图形 dll 之间的交互的关系图。

  1. 当应用程序调用 CreateDC 函数来创建打印机设备上下文时,GDI 会检查是否加载了相应的打印机图形 DLL。 如果不是,GDI 将加载 DLL,并调用 DLL 中的 DrvEnableDriver 函数。 除非重新加载驱动程序,否则不会再次调用该函数。

  2. 接下来,GDI 调用打印机图形 DLL 的 DrvEnablePDEV 函数,以便驱动程序可以创建物理设备实例并返回设备特征。 GDI 使用返回的信息创建设备实例的内部说明。

  3. 然后,GDI 调用图形 DLL 的 DrvCompletePDEV 函数,为设备实例提供 GDI 句柄。 图形 DLL 必须使用此句柄作为 GDI 绘图引擎提供的一些 Eng 前缀回调的输入(请参阅 GDI 支持服务)。

  4. GDI 收到设备实例句柄后,会调用图形 DLL 的 DrvEnableSurface 函数,该函数设置绘图图面,并将其与物理设备实例相关联。

  5. 驱动程序可以通过调用 EngCreateBitmap 为设备实例创建绘图图面。 或者,如果绘图图面是设备管理的,驱动程序可以调用 EngCreateDeviceSurface

  6. 如果 EngCreateBitmap 无法提供足够大的位图来包含整个物理页,并且如果驱动程序支持页面条带,则可以调用 EngMarkBandingSurface 来通知 GDI 将采用条带。

  7. 最后,必须调用 EngAssociateSurface 以允许 GDI 将创建的图面与指定的设备实例相关联,并让 GDI 知道在绘制此特定图面时应调用哪个驱动程序提供的图形 DDI 绘图函数(如果有的话)。

此时,已经创建了一个绘图图面,可以开始渲染了。 GDI 调用的函数取决于条带是否有效。

正在使用的条带

对于使用条带时要渲染的每个文档,GDI 在打印机图形 DLL 中调用以下函数:

DrvStartDoc

适用于每个物理页面

DrvStartPage

DrvStartBanding

适用于物理页上的每个条带传递

DrvQueryPerBandInfo

呈现操作

DrvNextBand // 发送此波段的光栅数据,然后清除表面以在下一波段中重复使用

DrvEndDoc

未使用的条带

对于不使用条带时要渲染的每个文档,GDI 在打印机图形 DLL 中调用以下函数:

DrvStartDoc

适用于每个物理页面

DrvStartPage

呈现操作

DrvSendPage // 发送页面的光栅数据

DrvEndDoc

除了 DrvQueryPerBandInfo 之外,这些函数旨在允许打印机图形 DLL 向打印机硬件发送控制序列(通过调用 EngWritePrinter),并执行初始化或完成文档、页面或带处理所需的任何内部操作。

打印机图形 DLL 负责在适当的时间(通过调用 EngWritePrinter)将渲染图像(即绘图图面的内容)发送到打印机,如下所示:

  • 适用于 GDI 托管或设备管理的位图图面

    绘图图面是 GDI 提供的或驱动程序提供的位图。 打印机图形 DLL 可能会挂钩某些绘图函数(请参阅图面协商)。 如果使用页面条带,DrvNextBand 函数应发送绘图图面内容。 如果未使用条带,则 DrvSendPage 函数应发送绘图图面内容。

  • 适用于设备管理的矢量图面

    绘图图面位于设备内。 打印机图形 DLL 挂钩所有绘图函数(请参阅曲面协商),这些函数在渲染操作期间将图像数据发送到打印机。 不使用页面条带。

如果预计打印机图形 DLL 提供的任何图形 DDI 函数可能需要五秒钟以上的时间才能执行,则应至少每五秒钟包含一次调用 EngCheckAbort 的代码,以查看是否应终止打印作业。

GDI 调用 DrvEndDoc 以指示文档已完全渲染后,它会调用 DrvDisableSurface。 如果 DrvEnableSurface 调用了 EngCreateBitmap,那么 DrvDisableSurface 必须调用 EngDeleteSurface

当应用程序调用 DeleteDC 时,GDI 调用打印机图形 DLL 的 DrvDisablePDEV 函数。

如果应用程序在打印文档期间调用 ResetDC 函数,GDI 将创建一个新的设备上下文,并为新上下文调用打印机图形 DLL 的 DrvEnablePDEV 函数。 然后,GDI 调用 DrvResetPDEV 函数,这样图形 DLL 就可以用旧上下文中的信息更新新上下文。 接下来,对于旧上下文,调用 DrvDisableSurfaceDrvDisablePDEV;对于新上下文,调用 DrvEnableSurface。 最后,GDI 调用 DrvStartDoc,并在新页面上恢复渲染。

GDI 在卸载打印机图形 DLL 之前调用 DrvDisableDriver

如果打印机硬件支持 GDI 绘图函数不支持的绘图操作,打印机图形 DLL 可以提供 DrvDrawEscape 函数。

如果需要支持 GDI 函数无法提供的绘图或非绘图操作,打印机图形 DLL 可以提供 DrvEscape 函数。 例如,Microsoft PostScript 打印机驱动程序使用转义来支持 PostScript 注入点。 或者,应用程序可能需要获取传真机的电话号码。 DrvEscape 函数还用于指示 DrvDrawEscape 函数支持的操作。