打印信息监控——打印池文件spl分析
在windows的打印过程中,会生成中间的打印池文件,在该文件中存储着打印页面的emf图源文件,通过该文件即可知道即将打印的内容。
Windows的假脱机打印会在Windows\System32\spool\PRINERS目录下生成.spl和.shd文件,其中的打印内容存贮在.spl文件中,但是.spl文件格式似乎未公开,那么如何才能将未知的.spl文件剥离成.emf文件呢?
Windows打印的基本原理是: 打印过程发生时,GDI模块和打印驱动(由打印机厂商提供)进行基本的数据交换,在假脱机设置环境下,生成打印机命令文件:.spl或.emf文件,作为一个打印池的作业,然后Windows后台打印线程处理打印作业,将数据文件送至打印机打印,打印完删除该打印文件。
参考: http://www.undocprint.org/formats/winspool/spl 中一些打印结构的定义。
首先,.spl文件都是以0x00010000签名开头,然后一个DWORD 是文件内容的文件偏移,第3个DWORD是文档描述字符串(UNICODE)的文件偏移,第4个DWORD 描述的是端口说明字符串(UNICODE)。大概可以定义为如下结构:
structSPLHead
{
DWORD dwSPLTag = 0x00010000; //spl标志
DWORD dwContentOffset; //文件内容偏移量
DWORD dwDocDiscribeOffset; //文档描述字符串偏移量
DWORD dwPortInfoOffset; //端口信息字符串偏移量
};
紧随其后的就是文档描述字符串与端口信息字符串,长度不定。字符串信息后就是文件内容区段。
文件内容区段结构比较简单,主要由两个结构体交替组成
structSPLSectionInfo
{
DWORD dwSectionType; //区段类型
DWORD dwSectionLength; //区段长度
};
structSPL_XXX_Section
{
... //区段内容,不必进行识别
};
我们要读取的主要是spl文件中包含的emf文件,根据以上的分析,只要根据SPLSectionInfo中的内容便可取得emf文件。根据已知的信息dwSectionType的值有如下几个定义:
0x0C: Enhanced Meta File (EMF)
0x0E: Ext EndOfPage GDI image data
0x03: DevMode
0x0D: Ext EndOfPage raster bitmap
在编程时,只关心dwSectionType值为0x0C的情况,将其读入内存并写入文件;在其他情况下直接跳过该区段,继续读取文件的其他内容。
其实.emf文件格式没有必要去解析,该类型文件可以直接使用windows自带的画图工具打开,也可以使用Windows SDK专门用来显示.emf文件的API来实现,3个函数:
HENHMETAFILE hEMF = GetEnhMetaFile("EMF_DumpOK.emf");
PlayEnhMetaFile (dc.m_hDC, hEMF, &rc) ;
DeleteEnhMetaFile (hEMF) ;
.emf文件已经剥离出来,后面的可以先不关心。
备注:
1. 与spl文件同时生成的shd文件中有该任务的更多描述信息,没有需要所以未进行解析,可用附带的splview工具打开并进行查看。
2. 将内容写入emf文件时需使用二进制,追加方式进行打开,否则会导致文件中插入无效字符无法打开。
3. 获取中间文件的方式:在控制面板的设备与打印机中,指定打印机->打印机属性->高级->勾选保留打印的文档(如下图),即可在C:\Windows\System32\spool\PRINTERS目录中获得打印生成的中间文件(spl,shd)。
4. demo的使用方法:demo为控制台程序,运行程序时将spl文件的全路径作为参数即可获得全部的emf文件页。
5. 附件00010为word通过虚拟打印机bitmap生成的文件,00012为notpad通过虚拟打印机bitmap生成的文件。