如何将.spl剥离成.emf文件格式
关键字: 打印 SPL EMF 文件格式
问题:
Windows的假脱机打印会在Windows/System32/spool/PRINERS目录下生成.spl和.shd文件,其中的打印内
容存贮在.spl文件中,但是.spl文件格式似乎未公开,那么如何才能将未知的.spl文件剥离成.emf文件呢?
首先,让我们了解一下Windows打印机制:
这是微软的官网的一副打印流程图片:
其中ISV是应用软件接口,IHV是硬件接口,左边是XP的打印模型,右边是Vista最新的XPS打印模
型,但两者可以互相转换,具有良好的兼容性。不过,这里暂时只关心XP系统的打印过程。
网络打印过程图:

但是这些图似乎还不够详细,那么请看下面一副:(摘录于论文:《基于关键字匹配的打印数据截获
系统》):

基本的思路是: 打印过程发生时,GDI模块和打印驱动(由打印机厂商提供)进行基本的数据交换,在假
脱机设置环境下,生成打印机命令文件:.spl或.emf文件,作为一个打印池的作业,然后Windows后台打印线
程处理打印作业,将数据文件送至打印机打印,打印完删除该打印文件。
好,现在回到正题:.spl文件该如何剥离成.emf呢?看一个例子:
在WinHex中打开一个.spl文件:
参考: http://www.undocprint.org/formats/winspool/spl 中一些打印结构的定义。
首先,.spl文件都是以0x00010000签名开头,然后一个DWORD 是emf相关区的文件偏移,第3个
DWORD是文档描述字符串(UNICODE)的文件偏移,第4个DWORD 描述的是端口说明字符串(UNICODE)。大
致结构如下:

文件尾就是这个样子:

当定位到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/ 星绽紫辉
程序截图如下:



2

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

11

12
BOOL AnalyseFile(const char* pszFileName);13

14
void PFT(const char* pszInfo,DWORD dwData)15


{16
printf("%s: 0x%08X/n",pszInfo,dwData);17
}18

19
void PFM(const char* pszInfo)20


{21
printf("%s/n",pszInfo);22
}23

24
void UPFM(const wchar_t pszInfo[])25


{26
wprintf(L"%s/n",pszInfo);27
}28

29
static char* ID_Func[] =30


{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

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

156
int main()157


{158
setlocale(LC_ALL,""); 159

160
const char* pszFileName = "C://Documents and Settings//joe//桌面//1//00053.SPL";161

162
if(!AnalyseFile(pszFileName))163
PFM("Analyse File Failed!");164
else165
PFM("Analyse File Successed Completed!");166

167
return 0;168
}169

170

171
BOOL AnalyseFile(const char* pszFileName)172


{173
BOOL bRet = FALSE;174

175
DWORD dwStartPos = 0;176

177
FILE* pFile = fopen(pszFileName,"rb");178

179
if(!pFile)180

{181
PFM("Open File Failed!");182
return bRet;183
}184

185
PFM("Begin Analyse
");186

187
PFM("[1] Begin to read SPL HeaderInfo:");188

189

/**//* =======================Headers================================ */190
DWORD dwTmp = 0;191

192
fseek(pFile,0,0);193

194
fread(&dwTmp,sizeof(DWORD),1,pFile);195

196
PFT("签名",dwTmp);197

198

199
fread(&dwTmp,sizeof(DWORD),1,pFile);200

201
dwStartPos = dwTmp;202

203
PFT("正文信息偏移:",dwTmp);204

205
fread(&dwTmp,sizeof(DWORD),1,pFile);206

207
PFT("文档信息偏移(UNICODE):",dwTmp);208

209
long pos = ftell(pFile);210

211
fseek(pFile,dwTmp,SEEK_SET);212

213

wchar_t pszInfo[256] =
{0};214
pszInfo[0] = L"(";215
216
WORD wTmp;217
for(int i = 1;;i++)218

{219
fread(&wTmp,sizeof(wTmp),1,pFile);220

221
if(!wTmp)222
break;223

224
memcpy((char*)&pszInfo[i],&wTmp,sizeof(wTmp));225
}226
pszInfo[i] = L")";227
UPFM(pszInfo);228

229
fseek(pFile,pos,SEEK_SET);230

231
fread(&dwTmp,sizeof(DWORD),1,pFile);232

233
PFT("打印端口信息偏移(UNICODE):",dwTmp);234

235
fseek(pFile,dwTmp,SEEK_SET);236

237
memset(pszInfo,0,sizeof(wchar_t)*256);238
pszInfo[0] = L"(";239
for(i = 1;;i++)240

{241
fread(&wTmp,sizeof(wTmp),1,pFile);242

243
if(!wTmp)244
break;245

246
memcpy((char*)&pszInfo[i],&wTmp,sizeof(wTmp));247
}248
pszInfo[i] = L")";249
UPFM(pszInfo);250

251

/**//* ======================== Unknown datas ================================= */252
PFM("[2] Begin to read SPL Unknown Datas:");253

254
fseek(pFile,dwStartPos,SEEK_SET);255

256
fread(&dwTmp,sizeof(DWORD),1,pFile);257

258
PFT("未知数据",dwTmp);259

260
fread(&dwTmp,sizeof(DWORD),1,pFile);261

262
PFT("未知数据",dwTmp);263

264

/**//* ======================== Record datas ================================= */265
PFM("[3] Begin to read Record Datas:");266

267
DWORD dwTmp2 = 0;268
for(int i=0;;i++)269

{270
pos = ftell(pFile);271

272
fread(&dwTmp,sizeof(DWORD),1,pFile);273

274
fread(&dwTmp2,sizeof(DWORD),1,pFile);275

276
277
printf("index: (%04d) type: 0x%04X size: %04d 0x%08X (%s)/n",i,dwTmp,dwTmp2,pos,ID_Func[dwTmp-1]);278

279
// printf("位置: %08X",pos);280

281
// printf("(%s)/n",ID_Func[dwTmp]);282

283
if(dwTmp == 0x0E)284

{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

290
fseek(pFile,pos+dwTmp2,SEEK_SET);291
}292

293
if(pFile) fclose(pFile);294
bRet = TRUE;295

296
return bRet;297
}298

299

300

301

302

303

304

305

306

307

308

309
有了以上的分析,你应该很容易写一个spl To EMF 文件格式的程序了。
如果代码有什么谬误或者Bug,请留言或者EmailToMe: xiaolu69soft@yahoo.com.cn
祝你好运~
rawdata
阅读更多
- 上一篇:没有了
- 下一篇:没有了
