需求

从需求出发,我们的目的是在电脑上提供一个虚拟打印机,然后让用户选择这个虚拟机打印时产生的中间文件被拦截下来,之后进行进一步处理后在执行真实的打印。

Windows打印体系

首先附上查找Windows打印相关内容的链接,这个分类下包含了Windows打印的方方面面

https://msdn.microsoft.com/en-us/library/windows/hardware/ff561035(v=vs.85).aspx

Windows2000以后的打印体系结构都是由一个打印机假脱机程序(Spooler)和一系列的打印驱动组成。应用程序通过调用设备无关的函数,就能创建打印任务,并发送到打印设备中。包括激光打印机、矢量绘图机、光栅打印机和传真机。

其中打印驱动包括一个渲染组件和一个配置组件。

渲染组件负责将应用程序传来的每一页的绘制命令(GDI命令)转换成打印机用来渲染的命令数据(打印机才能识别的命令)发送到打印机中。

配置组件又包含一个可以让用户进行打选项配置的用户接口组件和一个将打印机的配置和特征传递给应用程序的程序接口。

当GDI程序执行打印时,通过调用API来传递GDI绘图指令到绘图引擎,绘图引擎要么和打印驱动一起合作来缓存这些绘制指定到一个EMF文件中,要么直接渲染成一个可打印的图片发送到spooler中。Spooler解释EMF文件,并将页面布局和作业控制指令信息插入到数据流中,然后发送这些数据里到序列化、并行化或者网络形式的打印机关联的端口上。(XPS设备会有一点不同,这里不进行介绍)。

由于Spooler和打印驱动都是可以被单独取代,所以硬件厂商们可以很容易的增加对新硬件的支持。当需要增加对新款打印机的支持时,通常只需要创建根据微软所提供的打印驱动类型中相关联的数据类型就可以了。

下图是Windows提供的内置打印驱动程序:

 

大致了解了Windows打印体系组成之后,来分别看一下Spooler和打印驱动。

Spooler

从Windows2000开始,打印假脱机程序由一系列的微软提供的和可选的渲染组件组成,他们的作用包括:

1、检测是否打印任务是在本地处理还是跨网络处理。

2、接受GDI和打印驱动为特定类型的打印机所提供的数据流。

3、缓冲绘制数据到文件中。

4、从逻辑打印队列中选出第一个有效的物理打印机。

5、将缓冲的数据流(如EMF)转换成能呗打印机硬件所识别的格式(如PCL)。

6、发送打印数据流到打印机硬件中。

7、为假脱机组件和打印机的相关信息维护一个基于注册表的数据库

 

Spooler主要组成结构如下图所示:

Application通过调用GDI函数来创建打印任务,通过调用Winspool.drv提供的API接口,将打印内容路由到PrintProvider中。

PrintProvider负责管理本地打印和远程打印,同时要管理打印任务堆里的启动、停止和枚举打印队列。

我们这里只讨论本地打印流程,它提供了下面的能力:

1、打印任务缓冲和解析到打印队列

2、为Win2000以后的操作系统的打印驱动体系提供支持。

3、为厂商提供的打印处理器的提供支持

4、为场上提供的打印监视器的提供支持

下图提供了本地打印任务处理流程:

如图所示,应用程序通过GDI接口创建打印任务后,不管是否需要输出为EMF,本地的PrintProvider任务创建API都会创建一个spool文件。然后,当任务被调度的时候,通过读取这个spool文件,如果是EMF格式的话,就让EMF打印处理器配合打印机的渲染驱动,将打印任务发送回去给GDI转换成RAW格式,最后和没有使用EMF格式的任务一样,将数据流传递到端口监视器中执行最终打印。

我们通过定制自己的打印机,让整个打印流程走如上图中红线描述的路径,在打印处理器这一层拦截spool文件及其相关打印信息,来保留整个打印任务的相关数据,等待后续进行处理。

Printer Driver

Windows提供了三种类型的打印驱动,分别为:Universal Printer Driver、PostScript Printer Driver、Plotter Driver。原则上来说这三种类型的驱动已经能支持大多数打印机了,我们只需要简单的为新的打印机提供对应驱动的DataFile即可。我们这里只讨论Universal Printer Driver。

Universal Printer Driver由三部分组成:

1、Printer Graphics DLL: 负责和GDI一起渲染打印任务,并发送渲染数据流到打印假脱机程序中。

2、Printer Interface DLL: 提供打印机参数配置接口和假脱机能调用的用于通知打印系统事件的接口。

3、Printer Data Files:对于Universal Printer Driver而言,这个数据文件就是GPD文件,它用于创建UnidrvMiniDrivers,主要用于描述打印机的可选项配置。包括打印机属性、相关命令、特征、可选项、字体描述、环境状态等。

上面三个模块对应的就是下图中红色矩形框住的部分。

由于我们不需要对打印渲染和用户接口做过多的定制,只需要使用标准的Windows打印首选项对话框,所以无需自定义渲染插件和用户接口插件。当然如果需要的话,也是能在https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff547298(v=vs.85).aspx中找到这些插件重定义的方式。

根据需求,我们只需要自己定制GPD文件,来实现对系统标准的打印机首选项对话框相关设置的定制。(这种方式应该就是UnidrvMiniDrivers)。

解决方案

综上所述,我们的虚拟打印机要自己定制的模块就只有打印处理器和GPD文件。

打印处理器负责拦截打印生成的中间文件,GPD文件负责定制打印可选项。

打印处理器定制文档:https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff563807(v=vs.85).aspx

GPD文件说明文档:https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff551750(v=vs.85).aspx

打印处理器

WDK提供了支持相关示例,我们在这个示例的基础上直接更改,主要要更改的地方是在winprint.cpp中,PrintDocumentOnPrintProcessor函数的实现中。我们可以看到打印处理器对一个打印任务的处理流程如下:

由于我们这里的目的是拦截打印任务产生的中间文件保存下来,所以只需要调用GDI Functions in Print Processors,缓存好spool文件后直接返回(阻止传递数据流到spooler中去)。

GPD文件

前面介绍了,GPD文件是使用GPD语言去描述一台打印机,也就是说GPD文件有自己固定的格式,对应GPD语言也有固定的语法,其中主要包括下列信息:

1、Printer attributes: 描述打印机特征

2、Printer commands: 用于控制打印机的操作

3、Printer features: 描述能被通用打印驱动所控制的能力

4、Printer options: 呈现能用来设置Printer features值的状态。

5、Printer font descriptions :描述和硬件相关连的字体

6、Conditional statements: 描述Printer attributes 和 打印机的配置之间的依赖关系。

此外,GPD语言也定义了一些用来控制一些操作的GPD文件设置,这种操作我们暂不需要。

 

根据上面的描述,要完全自定义一个GPD文件相对来说是比较困难的,这里我们可以通过参考其他打印机中有使用GPD文件的部分,或者参考WDK目录下\src\print\mini中的GPD文件示例。然后根据需要去修改相应的部分更加简单。

我这里只对自己所理解的部分进行阐述,更详细的信息请参考MSDN。

首先GPD文件中最基本的值设置格式Entries,其格式为:

其中的EntryName都是GPD解析器预定义好的关键字(不然GPD解析器无法识别你写这么个关键字是要做什么),而EntryValue则只能是GPD所支持的值类型中的一种(不然GPD解析器无法判断你这个关键字对应的内容正不正确)。关于类型,请自行参考https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff550568(v=vs.85).aspx

 

下面拿我们的GPD文件作为参考进行描述。


如图所示,对于这种*AttributeName:AttributeValue格式的文本,都是前面描述的Printer Attribute,其中放在文件头部,又更细分为Root-Level-Only Attributes,其各部分含义可参见https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff561989(v=vs.85).aspx


如图所示,上面*%的部分都是注释,后面的Attribute,则是细分在Printer Capability Attributes下的一些属性,详细描述参见https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff560780(v=vs.85).aspx


 

如图所示,形如*Command:CommandName{CommandAttributes}的内容,则属于Printer Commands。前面描述过这类型是用于控制打印机的操作,其中CommandName都是预定义的命令名,具体这些命令名称的含义,参见https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff546117(v=vs.85).aspx中各类别的描述。


如图所示,形如*Feature:FeatureName{FeatureAttributes}的内容,描述的便是我们打印机所提供的打印选项功能。Feature又分为标准类型和自定义类型,当然我们只需要提供标准的特征,所支持的标准特种参见https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff562697(v=vs.85).aspx,如截图中所示即为标准特征中允许选择纸张方向的特征,这里不仅仅描述了这个特征的说明,而且描述了这个特征是不是必须的和支不支持自定义选项。

需要说明的是*rcNameID这个属性段,表述的是对应特征(或者可选项)显示在界面上的内容的ID,MSDN上也描述了可以使用*Name来直接指定内容。但是我们不需要自己指定。Unidrv驱动提供的stdname.gpd中包含了标准特征显示的文本的ID,我们只需要引用其中的就可以的。


另外补充说明一下上面Feature中的Option,前面描述了Option对应的其实是Feature可以设置的选项的描述,对应的每一个选项也有固定的格式,可以参见https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff559622(v=vs.85).aspx

对应上面Feature描述的界面效果如下:

类似的对应的*Feature:PaperSize产生的界面效果如下:


至此,关于GPD文件的描述就结束了。具体需要添加某项特征选项时,可在MSDN上找到对应选项的关键字段,然后根据描述设置相应的属性即可。

参考资料

打印处理器缓冲spool文件相关资料http://www.undocprint.org/winspool/spool_files

Windows打印管理解决方案的更多相关文章

  1. sap后台作业管理/sap打印管理

    sap后台作业管理: 后台作业,主要用于运行需要处理大量数据,对交互没有要求的程序.个人认为,简单的创建,配置和监控后台作业没有什么难度.后台作业管理最为困难的解决方案的取舍,系统负载的调控.失控的后 ...

  2. Windows打印体系结构之Print Spooler概念与架构

    Windows打印体系结构之Print Spooler概念与架构Windows 思杰之路(陶菘) · 2016-09-06 22:07 房子好不好,对我而言始终都是肉体的栖居.对于灵魂,我从来不知道该 ...

  3. EasyDSS流媒体视频实时回传与录像管理解决方案

    一.背景 1.1 方案背景 随着互联网基础设施建设的不断完善和发展,带宽的不断提速,尤其是光纤入户,4G/5G/NB-IoT各种技术的大规模商用,视频在各行各业越来越受到重视,无论是传统的视频媒体转向 ...

  4. Kong:Nginx支持的API Gateway管理解决方案

    Kong的主要功能 Kong可灵活扩展:只要增添更多的服务器实例,它就能横向扩展,毫无问题,那样你可以支持更多流量,同时确保网络延迟很短. Kong可在任何地方运行:它可以部署在单个或多个数据中心环境 ...

  5. 20140919 进程间通信 系统栈 用户栈 多级反馈队列 windows 内存管理

    1.进程间通信 共享内存(剪切板) 匿名管道只能实现父子进程间的通信(以文件系统为基础): 匿名管道是什么,有什么用,怎么用 1.创建父进程,也就是在解决方案中建立一个parent的工程 2.在par ...

  6. BPM合同管理解决方案分享

    一.方案概述合同是组织与组织间所订协议的法律 表现形式,体现着双方对于合作在法律和道德上的承诺.然而,大多数企业的合同管理都或多或少存在合同审批过程不规范.签订草率.审批权责不清.合同执行跟踪难.合同 ...

  7. BPM公文管理解决方案分享

    一.方案概述 公文作为一种规范性文书,具有法律性.指导性.政令性强的特点,是企事业单位政令上通下达的重要方式.及时.准确.安全地处理.控制和管理公文,方能保障企事业单位正常运转,确保组织权威和政令畅通 ...

  8. Session管理解决方案笔记

    大型网站Session管理解决方案: 1. web服务器之间的session复制.    优点:方案成熟    缺点:复制的性能开销大 2. 减少session使用,使用客户端存储cookie     ...

  9. 无法从命令行或调试器启动服务,必须首先安装Windows服务(使用installutil.exe),然后用ServerExplorer、Windows服务器管理工具或NET START命令启动它

    无法从命令行或调试器启动服务,必须首先安装Windows服务(使用installutil.exe),然后用ServerExplorer.Windows服务器管理工具或NET START命令启动它 1. ...

随机推荐

  1. Linux 下Mysql自动备份脚本

    backdb.sh 文件 #!/bin/bash USER="root" PASSWORD="888888" DATABASE="mydb" ...

  2. 9.2noip模拟试题

      题目名称 改造二叉树 数字对 交换 英文名称 binary pair swap 输入文件名 binary.in pair.in swap.in 输出文件名 binary.out pair.out ...

  3. codevs 2612 最有分解方案 (贪心)

    /* 数字不重复 将一个正整数分解成若干的整数的和 数字不重复 且数字不相同 保证不重复的话 贪心策略是从2开始分 然后把最后剩下的数均匀分到后面 证明嘛 这里写的可能不是很严谨 对于一个n 如果我们 ...

  4. C#解leetcode:119. Pascal's Triangle II

    题目是: Given an index k, return the kth row of the Pascal's triangle. For example, given k = 3,Return  ...

  5. Word 查找替换,通配符一览表

    Word查找替换详细用法及通配符一览表 使用通配符要查找“?”或者“*”,可输入“\?”和“\*”,\1\2\3依次匹配数对括号内容查找(a)12(b)   替换\2XY\1   结果:bXYa ([ ...

  6. 3xian之所在

    最后一天,漫天飘起了雪花,假装欢送我离去. 这次WF之战不太顺利,早期的C题大概花了1秒钟构思,然而由于输出格式多了一个空格直到两个半小时才逃脱Wrong Answer的纠缠.还好lynncui在期间 ...

  7. angularjs项目中关于服务的应用

    /** *普通ajax请求公共服务 */ mainModule.factory('myService',function($http,$q){ var service = {}; var baseUr ...

  8. phonegap 2.8.1 toast

    目录结构如下: 以上三个用红色框勾出的地方是需要修改的文件夹. 首先:添加java代码. 在src目录下新建一个包裹:org.apache.cordova 在该包裹下新建类:ToastPlugin.j ...

  9. javascript 获取用户光标,插入文本

    图1 如图1所示,点击[函数名称],将函数名称添加到表达式内容框中,点击参数名称,将参数名称index1作为方法的参数添加到表达式内容中的表达式中. 该功能实现主要是采用了javascript获取鼠标 ...

  10. OpenGL ES 3.0 顶点缓冲区VBO使用

    一般情况下数据都是有CPU从RAM取数据 然后传给GPU去处理,相对于GPU速度要慢一些. 使用VBO技术 可以把数据存储到GPU的内存空间中,这样GPU可以直接从GPU的内存中取得数据进行处理 速度 ...