虚拟打印机 ecgprint 阅读笔记
Windows 打印体系结构以打印池为中心,打印机图形 dll 的打印接口是打印驱动程序的
一部分,打印的流程如下:1.应用程序通知打印池开始一个新的打印任务;2.打印池调用打
印接口 dll,显示打印对话框,并将打印设置信息传给它;3.应用程序调用 GDI 进行绘图操作;
4.GDI 将应用程序的绘图调用保存在 EMF 文件中,记录完毕将之发送给打印池;5.GDI 返回,
应用程序完成一次假脱机打印过程,可以进行其他任务;6.打印池调用 GDI,把 EMF 文件中
的绘图命令一条条分解到打印机上下文中;7.GDI 通过系统调用,调用 GDI 引擎实现绘图操
作;8.GDI 引擎将 GDI 绘图命令分解组合,在打印机图形 dll 的帮助下,完成各种图形的绘制;
9.打印机图形 dll 将绘图解码后的数据发往打印池;10.打印池把打印机数据发往打印机。
实际上开发虚拟打印机过程就是设计第 8 步的 GDI 引擎中的图形绘制命令。GDI 引擎和
图形设备之间的接口叫做 Device Driver Interface(DDI),DDI 函数都有 Drv 前缀,共有 89 个,
其中 GDI 引擎和打印机图形 dll 之间的 DDI 函数可以分成 3 部分,即初始化函数,文档和页
面控制函数以及图形绘制函数(表面钩子函数)。
开始打印前要对打印机进行初始化:
DrvEnableDriver 是打印机图形 dll 的入口点,相当于一般 dll 的 dllMain,当 GDI 引擎加
载打印机图形 dll 时要先调用这个函数,它负责分配资源和初始化内部变量。Ecgprint 中为
OEMEnableDriver 函数,在此函数中钩入钩子函数(如 OEMTextOut,OEMStartDoc,
OEMEndDoc 等)。
DrvEnablePDEV 是很重要的函数,它负责分配驱动程序定义的 PDEV(物理设
备)结构实例。其中有两个结构非常重要:一个是 GDIINFO 结构,这个结构设置
设备分辨率、物理大小、颜色格式等信息;另一个是 DEVINFO 结构,描述驱动程
序图形能力、缺省字体、设备字体数量和抖动格式等。Ecgprint 中为 OEMEnablePDEV
函数,在此函数中没有设置这两个结构,不知为什么?
DrvEnablePDEV 成功返回后,即表示该打印机设备已初始化,随后 GDI 引擎
调用 DrvCompletePDEV 来给物理设备准备使用的信号。
在 GDI 引擎能够实际开始绘画之前,必须在 DrvEnableSurface 中提供一个
绘图表面。这个表面既可以是 GDI 引擎管理的位图表面(用 EngCreateBitmap
创建),即 DIB,也可以用 EngCreateDeviceSurface 创建设备管理的位图表面,
即 DDB。Ecgprint 中没有实现此函数。
当使用标准 DIB 时,驱动程序可以让 GDI 引擎完成所有的绘制工作而不必钩
入任何函数;否则就要提供自己的实现,除了几个基本实现的基本钩子,其他的
都可以交给 GDI 引擎处理。
为了完成文档打印,需要实现以下文档和页面控制函数以及表面钩子函数:
表 1 需要实现的函数
DDI 函数
DrvStartDoc
DrvEndDoc
DrvStartPage
DrvSendPage
DrvAlphaBlend
DrvBitBlt
DrvCopyBits
DrvFillPath
DrvGradientFill
DrvLineTo
DrvNextBand
DrvPlgBlt
DrvStretchBlt
DrvStrokePath
意义
Ecgprint 中对应的函数
OEMStartDoc
OEMEndDoc
开始打印时调用
结束打印时调用
开始打印一个物理页时调用 OEMStartPage
打印完一个物理页后调用
OEMSendPage
以下在打印每个物理页是根据实际情况调用
实现位块透明度
实现位块数据传输
复制位图
填充闭合路径
绘制阴影
划线
在一个物理页绘制完一段后
调用
旋转位块
缩放位块
用画笔绘制 Path
可选函数,没有实现
OEMBitBlt
可选函数,没有实现
可选函数,没有实现
可选函数,没有实现
可选函数,没有实现
OEMNextBand
可选函数,没有实现
OEMStretchBlt
OEMStrokePath
DrvTextOut
绘制文字
OEMTextOut