原创: 星战紫辉 http://www.cppblog.com/rawdata 2009-2-23
关键字: 打印 SPL EMF 文件格式
问题:
Windows的假脱机打印会在Windows/System32/spool/PRINERS目录下生成.spl和.shd文件,其中的打印内
容存贮在.spl文件中,但是.spl文件格式似乎未公开,那么如何才能将未知的.spl文件剥离成.emf文件呢?
首先,让我们了解一下Windows打印机制:
这是微软的官网的一副打印流程图片:
其中ISV是应用软件接口,IHV是硬件接口,左边是XP的打印模型,右边是Vista最新的XPS打印模
型,但两者可以互相转换,具有良好的兼容性。不过,这里暂时只关心XP系统的打印过程。
网络打印过程图:
![](https://i-blog.csdnimg.cn/blog_migrate/be2851e5c57fd499aa51b19dc008aabc.gif)
但是这些图似乎还不够详细,那么请看下面一副:(摘录于论文:《基于关键字匹配的打印数据截获
系统》):
![](https://i-blog.csdnimg.cn/blog_migrate/97ac19c4c7a8a5bbaa8a22fb8b59e0f1.gif)
基本的思路是: 打印过程发生时,GDI模块和打印驱动(由打印机厂商提供)进行基本的数据交换,在假
脱机设置环境下,生成打印机命令文件:.spl或.emf文件,作为一个打印池的作业,然后Windows后台打印线
程处理打印作业,将数据文件送至打印机打印,打印完删除该打印文件。
好,现在回到正题:.spl文件该如何剥离成.emf呢?看一个例子:
在WinHex中打开一个.spl文件:
![](https://i-blog.csdnimg.cn/blog_migrate/2c3ad4c3e6e0701af8dcd40c0c6c5342.gif)
参考: http://www.undocprint.org/formats/winspool/spl 中一些打印结构的定义。
首先,.spl文件都是以0x00010000签名开头,然后一个DWORD 是emf相关区的文件偏移,第3个
DWORD是文档描述字符串(UNICODE)的文件偏移,第4个DWORD 描述的是端口说明字符串(UNICODE)。大
致结构如下:
![](https://i-blog.csdnimg.cn/blog_migrate/da67cbe259702e8a16aa76b51c18fe36.gif)
文件尾就是这个样子:
![](https://i-blog.csdnimg.cn/blog_migrate/aaf7301195e9ab2fd60103867499fe67.gif)
当定位到0x50的文件位置,读取2个DWORD数据之后,就是.emf文件开始了。.emf文件格式是公开的,而
且非常简单,是一系列EMR_XXX开口结构的紧密排列,通常以EMR_HEADER(0x01)开头,以EMR_EOF
(0x0E)结尾。其实我们根本没有必要去解析.emf文件格式,Windows SDK有专门显示.emf文件的API,3个函数就
搞定:
HENHMETAFILE hEMF = GetEnhMetaFile("EMF_DumpOK.emf");
PlayEnhMetaFile (dc.m_hDC, hEMF, &rc) ;
DeleteEnhMetaFile (hEMF) ;
然后.spl文件还有一些东西,我现在还没有解析出来,但是.emf文件已经剥离出来了,后面的可以先不理它。
然后,开始写程序喽,因为比较简单,所以代码有点随便哦~~:)
http://www.cppblog.com/rawdata/ 星绽紫辉
程序截图如下:
![](https://i-blog.csdnimg.cn/blog_migrate/260bbf4b697b770c1c4807f522144d07.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/e4bde9790f072d35367c57d1bcb1c94a.gif)
1
2
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
3
#include
<
windows.h
>
4
#include
<
winspool.h
>
5
#include
<
stdio.h
>
6
#include
<
locale.h
>
7
#include
<
tchar.h
>
8
#include
<
iostream
>
9
using
namespace
std;
10
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
11
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
12
BOOL AnalyseFile(
const
char
*
pszFileName);
13
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
14
void
PFT(
const
char
*
pszInfo,DWORD dwData)
15
![](https://i-blog.csdnimg.cn/blog_migrate/2f88ce130b654eb5dc6788e02dbcfc90.gif)
{
16
printf("%s: 0x%08X/n",pszInfo,dwData);
17
}
18
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
19
void
PFM(
const
char
*
pszInfo)
20
![](https://i-blog.csdnimg.cn/blog_migrate/2f88ce130b654eb5dc6788e02dbcfc90.gif)
{
21
printf("%s/n",pszInfo);
22
}
23
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
24
void
UPFM(
const
wchar_t pszInfo[])
25
![](https://i-blog.csdnimg.cn/blog_migrate/2f88ce130b654eb5dc6788e02dbcfc90.gif)
{
26
wprintf(L"%s/n",pszInfo);
27
}
28
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
29
static
char
*
ID_Func[]
=
30
![](https://i-blog.csdnimg.cn/blog_migrate/2f88ce130b654eb5dc6788e02dbcfc90.gif)
{
31
"EMR_HEADER",
32
"EMR_POLYBEZIER",
33
"EMR_POLYGON",
34
"EMR_POLYLINE",
35
"EMR_POLYBEZIERTO",
36
"EMR_POLYLINETO",
37
"EMR_POLYPOLYLINE",
38
"EMR_POLYPOLYGON",
39
"EMR_SETWINDOWEXTEX",
40
"EMR_SETWINDOWORGEX",
41
"EMR_SETVIEWPORTEXTEX",
42
"EMR_SETVIEWPORTORGEX",
43
"EMR_SETBRUSHORGEX",
44
"EMR_EOF",
45
"EMR_SETPIXELV",
46
"EMR_SETMAPPERFLAGS",
47
"EMR_SETMAPMODE",
48
"EMR_SETBKMODE",
49
"EMR_SETPOLYFILLMODE",
50
"EMR_SETROP2",
51
"EMR_SETSTRETCHBLTMODE",
52
"EMR_SETTEXTALIGN",
53
"EMR_SETCOLORADJUSTMENT",
54
"EMR_SETTEXTCOLOR",
55
"EMR_SETBKCOLOR",
56
"EMR_OFFSETCLIPRGN",
57
"EMR_MOVETOEX",
58
"EMR_SETMETARGN",
59
"EMR_EXCLUDECLIPRECT",
60
"EMR_INTERSECTCLIPRECT",
61
"EMR_SCALEVIEWPORTEXTEX",
62
"EMR_SCALEWINDOWEXTEX",
63
"EMR_SAVEDC",
64
"EMR_RESTOREDC",
65
"EMR_SETWORLDTRANSFORM",
66
"EMR_MODIFYWORLDTRANSFORM",
67
"EMR_SELECTOBJECT",
68
"EMR_CREATEPEN",
69
"EMR_CREATEBRUSHINDIRECT",
70
"EMR_DELETEOBJECT",
71
"EMR_ANGLEARC",
72
"EMR_ELLIPSE",
73
"EMR_RECTANGLE",
74
"EMR_ROUNDRECT",
75
"EMR_ARC",
76
"EMR_CHORD",
77
"EMR_PIE",
78
"EMR_SELECTPALETTE",
79
"EMR_CREATEPALETTE",
80
"EMR_SETPALETTEENTRIES",
81
"EMR_RESIZEPALETTE",
82
"EMR_REALIZEPALETTE",
83
"EMR_EXTFLOODFILL",
84
"EMR_LINETO",
85
"EMR_ARCTO",
86
"EMR_POLYDRAW",
87
"EMR_SETARCDIRECTION",
88
"EMR_SETMITERLIMIT",
89
"EMR_BEGINPATH",
90
"EMR_ENDPATH",
91
"EMR_CLOSEFIGURE",
92
"EMR_FILLPATH",
93
"EMR_STROKEANDFILLPATH",
94
"EMR_STROKEPATH",
95
"EMR_FLATTENPATH",
96
"EMR_WIDENPATH",
97
"EMR_SELECTCLIPPATH",
98
"EMR_ABORTPATH",
99
"69--Unknown",
100![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
101
"EMR_GDICOMMENT",
102
"EMR_FILLRGN",
103
"EMR_FRAMERGN",
104
"EMR_INVERTRGN",
105
"EMR_PAINTRGN ",
106
"EMR_EXTSELECTCLIPRGN",
107
"EMR_BITBLT ",
108
"EMR_STRETCHBLT",
109
"EMR_MASKBLT",
110
"EMR_PLGBLT",
111
"EMR_SETDIBITSTODEVICE",
112
"EMR_STRETCHDIBITS",
113
"EMR_EXTCREATEFONTINDIRECTW",
114
"EMR_EXTTEXTOUTA ",
115
"EMR_EXTTEXTOUTW",
116
"EMR_POLYBEZIER16",
117
"EMR_POLYGON16 ",
118
"EMR_POLYLINE16 ",
119
"EMR_POLYBEZIERTO16",
120
"EMR_POLYLINETO16 ",
121
"EMR_POLYPOLYLINE16",
122
"EMR_POLYPOLYGON16",
123
"EMR_POLYDRAW16 ",
124
"EMR_CREATEMONOBRUSH ",
125
"EMR_CREATEDIBPATTERNBRUSHPT",
126
"EMR_EXTCREATEPEN",
127
"EMR_POLYTEXTOUTA ",
128
"EMR_POLYTEXTOUTW",
129
"EMR_SETICMMODE ",
130
"EMR_CREATECOLORSPACE",
131
"EMR_SETCOLORSPACE ",
132
"EMR_DELETECOLORSPACE ",
133
"EMR_GLSRECORD ",
134
"EMR_GLSBOUNDEDRECORD",
135
"EMR_PIXELFORMAT",
136
"EMR_RESERVED_105 ",
137
"EMR_RESERVED_106 ",
138
"EMR_RESERVED_107",
139
"EMR_RESERVED_108 ",
140
"EMR_RESERVED_109",
141
"EMR_RESERVED_110 ",
142
"EMR_COLORCORRECTPALETTE",
143
"EMR_SETICMPROFILEA ",
144
"EMR_SETICMPROFILEW ",
145
"EMR_ALPHABLEND",
146
"EMR_SETLAYOUT ",
147
"EMR_TRANSPARENTBLT",
148
"EMR_RESERVED_117 ",
149
"EMR_GRADIENTFILL",
150
"EMR_RESERVED_119 ",
151
"EMR_RESERVED_120",
152
"EMR_COLORMATCHTOTARGETW",
153
"EMR_CREATECOLORSPACEW"
154
}
;
155
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
156
int
main()
157
![](https://i-blog.csdnimg.cn/blog_migrate/2f88ce130b654eb5dc6788e02dbcfc90.gif)
{
158
setlocale(LC_ALL,"");
159![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
160
const char* pszFileName = "C://Documents and Settings//joe//桌面//1//00053.SPL";
161![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
162
if(!AnalyseFile(pszFileName))
163
PFM("Analyse File Failed!");
164
else
165
PFM("Analyse File Successed Completed!");
166![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
167
return 0;
168
}
169
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
170
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
171
BOOL AnalyseFile(
const
char
*
pszFileName)
172
![](https://i-blog.csdnimg.cn/blog_migrate/2f88ce130b654eb5dc6788e02dbcfc90.gif)
{
173
BOOL bRet = FALSE;
174![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
175
DWORD dwStartPos = 0;
176![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
177
FILE* pFile = fopen(pszFileName,"rb");
178![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
179
if(!pFile)
180![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
{
181
PFM("Open File Failed!");
182
return bRet;
183
}
184![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
185
PFM("Begin Analyse
");
186![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
187
PFM("[1] Begin to read SPL HeaderInfo:");
188![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
189![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
/**//* =======================Headers================================ */
190
DWORD dwTmp = 0;
191![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
192
fseek(pFile,0,0);
193![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
194
fread(&dwTmp,sizeof(DWORD),1,pFile);
195![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
196
PFT("签名",dwTmp);
197![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
198![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
199
fread(&dwTmp,sizeof(DWORD),1,pFile);
200![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
201
dwStartPos = dwTmp;
202![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
203
PFT("正文信息偏移:",dwTmp);
204![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
205
fread(&dwTmp,sizeof(DWORD),1,pFile);
206![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
207
PFT("文档信息偏移(UNICODE):",dwTmp);
208![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
209
long pos = ftell(pFile);
210![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
211
fseek(pFile,dwTmp,SEEK_SET);
212![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
213![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
wchar_t pszInfo[256] =
{0};
214
pszInfo[0] = L'(';
215
216
WORD wTmp;
217
for(int i = 1;;i++)
218![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
{
219
fread(&wTmp,sizeof(wTmp),1,pFile);
220![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
221
if(!wTmp)
222
break;
223![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
224
memcpy((char*)&pszInfo[i],&wTmp,sizeof(wTmp));
225
}
226
pszInfo[i] = L')';
227
UPFM(pszInfo);
228![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
229
fseek(pFile,pos,SEEK_SET);
230![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
231
fread(&dwTmp,sizeof(DWORD),1,pFile);
232![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
233
PFT("打印端口信息偏移(UNICODE):",dwTmp);
234![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
235
fseek(pFile,dwTmp,SEEK_SET);
236![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
237
memset(pszInfo,0,sizeof(wchar_t)*256);
238
pszInfo[0] = L'(';
239
for(i = 1;;i++)
240![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
{
241
fread(&wTmp,sizeof(wTmp),1,pFile);
242![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
243
if(!wTmp)
244
break;
245![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
246
memcpy((char*)&pszInfo[i],&wTmp,sizeof(wTmp));
247
}
248
pszInfo[i] = L')';
249
UPFM(pszInfo);
250![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
251![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
/**//* ======================== Unknown datas ================================= */
252
PFM("[2] Begin to read SPL Unknown Datas:");
253![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
254
fseek(pFile,dwStartPos,SEEK_SET);
255![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
256
fread(&dwTmp,sizeof(DWORD),1,pFile);
257![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
258
PFT("未知数据",dwTmp);
259![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
260
fread(&dwTmp,sizeof(DWORD),1,pFile);
261![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
262
PFT("未知数据",dwTmp);
263![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
264![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
/**//* ======================== Record datas ================================= */
265
PFM("[3] Begin to read Record Datas:");
266![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
267
DWORD dwTmp2 = 0;
268
for(int i=0;;i++)
269![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
{
270
pos = ftell(pFile);
271![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
272
fread(&dwTmp,sizeof(DWORD),1,pFile);
273![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
274
fread(&dwTmp2,sizeof(DWORD),1,pFile);
275![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
276
277
printf("index: (%04d) type: 0x%04X size: %04d 0x%08X (%s)/n",i,dwTmp,dwTmp2,pos,ID_Func[dwTmp-1]);
278![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
279
// printf("位置: %08X",pos);
280![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
281
// printf("(%s)/n",ID_Func[dwTmp]);
282![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
283
if(dwTmp == 0x0E)
284![](https://i-blog.csdnimg.cn/blog_migrate/f70a0fde2b51b7dd92a70e712e540cf6.gif)
{
285
// printf("index: (%04d) type: 0x%04X size: %04d 0x%08X (End)/n",i,dwTmp,dwTmp2,pos,);
286
PFM("End of Record Datas.");
287
break;
288
}
289![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
290
fseek(pFile,pos+dwTmp2,SEEK_SET);
291
}
292![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
293
if(pFile) fclose(pFile);
294
bRet = TRUE;
295![](https://i-blog.csdnimg.cn/blog_migrate/df37983f39daa189b8c814e01a6a9011.gif)
296
return bRet;
297
}
298
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
299
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
300
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
301
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
302
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
303
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
304
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
305
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
306
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
307
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
308
![](https://i-blog.csdnimg.cn/blog_migrate/cbef093dcc044b2793832001e2365e43.gif)
309
有了以上的分析,你应该很容易写一个spl To EMF 文件格式的程序了。
如果代码有什么谬误或者Bug,请留言或者EmailToMe: xiaolu69soft@yahoo.com.cn
祝你好运~
rawdata