admin管理员组

文章数量:1536088


2024年6月17日发(作者:)

EM F虚拟打印机的实现 

张生生 

(福建实达电脑设备有限公司福建福州350002) 

【摘要】:本文简单分析了Windows(Win2000及之后的)操作系统的打印驱动程序的架构,并介 

绍了一种利用其spooler组件中的processor实现EMF虚拟打印机的方法。 

【关键词】:虚拟打印机EMF Spooler组件Processor 

1.引言 

Provider几个部分构成。Winspoo1.dry(含)之前部分是 

2.1 GDI——Windows图形用户接口。 

随着应用软件的不断发展,各种新的需求不断出 

客户端,之后的为服务端。 

现,很多时候需要将各种文档转换成特定的格式。虚 

拟打印机应此而生。虚拟打印机的本质就是实现文档 

应用程序调用此接口的绘图函数,再通过这些函 

类型转换,对于这种程序的制作者,他无需了解各种 数调用图形渲染引擎(GRE),配合调用打印机图形驱 

被转换文档的内在格式,降低了实现难度;而对于使 动库,实现最终打印图像。 

用者,它是一款打印机,在各种有打印功能的文档查 

看软件中很容易操作。 

2.2打印机图形驱动DLL 、 

完成特定的图形渲染,是GDI的一个补充。由打 

EMF是Windows NT以后的操作系统支持的一种 印机生产商提供,其实现根据各种打印机的特性而不 

 

矢量图形文件,由于其数据量小的特点,应用也很广 

同。

泛。 

2.3 Winspoo1.dnr——Win32 spooler客户端,提供 

EMF虚拟打印机即是一款将文档转换为EMF格 

API与应用程序交互。 

式文件的打印机。 

2.打印机驱动架构(GDI、Spooler) 

主要功能:查询打印机、打印作业,查询、修改打 

印机设置,显示打印机设置属性页(调用打印机驱动1 

等等。 

Windows打印驱动的架构略图如下: 

主要函数有OpenPrinter WritePrinter ClosePrinter 

等。 

2.4 Spoolsv.exe——sp0oler服务程序。通过RPC 

与其客户端交互。 

大部分调用通过Router转发到Provider,由 

Provider实现。 

2.5 Spoolss.dll——Router。 

主要功能:通过打印机名称/打印机句柄(来自于 

打印作业)、打印机设置(来自于注册表),找到正确的 

provider,转发打印作业。 

应用程序调用spooler客户端的OpenPrinter,通 

过spooler服务程序,调用被传到Router,然后Router 

调用所有Provider的OpenPrinter,直到找到一个名称 

符合的打印机,返回句柄以完成后续打印工作。 

Windows打印机驱动程序是一个C/S架构,在更 

小的范围内,Spooler组件也是一个C/S结构。Spooler 

组件

(Spooler组件的以上三个部分不可定制。) 

2.6 Print Provider 

由Winspoo1.srv、Spoolsv.exe、Spoolss.dll、Print 

Provider由打印机生产商提供,包含以下几个部 

154・ 福建电脑j 20l3年第6期 

IA 

t 

typedef struct tagEMR 

分,各部分可以定制。 

2.6.1 localsp1.dll——本地打印机上的作业管理、 

调度。 

{ 

DWORDiType;//EMR类型,宏定义为EMR_XXX 

DWORDnSize;//EMR大小,单位为字节 

l EMR; 

在此创建Spool文件。Spool文件有Raw、Text、 

EMF格式。通常为EMF格式,数据量小,可以快速完 

2.6.2节中介绍了spool文件,通常这种文件是NT 

成缓存(使控制返回到应用程序),也便于网络打印的 

EMF格式文件。NT EMF格式一般有几个固定的数据 

传输。 

段,每个数据段都是EMR结构。 

实际上Spool文件的内容是由GDI完成的,可能 

NT EMF格式文件会按顺序出现以下几个数据段 

有打印机图形驱动的配合。 

2.6.2 Drocesso广__把打印作业的spool文件转换 

为可被打印机接受的Raw格式。 

实现打印作业暂停、恢复、取消。 

Raw格式spool文件通过WritePrinter直接发给 

打印机;Text格式调用StartDoc,把GDI命令发给打印 

机驱动;EMF格式通过GdiEndPageEMF调用GDI的 

EMFPlayBack机制把各种绘图命令传给打印机驱动, 

打印成Raw格式,再通过WritePrinter发给打印机。 

EMF格式Spool文件成对出现,后缀为.shd的文 

件包含打印作业的设置信息,如打印机名称、文档名 

称、端口名,以及DEVMODE拷贝;后缀为.sp1的文件 

被称为NT EMF文件,包含一个文件头,一些内嵌字 

体(可以没有),以及对应文档各页面的标准EMF页 

面。 

Spool文件经过processor的处理后传回给GDI处 

理,生产最终的打印机可处理的文件。 

2.6_3 monito广一监视器,可以修改数据内容及流 

向。 

包括Language monitor和Port monitor两种。前者 

是Spooler和打印机之间的全双工通讯通道,可以获 

取打印机信息(调用DeviceIoContro1),反馈给Spooler、 

驱动、应用程序,可以修改Raw数据。后者是Spooler 

与核心态端口驱动的通讯通道,管理与设置服务器打 

印端口,可以实现打印端口重定向。具体实现时两者 

可以合并为一个。 

3.EMF和Spool文件 

EMF(Enhanced MetaFile)是WMF(Windows—format 

MetaFile)的升级,实现了真正意义上的设备无关性,且 

可以应用于32位操作系统。 

之所以被称为“元文件(metafile1 99 9是因为它是由 

系列“元文件记录”构成的。“元文件记录”是一种变 

长的结构。大部分这种结构对应各种GDI指令。该结 

构通常都是以EMR结构作为第一个成员。EMR结构 

的定义为: 

(只列出EMR类型): 

11 iType=0x100OO—NT EMF文件标志 

2)[iType=0,2,3—0xFFFF]——可选的说明性数据 

段,其值若为2,表示该段为嵌入字体 

31 iType=OxOC——标准EMF文档起始标志,i— 

Size该EMF文档的大小 

41标准EMF文档结构(可以从MSDN上找到其 

详细描述) 

51 iType=o】【80000O 标准EMF文档结束标志 

6).…・・(若有多页内容,重复3、4、5段内容) 

通常,processor对此类spool文件的处理只是完 

成比如缩放、合页(N—up)、小册子(booklet)打印样式等 

等的逻辑处理,然后通过GdiEndPageEMF函数调用 

GDI的EMFPlayBack机制把各种绘图命令传给打印 

机驱动,打印成Raw格式,再通过WritePrinter函数发 

送给打印机。 

4.虚拟打印机可采取的设计方案 

从第2节介绍的内容可以看出,要设计虚拟打印 

机可以从两处着手: 

其一,自定义打印机图形驱动库,将打印内容处 

理成需要的文档格式。 

其二,自定义Spooler组件,在processor中截取 

spool文件内容,转换成需要的文档格式,或者在moni— 

tor中修改数据内容,转换成需要的文档格式。 

5.定制processor实现EMF虚拟打印机 

从前面的介绍中可以知道,spool文件的内容基本 

都是NT EMF格式,这种格式是EMF格式的一个再 

包装。因此从spool文件中截取EMF内容,另存为 

EMF文件是简单、快速实现EMF虚拟打印机的一种 

方式。即我们需要定制processor。 

5.1 Processor的函数 

定制一个processor,必须实现并导出几个函数 

(详细说明可以查看DDK帮助文件): 

HANDLE OpenPrintProcessor( 

LPWSTR pPrinterName, 

2叭3年第6期l福建电脑 ・155・ 

囊U ;; A 00 pU丁 疆 

PPRINTPROCESSOROPENDATA pPrintProcessorOpenData Control\Print\Printers: DetaultSp0olDirectory; 

); 

个性化假脱机目录在注册表中的位置: 

HKEY

LOCALMACHINE\SYSTEM\CurrentControlSet\Con— 

此函数为开始一个打印作业做准备,必须基于打 

指向一个内部数据结构,该结构包含打印机名称和 

DEVMODE结构的指针。 

BOOL ClosePrintProcessor( 

HANDLE hPrintProcessor 

印作业的数据类型执行…一些初始化操作。返回的句柄 

trol\Print\Printers\打印机名:SpoolDirectory。 

在spool目录下可能存在多个spool文件,正存处 

理的文档的名称会通过参数传递到Processor里,sDool 

文件中也有记录其文档名称,通过比较_者的值我们 

可以找到正确的spool文件。 

5.2.2提取EMF内容并保存。 

); 

此函数结束打印作业,释放0penPrintPmcessor所 

申请的所有资源。 

BOOI ControlPrintProcessor( 

HANDI E hPrintProcessor, 

DWORDCommand 

); 

此函数控制打印作业的暂停、取消、恢复等动作。 

DWORD GetPrintProcessorCapabilities( 

LPTSTRpValueName, 

DWORD dwAttributes, 

LPBYTEpData, 

DWORD nSize, 

LPDWORD pcbNeeded 

); 

此函数获取输入的数据类型的相关能力,以便后 

续执行相关处理。(有时这个函数可以不导出。) 

BOOL PrintDocumentOnPrintProcessor( 

HANDLE hPrintProcessor, 

LPWSTR pDocumentName 

); 

此函数执行spool文件内容的处理,是我们需要 

的最重要的一个函数。 

5.2实现EMF打印机 

为实现EMF打印机,我们要在PrintDocumentOn— 

PrintProcessor函数中执行几个步骤: 

5.2.1获取正确的spool文件。 

spool文件处于spool目录下。所有打印机都有一 

个共同的默认spool目录,默认为系统目录下的 

sDo0l\PRINTERS\,可以通过修改“打印服务器属性”一> 

“高级”一>‘‘后台打印文件夹”更改该目录。每台打印机 

也可以通过修改注册表来个性化自己的spool目录。 

通过查询注册表值可以获取正确的spool目录。 

默认spool目录在注册表中的位置: 

HKEY LOCAL MACHINEkSYSTEM\CurrentControlSet\ 

156・ 福建电脑l 2ol3年第6期 

依据NT EMF文件的结构,解析出EMF内容,按 

指定的命名规则或者获取用户输入的文件名称把它 

保存下来。 

若要让用户自定义如EMF文件保存目录、命名 

规则等,可以另写一个uI动态链接库,或者增加一 个 

插件式UI(可以参考DDK例子)。 

6.其它相关问题 

6.1 EMF打印机的安装。 

由于processor在spooler组件中的位置以及其功 

能特性,只要把这个processor安装到操作系统上,把 

它挂在任何现有的打印机上都可以使之失去原来的 

打印功能而变为EMF打印机。 

要制作独立的EMF打印机,可重新写一个inf文 

件。驱动文件使用unidrv.dll,设置文件使用unidrvui. 

dll,加上processor段,即可。 

6.2使用的特别事项。 

由于此打印机是在processor中提取spool文件的 

内容,所以要获取全部打印文档的内容,必须等整个 

打印文档spool完成后才能启动processor。因此,打印 

机的设置必须为:“使用后台打印,以便程序更快的结 

束打印”并且“在后台处理完最后一页时开始打印”。 

使用inf来安装打印机时,可能要手动设置此项。也可 

以通过制作打印机安装程序自动设置此项。 

7.结束语 

本文通过分析Windows打印机驱动的架构以及 

打印缓冲文件.spl的格式,以定制spooler组件的pro— 

cessor

的方式,实现了简单、快速的EMF虚拟打印机。 

参考文献: 

1]Microsoft Corporation.MSDN Library for Visual Studio 2005 

l 2 j Microsoft Corporation.DDK Documentation. 


本文标签: 打印机打印文件文档实现