Click here to Skip to main content
Click here to Skip to main content

EMF Printer Spool File Viewer

By , 21 Aug 2006
 

What is an EMF spool file?

When an application sends pages to a printer they are held in an intermediary file which the application can write to and the printer driver can read from simultaneously. This speeds up the print process as control can return to the application before the printer has finished printing the document.

Usually this spool file is held in the raw printer page definition language (which could be PCL, PostScript or one of many other options) but in Windows NT, 2000, XP and 2003, it is possible to make the spooler use a different, more device independent format known as an EMF spool file.

The file layout of an EMF spool file is not officially documented by Microsoft, but this article reveals that it is a series of enhanced metafile records (one for each page) and a number of other record types which are specific to the business of printing these pages.

The EMF spool file record types

The spool file is composed of the following record types:

    Private Enum SpoolerRecordTypes
        SRT_EOF = &H0            ' // int32 zero
        SRT_RESERVED_1 = &H1     '*  1                               */
        SRT_FONTDATA = &H2       '  2 Font Data                      */
        SRT_DEVMODE = &H3        '  3 DevMode                        */
        SRT_FONT2 = &H4          '4 Font Data                        */
        SRT_RESERVED_5 = &H5     ' 5                                 */
        SRT_FONT_MM = &H6        ' 6 Font Data (Multiple Master)     */
        SRT_FONT_SUB1 = &H7      '   7 Font Data (SubsetFont 1)      */
        SRT_FONT_SUB2 = &H8      '   8 Font Data (SubsetFont 2)      
        SRT_RESERVED_9 = &H9
        SRT_UNKNOWN = &H10       ' // int unknown...
        SRT_RESERVED_A = &HA
        SRT_RESERVED_B = &HB
        SRT_PAGE = &HC           ' 12  Enhanced Meta File (EMF)       */
        SRT_EOPAGE1 = &HD        ' 13  EndOfPage                      */
        SRT_EOPAGE2 = &HE        ' 14  EndOfPage                      */
        SRT_EXT_FONT = &HF       ' 15  Ext Font Data                  */
        SRT_EXT_FONT2 = &H10     ' 16  Ext Font Data                  */
        SRT_EXT_FONT_MM = &H11   ' 17  Ext Font Data (Multiple Master)
        SRT_EXT_FONT_SUB1 = &H12 ' 18  Ext Font Data (SubsetFont 1)   */
        SRT_EXT_FONT_SUB2 = &H13 '* 19  Ext Font Data (SubsetFont 2)  */
        SRT_EXT_PAGE = &H14      ' 20  Enhanced Meta File? 
    End Enum

Of these the most important record types are:

SRT_PAGE

This record contains a Windows standard enhanced metafile, consisting of an EMF header and one or more EMF graphics record structures. The EMF header record gives you the dimensions of the boundary rectangle (the area inside the print margins), the number of graphics records that make up the page, and the file size of this single EMF page.

SRT_DEVMODE

This record contains the device settings that apply to the rest of the pages in the document (or until another DEVMODE record is encountered that overrides it). The DEVMODE structure holds details such as the number of copies, the page orientation (landscape versus portrait), the paper size and paper source, and so on.

SRT_EOF

This signifies the end of the spool file records.

Using the EMF spoolfile viewer

To view an EMF spool file, select the menu File -> Open. A dialog box will appear to allow you to browse to the spool file (extension .spl). These are typically held in your $winnt$\System32\spool\ directory. (I have included some samples with this application code as well.)

The viewer allows you to go to a particular page, zoom in and out, and even print the spool file using the following menu options:

  • File
    • Open - Brings up a dialog box to find and open EMF spool files.
    • Print - Allows you to reprint the currently open EMF spool file.
    • Properties - Brings up a dialog box listing the print file properties.
    • Exit - Quits the application.
  • Pages
    • First Page - Goes to the beginning of the document.
    • Previous Page - Goes back one page.
    • Next Page - Goes to the next page.
    • Last Page - Goes to the end of the document.
    • Goto - Goes directly to the selected page.
    • Properties = Brings up a dialog with the properties of this page.
  • View
    • Zoom in enlarges the preview.
    • Zoom out reduces the size of the preview.

Uses for EMF spoolfiles

Since pretty much every application has a print function, the EMF spool file can serve as a quick and dirty portable document format (though much less featured than a PDF). Thus if you have an application and you want to send a file to someone who doesn't have that application to view, you simply use the application's print function and send them the spool file.

In addition, knowing the structure of the spool file means that it is possible to parse the file to extract information from it. You might want to extract just the text from a printed document for archival purposes, and you can do this by parsing the file and extracting the EMR_EXTTEXTOUTA and EMR_EXTTEXTOUTW records.

Acknowledgements

The source code in this application draws heavily on the work of Feng Yuan and Christophe Lindemann as well as numerous others on the various forums and news groups.

Portions of this article based on www.undocprint.org/formats/winspool/spl. These portions are subject to the GNU Free Documentation License and are copyright © 2003-2005 Free Software Foundation, Inc.

History

  • 21 Aug 2006

    Code updated to .NET 2.0 and page navigation improved.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Duncan Edwards Jones
Software Developer (Senior) JP Morgan
Ireland Ireland
Member
C# / SQL Server developer
Microsoft MVP 2006, 2007
Visual Basic .NET

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionLength DEVMODEmemberDanielRM28 Feb '13 - 9:39 
The length to read the DEVMODE structure is incorrect. DmDeviceName value is 32 bytes (no 64).
 
Here is the code so that it can be corrected.
 
Duncan Thanks for your great help, and I hope to contribute with this comment.
 
Public Sub New(ByVal FileReader As System.IO.BinaryReader)
        dmDeviceName = FileReader.ReadChars(32)
        dmSpecVersion = FileReader.ReadInt16
 
.....
End Sub

QuestionSaving the EMF filememberAdi Shavit21 Jun '12 - 8:22 
Hi,
 
I tried renaming the SPL file to EMF, but it is not a valid EMF file.
How can the SPL be converted to a valid EMF file?
 
Thanks,
Adi
AnswerRe: Saving the EMF filememberDuncan Edwards Jones12 Jul '12 - 1:22 
It can't be converted - it either is EMF or it is RAW (a different printer control language such as PostScript, PCL-5, PCL-6 etc.)
'--8<------------------------
Ex Datis:
Duncan Jones
 
Free eBook: Printing - a .NET Developer's Guide (Part 1)

Questiontried to open a .spl file and is getting this detailed error message.. any ideamemberfreefall_020321 Jun '12 - 7:17 
See the end of this message for details on invoking
just-in-time (JIT) debugging instead of this dialog box.
 
************** Exception Text **************
System.IO.EndOfStreamException: Unable to read beyond the end of the stream.
at System.IO.__Error.EndOfFile()
at System.IO.BinaryReader.FillBuffer(Int32 numBytes)
at System.IO.BinaryReader.ReadInt32()
at EMFSpoolfileReader.EMFSpoolfileReader.GetTruePageCount(String SpoolFilename)
at EMFSpoolViewer.SpoolFileForm.MenuItem_File_Open_Click(Object sender, EventArgs e)
at System.Windows.Forms.MenuItem.OnClick(EventArgs e)
at System.Windows.Forms.MenuItem.MenuItemData.Execute()
at System.Windows.Forms.Command.Invoke()
at System.Windows.Forms.Command.DispatchID(Int32 id)
at System.Windows.Forms.Control.WmCommand(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
at System.Windows.Forms.ContainerControl.WndProc(Message& m)
at System.Windows.Forms.Form.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
 

************** Loaded Assemblies **************
mscorlib
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.3053 (netfxsp.050727-3000)
CodeBase: file:///C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/mscorlib.dll
----------------------------------------
EMFSpoolViewer
Assembly Version: 1.0.1980.19643
Win32 Version: 1.0.1980.19643
CodeBase: file:///C:/Documents%20and%20Settings/Administrator/Desktop/EMFSpoolViewer/EMFSpoolViewer.exe
----------------------------------------
System.Windows.Forms
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.3053 (netfxsp.050727-3000)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Windows.Forms/2.0.0.0__b77a5c561934e089/System.Windows.Forms.dll
----------------------------------------
System
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.3053 (netfxsp.050727-3000)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System/2.0.0.0__b77a5c561934e089/System.dll
----------------------------------------
System.Drawing
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.3053 (netfxsp.050727-3000)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Drawing/2.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll
----------------------------------------
Microsoft.VisualBasic
Assembly Version: 8.0.0.0
Win32 Version: 8.0.50727.3053 (netfxsp.050727-3000)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/Microsoft.VisualBasic/8.0.0.0__b03f5f7f11d50a3a/Microsoft.VisualBasic.dll
----------------------------------------
EMFSpoolfileReader
Assembly Version: 1.1.1980.19643
Win32 Version: 1.1.1980.19643
CodeBase: file:///C:/Documents%20and%20Settings/Administrator/Desktop/EMFSpoolViewer/EMFSpoolfileReader.DLL
----------------------------------------
System.Configuration
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.3053 (netfxsp.050727-3000)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Configuration/2.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll
----------------------------------------
System.Xml
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.3053 (netfxsp.050727-3000)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Xml/2.0.0.0__b77a5c561934e089/System.Xml.dll
----------------------------------------
 
************** JIT Debugging **************
To enable just-in-time (JIT) debugging, the .config file for this
application or computer (machine.config) must have the
jitDebugging value set in the system.windows.forms section.
The application must also be compiled with debugging
enabled.
 
For example:
 



 
When JIT debugging is enabled, any unhandled exception
will be sent to the JIT debugger registered on the computer
rather than be handled by this dialog box.
AnswerRe: tried to open a .spl file and is getting this detailed error message.. any ideamemberDuncan Edwards Jones25 Jun '12 - 3:53 
Are you sure the file you are opening is an EMF spool file? Spool files can either be "RAW" (meaning they are in the printer control language of the printer itself such as PCL-5 or PostScript) or "EMF".
'--8<------------------------
Ex Datis:
Duncan Jones
 
Free eBook: Printing - a .NET Developer's Guide (Part 1)

QuestionCrash on loadmemberkelemvorx7 Mar '12 - 6:17 
Trying to find a way to view a spooler file but it's not working.
 
I can select the file, it loads for a bit, then it crashes:
 
Unhandled exception has occurred in a component in your application.
Unable to read beyond the end of the stream.
 
See the end of this message for details on invoking
just-in-time (JIT) debugging instead of this dialog box.
 
************** Exception Text **************
System.IO.EndOfStreamException: Unable to read beyond the end of the stream.
at System.IO.__Error.EndOfFile()
at System.IO.BinaryReader.FillBuffer(Int32 numBytes)
at System.IO.BinaryReader.ReadInt32()
at EMFSpoolfileReader.EMFSpoolfileReader.GetTruePageCount(String SpoolFilename)
at EMFSpoolViewer.SpoolFileForm.MenuItem_File_Open_Click(Object sender, EventArgs e)
at System.Windows.Forms.MenuItem.OnClick(EventArgs e)
at System.Windows.Forms.MenuItem.MenuItemData.Execute()
at System.Windows.Forms.Command.Invoke()
at System.Windows.Forms.Command.DispatchID(Int32 id)
at System.Windows.Forms.Control.WmCommand(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
at System.Windows.Forms.ContainerControl.WndProc(Message& m)
at System.Windows.Forms.Form.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
 

************** Loaded Assemblies **************
mscorlib
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.3625 (GDR.050727-3600)
CodeBase: file:///c:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/mscorlib.dll
----------------------------------------
EMFSpoolViewer
Assembly Version: 1.0.1980.19643
Win32 Version: 1.0.1980.19643
CodeBase: file:///C:/Documents%20and%20Settings/tkmaxa6/Desktop/EMFSpoolViewer/EMFSpoolViewer.exe
----------------------------------------
System.Windows.Forms
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.3623 (GDR.050727-3600)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Windows.Forms/2.0.0.0__b77a5c561934e089/System.Windows.Forms.dll
----------------------------------------
System
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.3620 (GDR.050727-3600)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System/2.0.0.0__b77a5c561934e089/System.dll
----------------------------------------
System.Drawing
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.3053 (netfxsp.050727-3000)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Drawing/2.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll
----------------------------------------
Microsoft.VisualBasic
Assembly Version: 8.0.0.0
Win32 Version: 8.0.50727.3053 (netfxsp.050727-3000)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/Microsoft.VisualBasic/8.0.0.0__b03f5f7f11d50a3a/Microsoft.VisualBasic.dll
----------------------------------------
EMFSpoolfileReader
Assembly Version: 1.1.1980.19643
Win32 Version: 1.1.1980.19643
CodeBase: file:///C:/Documents%20and%20Settings/tkmaxa6/Desktop/EMFSpoolViewer/EMFSpoolfileReader.DLL
----------------------------------------
System.Configuration
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.3053 (netfxsp.050727-3000)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Configuration/2.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll
----------------------------------------
System.Xml
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.3053 (netfxsp.050727-3000)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Xml/2.0.0.0__b77a5c561934e089/System.Xml.dll
----------------------------------------
 
************** JIT Debugging **************
To enable just-in-time (JIT) debugging, the .config file for this
application or computer (machine.config) must have the
jitDebugging value set in the system.windows.forms section.
The application must also be compiled with debugging
enabled.
 
For example:
 



 
When JIT debugging is enabled, any unhandled exception
will be sent to the JIT debugger registered on the computer
rather than be handled by this dialog box.
AnswerRe: Crash on loadmemberDuncan Edwards Jones25 Jun '12 - 3:53 
Are you sure the file you are opening is an EMF spool file? Spool files can either be "RAW" (meaning they are in the printer control language of the printer itself such as PCL-5 or PostScript) or "EMF".
'--8<------------------------
Ex Datis:
Duncan Jones
 
Free eBook: Printing - a .NET Developer's Guide (Part 1)

QuestionCannot take the text of the Recordmembersgkin8 Feb '12 - 7:34 
Very nice article, but i have a problem.
How I use the EMFTextRecord to take the text?
If I call it inside the
ProcessEMFRecords
, it doesn't return any text
AnswerRe: Cannot take the text of the Recordmemberinternet7827 Feb '12 - 0:26 
I also have this problem. Does someone already solved this problem ? I tried to read EMFTextRecord from the start but i don't get any string ....
GeneralMy vote of 5memberLeviButler10 Jan '12 - 3:00 
Fantastic!
Also works perfect in C#
GeneralThere is definitely a difference between executable and sourcememberMember 58133013 Jun '11 - 2:37 
The part that really interests me is the part where you reprint the spool file using new printersettings. But the print option in the File menu exists in the executable, but not in the source code.
 
Would you like to reveal this part of the code or is it not a coincedence that this code is not there?
 
Thanks in advance
GeneralRe: There is definitely a difference between executable and sourcememberMember 800497814 Jun '11 - 0:58 
No the code is not deliberately withheld - I just lost the original when I moved my code to new VCS. I'll see if any of the backups include this app code - otherwise you can use Reflector to decompile it?
GeneralRe: There is definitely a difference between executable and sourcememberCalcMan5512 Jul '11 - 8:01 
Any news on this front? I was hoping to use a working code block to play with some stuff, like monitoring spl and dumping new docs into pdf or post processing.
GeneralRe: There is definitely a difference between executable and sourcememberDuncan Edwards Jones22 Jan '12 - 10:41 
Sorry - it is gone Frown | :-(
'--8<------------------------
Ex Datis:
Duncan Jones
 
Free eBook: Printing - a .NET Developer's Guide (Part 1)

GeneralCode difference?memberSkif7 Jun '11 - 13:14 
It looks like there is a code difference in the posted code and the code behind the binaries. When I run the same file (1000+ pages) on EMFSpoolViewer.exe it works fine, when I run the same file on the code from VB.NET projects the SpoolfileReadertest pretty much takes all RAM it can get (10+Gb) and I have to kill the process to get my machine mack.
 
Do you have any idea why the sample app and source code behave so differently? Thanks!
GeneralLoading emf file .... nothing happens...membertinvaltino15 Sep '10 - 12:28 
I downloaded the 3 application files - the 2 dlls and the 1 exe
 
I have win xp pro..
Extracted them to folder
 
Ran the exe.. prog opens.. i load SPL file in it.. and all it says in the title bar is "Loading emf file..." filepath
 
And .. nothing else..
Then if i click on menu zoom in or soom out = crash
 
Unhandled exception has occured in a component in your application. If you click continue, the application will ignore this error and attempt to continue
 
Index was out of range. Must be non-negative and less than the size of the collection.
Parameter nameL index
 

Details:
 
See the end of this message for details on invoking
just-in-time (JIT) debugging instead of this dialog box.
 
************** Exception Text **************
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
at System.Collections.ArrayList.get_Item(Int32 index)
at EMFSpoolViewer.SpoolFileForm.MenuItem_View_Zoomout_Click(Object sender, EventArgs e)
at System.Windows.Forms.MenuItem.OnClick(EventArgs e)
at System.Windows.Forms.MenuItem.MenuItemData.Execute()
at System.Windows.Forms.Command.Invoke()
at System.Windows.Forms.Command.DispatchID(Int32 id)
at System.Windows.Forms.Control.WmCommand(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
at System.Windows.Forms.ContainerControl.WndProc(Message& m)
at System.Windows.Forms.Form.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
 

************** Loaded Assemblies **************
mscorlib
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.3615 (GDR.050727-3600)
CodeBase: file:///c:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/mscorlib.dll
----------------------------------------
EMFSpoolViewer
Assembly Version: 1.0.1980.19643
Win32 Version: 1.0.1980.19643
CodeBase: file:///C:/Documents%20and%20Settings/tino/Desktop/EMFSpoolViewer/EMFSpoolViewer.exe
----------------------------------------
System.Windows.Forms
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.3053 (netfxsp.050727-3000)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Windows.Forms/2.0.0.0__b77a5c561934e089/System.Windows.Forms.dll
----------------------------------------
System
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.3614 (GDR.050727-3600)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System/2.0.0.0__b77a5c561934e089/System.dll
----------------------------------------
System.Drawing
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.3053 (netfxsp.050727-3000)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Drawing/2.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll
----------------------------------------
Microsoft.VisualBasic
Assembly Version: 8.0.0.0
Win32 Version: 8.0.50727.3053 (netfxsp.050727-3000)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/Microsoft.VisualBasic/8.0.0.0__b03f5f7f11d50a3a/Microsoft.VisualBasic.dll
----------------------------------------
EMFSpoolfileReader
Assembly Version: 1.1.1980.19643
Win32 Version: 1.1.1980.19643
CodeBase: file:///C:/Documents%20and%20Settings/tino/Desktop/EMFSpoolViewer/EMFSpoolfileReader.DLL
----------------------------------------
System.Configuration
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.3053 (netfxsp.050727-3000)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Configuration/2.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll
----------------------------------------
System.Xml
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.3082 (QFE.050727-3000)
CodeBase: file:///C:/WINDOWS/assembly/GAC_MSIL/System.Xml/2.0.0.0__b77a5c561934e089/System.Xml.dll
----------------------------------------
 
************** JIT Debugging **************
To enable just-in-time (JIT) debugging, the .config file for this
application or computer (machine.config) must have the
jitDebugging value set in the system.windows.forms section.
The application must also be compiled with debugging
enabled.
 
For example:
 
<configuration>
<system.windows.forms jitDebugging="true" />
</configuration>
 
When JIT debugging is enabled, any unhandled exception
will be sent to the JIT debugger registered on the computer
rather than be handled by this dialog box.
GeneralRe: Loading emf file .... nothing happens...memberDuncan Edwards Jones9 Dec '10 - 7:33 
Is it definitely an EMF format spool file?
'--8<------------------------
Ex Datis:
Duncan Jones
 
Free eBook: Printing - a .NET Developer's Guide (Part 1)

GeneralRe: Loading emf file .... nothing happens...memberLoris Rinaldo10 Nov '11 - 4:31 
I have the same problem.
The file I want to view was sent to me as with an EMF file extention (its a binary file, not text, of about 6MB) .
I've renamed it to .spl but When I open it with your application I see nothing.
 
If I use an image viewer as IrfanView or similar I can only view the first page.
 
Please give me any advice so to be able to view it.
 
thanks.
Loris
GeneralRe: Loading emf file .... nothing happens...memberLoris Rinaldo18 Nov '11 - 10:21 
I'll give myself the answer:
 
I found this other piece of software that does the job perfectly
http://www.lvbprint.de/html/splviewer1.html
 
bye
GeneralRe: Loading emf file .... nothing happens...memberLoris Rinaldo18 Nov '11 - 10:23 
Use this free software to do the job:
 
http://www.lvbprint.de/html/splviewer1.html
 
Bye,
Loris
QuestionExtract text from .spl file to .txt filememberBuzardHawk24 Jul '10 - 9:06 
Hi Duncan,
 
I'm used to program VBA code behind Excel.
Manipulating text files.
 
I stumbled accros EMFSpoolViewer.
I'd like to use this to extract tekst from a .spl to .txt.
 
Something like this
 
File open(1, c:\archieve\printarchive.txt, openmode.output
'open spl file'(2)
 
Do while not EOF(2)
'Read spl file'
'spl tekst' = printdata
Writeline(1, printdata)
loop
 
How do i implement this in the source code?
 
With kind regards,
 
Leon
GeneralAdobe PDF Files Display Incorrectly [modified]membertokfrans22 Mar '10 - 2:44 
I really appreciate the hard work that has been put into this article and the source code especially.
I have found that viewing PDF files doesn't work correctly for some documents.
When loading the spooler file, the text looks scrambled and the underlying text is different to what's showing in the display.
To illustrate this I'm showing what I'm seeing.
 
In the original document when printed on paper you can find this text:
Hardware Requirements
 
The EMFViewer Application displays:
Ibsexbsf!Sfrvjsfnfout
 
When debugging the code, I find that this is the text in the EMF record:
,EVH[EVI6IUYMVIQIRXW
 
To me this seems like the EMF display has been shifted one byte up. H=I, a=b, r=s and so forth. And the same goes for the EMF record text, but the shift is 28 bytes, H=, a=E, r=V, d=H. You get the picture.
 
Some PDF files works without any problems and looks great, and others display problems like or similar to this.
Can anyone please try to explain why this is, and if there's anything I can do to handle this.
 
Thanks.
Timmy

GeneralRe: Adobe PDF Files Display IncorrectlymemberDuncan Edwards Jones22 Mar '10 - 9:38 
I can kind-of explain it but I'm afraid I do not know what to do to resolve it.
 
Basically when you print to a PDF it doesn't know if the target machine is going to have the font you are printing in or not so in certain circumstances the font is embedded in the spool file. However it only embeds the letters that are used which means that the glyph at a given position in the font table may be different from the character you would expect to be there - hence the offset effect.
 
I have not found any way of either (a) knowing that this has occured or (b) un-offsetting the font array but if you do please post it here and I will bake it into the above code.
'--8<------------------------
Ex Datis:
Duncan Jones
 
Free eBook: Printing - a .NET Developer's Guide (Part 1)

GeneralDidn't get The Text From Spool Job using EmfTextRecordmemberm.junaid8614 Jan '10 - 1:25 
I found EMFSpoolfileReader.EMFTextRecord.
 
how can i read Text from Spool Job
Can you please help me its Urgent. I am very Thank full to you
 
Regards
Muhammad Junaid Khan

GeneralRe: Didn't get The Text From Spool Job using EmfTextRecordmemberDuncan Edwards Jones14 Jan '10 - 20:52 
From the start of the EMFTextRecord read the structure thus:
 
        With SpoolBinaryReader
            _Top = .ReadInt32
            _Left = .ReadInt32
            _Bottom = .ReadInt32
            _Right = .ReadInt32
            _GraphicsMode = .ReadInt32
            _scaleX = .ReadSingle
            _scaleY = .ReadSingle
            _PTx = .ReadInt32
            _PTy = .ReadInt32
            _nChars = .ReadInt32
            _offString = .ReadInt32
            _Options = .ReadInt32
            _TxtTop = .ReadInt32
            _TxtLeft = .ReadInt32
            _TxtBottom = .ReadInt32
            _TxtRight = .ReadInt32
            _offDX = .ReadInt32
            If _offString >= 76 Then
                .BaseStream.Seek(_offString - 76, SeekOrigin.Current)
                Dim chars() As Byte
                chars = .ReadBytes(_nChars * 2)
                _Text = System.Text.Encoding.Unicode.GetString(chars) '  New String(chars)
            End If
        End With

 
'--8<------------------------
Ex Datis:
Duncan Jones
Merrion Computing Ltd

GeneralRe: Didn't get The Text From Spool Job using EmfTextRecordmembermujahidcodeproject21 Jun '12 - 0:08 
Hi Junaid,
 
I have the same requirement of reading the text, can u plz share the code if you were able to view the text.
 
Thanks & Regards
Mujahid
GeneralRead Text Printer outputmemberbardill19 Dec '08 - 4:17 
Hi
i am searching for a code that convert every printoutput in a textfile for
a content filtering.
i think with your code i can do this but i not understand how i can read the text from the spool file?
i see you have a EMFTextRecord , but i don't now how i ca rraed it???
have you a example in vb.net
i am not a very good programmer and my english is not the best sorry.
GeneralPrint all pagesmemberCount.Zilch11 Dec '08 - 23:15 
Is there anyway to send all pages of an EMF file to the printer with the listed exe? Unless I'm missing something, I'm having to print each page one-by-one, (to PDFCreator print driver) and then I'll have to use Acrobat or something to join all the pages back together Frown | :-(
GeneralRe: Print all pagesmemberDuncan Edwards Jones12 Dec '08 - 22:18 
Indeed - although I think if you drag the EMF spool file onto the PDF printer icon (control panel -> printer) it might print it?
 
'--8<------------------------
Ex Datis:
Duncan Jones
Merrion Computing Ltd

GeneralRe: Print all pagesmemberCount.Zilch13 Dec '08 - 0:05 
Thanks for the tip, but no, unfortunately I already tried this (PDFCreator under XP using .SPL files). It first prompts you to change this to be the default printer, then fails with a message "This file cannot be printed. Please try opening the file with the correct application and printing from there". Frown | :-(
 
Also tried sharing the virtual printer and issuing "copy file.spl \\computer\pdfcreator" and that gives a PDF with a blank landscape page. Copying the same file to a physical laser printer works fine.
 
Any other ideas appreciated! The view works perfectly, except I have to do everything one page at a time...
GeneralIt's great, thanks. Where can I find the code of SpoolfileReaderBase.dll??? [modified]memberamanofsky10 Oct '08 - 6:40 
Can you please upload it?
Besides, I tried to compile the codes you uploaded successfully after removing the reference SpoolfileReaderBase.dll, but the output appears quite different from the binary you uploaded.
For example, the [FILE] menu, there is no [properties] sub menu items.
 
Can you please upload the latest codes that can compile the binary you uploaded? thanks
 
modified on Friday, October 10, 2008 12:55 PM

GeneralRe: It's great, thanks. Where can I find the code of SpoolfileReaderBase.dll???memberDhanushkatr9 Jun '09 - 18:00 
Please upload the complete code. I need to get the properties of the spool file. In this cording it only allow to open the spooled file but can not see the properties..
 
Thank you
QuestionProblem with GDI+memberhsirc21 Sep '08 - 7:30 
error while open a SPL file.
 

A generic error occurred in GDI+.
Dim emfPage As New System.Drawing.Imaging.Metafile(FileReader.BaseStream)
 
the error is in FileReader.BaseStream
 

 
some solution?
salu2.
AnswerRe: Problem with GDI+memberDuncan Edwards Jones22 Sep '08 - 1:37 
Can you check that the spool file is actually an EMF spool file?
(It could be RAW e.g. postscript or PCL or similar)
 
'--8<------------------------
Ex Datis:
Duncan Jones
Merrion Computing Ltd

GeneralRe: Problem with GDI+memberhsirc23 Sep '08 - 20:09 
wend open a file with notepad, and find a EMF word inside,
 
look this is a file, http://www.paginasprodigy.com/cristianescalante/00009.zip
 
was printed with Firefox 3
 
Great Work Duncan!
GeneralGET SPLmemberEfrain Dominguez Goycochea9 Sep '08 - 9:10 
How can i get the SPL files?
how can i get the relationship between de jobID and the document name?
 

thanks.
GeneralRe: GET SPLmemberhsirc21 Sep '08 - 7:01 
you need set you printer with PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS, and the new documents print, are equal a filename to Jobid, XXXX.spl XXXX=JobId.
 
bad English
Saludos Roll eyes | :rolleyes:
QuestionDevModememberJC_Denton10 Jul '08 - 3:59 
How can I access the Devmode struct for each page in this source code?
 
Thanks a lot.
AnswerRe: DevModememberDuncan Edwards Jones10 Jul '08 - 8:36 
You have to get the SRT_DEVMODE record and then read the DEVMODE from that - it is exactly the same as the DEVMODE structure in the windows api.
 
The SRT_DEVMODE devmode applies to all the pages that come after it until the next SRT_DEVMODE record comes along...so there isn't one devmode per page.
 
'--8<------------------------
Ex Datis:
Duncan Jones
Merrion Computing Ltd

GeneralRe: DevModememberJC_Denton11 Jul '08 - 5:57 
So in your code, where:
 
While recNext.iType <> SpoolerRecordTypes.SRT_EOF
            If recNext.iType = SpoolerRecordTypes.SRT_PAGE Then
                _Pages += 1
            End If
            'SpoolfileReaderPerformaceCounter.Increment()
            Call SkipAHeader(recNext, SpoolBinaryReader)
            recNext = NextHeader(SpoolBinaryReader)
End While
 
I tried that:
        While recNext.iType <> SpoolerRecordTypes.SRT_EOF
            If recNext.iType = SpoolerRecordTypes.SRT_DEVMODE Then
                ' I tried the following:
                Dim newdevmode As New DevMode
                newdevmode = recNext.iType
                _Pages += newdevmode.Copies()
            End If
            If recNext.iType = SpoolerRecordTypes.SRT_PAGE Then
                _Pages += 1
            End If
            'SpoolfileReaderPerformaceCounter.Increment()
            Call SkipAHeader(recNext, SpoolBinaryReader)
            recNext = NextHeader(SpoolBinaryReader)
        End While
 
Obviously it didn't worked...
So how can I read the devmode when I find a SRT_DEVMODE???
 
Thanks a lot for your help.
GeneralRe: DevModememberDuncan Edwards Jones11 Jul '08 - 9:03 
Something like:-
 
'\\ --[DevMode]------------------------------------------------------------
'\\ Represnts a DEVMODE structure stored in a file (shadow or spool...)
'\\ -----------------------------------------------------------------------
Public Class DevMode
 
#Region "Private properties"
    Private dmDeviceName(64) As Char
    Private dmSpecVersion As Short
    Private dmDriverVersion As Short
    Private dmSize As Short
    Private dmDriverExtra As Short
    Private dmFields As Integer
    Private dmOrientation As Short
    Private dmPaperSize As Short
    Private dmPaperLength As Short
    Private dmPaperWidth As Short
    Private dmScale As Short
    Private dmCopies As Short
    Private dmDefaultSource As Short
    Private dmPrintQuality As Short
    Private dmColor As Short
    Private dmDuplex As Short
    Private dmYResolution As Short
    Private dmTTOption As Short
    Private dmCollate As Short
    Private dmFormName(32) As Char
    Private dmUnusedPadding As Short
    Private dmBitsPerPel As Integer
    Private dmPelsWidth As Integer
    Private dmPelsHeight As Integer
    Private dmDisplayFlags As Integer
    Private dmDisplayFrequency As Integer
    Private dmICMMethod As Integer
    Private dmICMIntent As Integer
    Private dmMediaType As Integer
    Private dmDitherType As Integer
    Private dmReserved1 As Integer
    Private dmReserved2 As Integer
    Private dmPanningWidth As Integer
    Private dmPanningHeight As Integer
#End Region
 
#Region "Public properties"
 
#Region "Copies"
    Public ReadOnly Property Copies() As Short
        Get
            If dmCopies < 1 Then
                dmCopies = 1
            End If
            Return dmCopies
        End Get
    End Property
#End Region
#Region "Collate"
    Public ReadOnly Property Collate() As Boolean
        Get
            Return (dmCollate > 0)
        End Get
    End Property
#End Region
#End Region
 
#Region "Public constructors"
    Public Sub New(ByVal FileReader As System.IO.BinaryReader)
        dmDeviceName = FileReader.ReadChars(64)
        'FileReader.BaseStream.Seek(64, IO.SeekOrigin.Current)
        dmSpecVersion = FileReader.ReadInt16
        dmDriverVersion = FileReader.ReadInt16
        dmSize = FileReader.ReadInt16
        dmDriverExtra = FileReader.ReadInt16
        dmFields = FileReader.ReadInt32
        dmOrientation = FileReader.ReadInt16
        dmPaperSize = FileReader.ReadInt16
        dmPaperLength = FileReader.ReadInt16
        dmPaperWidth = FileReader.ReadInt16
        dmScale = FileReader.ReadInt16
        dmCopies = FileReader.ReadInt16
        dmDefaultSource = FileReader.ReadInt16
        dmPrintQuality = FileReader.ReadInt16
        dmColor = FileReader.ReadInt16
        dmDuplex = FileReader.ReadInt16
        dmYResolution = FileReader.ReadInt16
        dmTTOption = FileReader.ReadInt16
        dmCollate = FileReader.ReadInt16
        dmFormName = FileReader.ReadChars(32) '32 chars
        dmUnusedPadding = FileReader.ReadInt16
        dmBitsPerPel = FileReader.ReadInt32
        dmPelsWidth = FileReader.ReadInt32
        dmPelsHeight = FileReader.ReadInt32
        dmDisplayFlags = FileReader.ReadInt32
        dmDisplayFrequency = FileReader.ReadInt32
        dmICMMethod = FileReader.ReadInt32
        dmICMIntent = FileReader.ReadInt32
        dmMediaType = FileReader.ReadInt32
        dmDitherType = FileReader.ReadInt32
        dmReserved1 = FileReader.ReadInt32
        dmReserved2 = FileReader.ReadInt32
        dmPanningWidth = FileReader.ReadInt32
        dmPanningHeight = FileReader.ReadInt32
    End Sub
#End Region
 
End Class
 
wich you would populate thusly:-
'--8<---------------------------
            ElseIf .iType = SpoolerRecordTypes.SRT_DEVMODE Then
                '\\ Spool job DEVMODE
                Dim _dmThis As New DevMode(SpoolBinaryReader)
                _Copies = _dmThis.Copies
                SpoolBinaryReader.BaseStream.Seek(.Seek + 8 + .nSize, SeekOrigin.Begin)
'--8<---------------------------

 
'--8<------------------------
Ex Datis:
Duncan Jones
Merrion Computing Ltd

AnswerRe: DevModememberJC_Denton11 Jul '08 - 9:23 
Thanks a lot Duncan! Big Grin | :-D
GeneralRe: DevModememberUmeshDrift8 Oct '08 - 3:46 
Hi Duncan,
 
I notice that in the attached code you say that the numbr of copies are in the shadow file.
 
        
        '\\ The number of copies is held in the shadow file
        Dim ShadowFilename As String
        If Not Path.GetExtension(SpoolFilename).ToUpper = ".SHD" Then
            ShadowFilename = Path.ChangeExtension(SpoolFilename, ".SHD")
        Else
            ShadowFilename = SpoolFilename
        End If
 
But in the above code you are refering to the spool file.. isnt it.
            ElseIf recNext.iType = SpoolerRecordTypes.SRT_DEVMODE Then
                '\\ Spool job DEVMODE
                Dim _dmThis As New DevMode(SpoolBinaryReader)
                _Copies = _dmThis.Copies
                SpoolBinaryReader.BaseStream.Seek(recNext.Seek + 8 + recNext.nSize, SeekOrigin.Begin)
 
So I am confused, cause when i try to look for SpoolerRecordTypes.SRT_DEVMODE in the spool file, it doesnt come.
 
Please advise.
GeneralRe: DevModememberDuncan Edwards Jones6 Jan '09 - 8:58 
What is held in the spool header file is the # of copies as reported to the spool manager (i.e. what is shown in the printer job queue) but it is possible for different pages within a job to have different numbers of copies. In this case a DEVMODE record would exist for each page for which this different number of copies applies...
 
'--8<------------------------
Ex Datis:
Duncan Jones
Merrion Computing Ltd

GeneralRe: DevModememberroyzhou198516 Jan '09 - 4:16 
DevMode _dmThis = new DevMode(SpoolBinaryReader);
_Copies = _dmThis.Copies;
 
when i try the above code , I get _Copies a 0
I am confused!
 
Is it system problem!
I was running the program on Windows XP
and with the spl file create by the virtual printer!
 
Somebody could help me?
GeneralProblem with HP Laserjetmemberademian4421 May '08 - 11:29 
Problem with HP Laserjet
As one reads the structure. Spl generated by such printers?
tested the printing process RAW and NT EMF and does not work ...
 
greetings and thank you very much
GeneralRe: Problem with HP LaserjetmemberDuncan Edwards Jones21 May '08 - 11:50 
depending on how old the printer is, it is likely to be either PCL 5[^] or PCL XL (aka PCL6)[^]..
 
'--8<------------------------
Ex Datis:
Duncan Jones
Merrion Computing Ltd

GeneralEMF Spoolfile documentation updatememberDuncan Edwards Jones8 May '08 - 23:46 
Microsoft have posted some additional documentation on the Enhanced Metafile Spool Format Specification[^]
 
I'll update the code/article accordingly as soon as I can.
 
'--8<------------------------
Ex Datis:
Duncan Jones
Merrion Computing Ltd

GeneralPrint EMF spool FilememberEfrain Dominguez Goycochea5 May '08 - 13:58 
How Can I print the EMF spool file in VB.NET?
 
I will appreciate your help.
GeneralRe: Print EMF spool FilememberDuncan Edwards Jones9 May '08 - 1:35 
Apologies for taking so long to get back to you
 
Anyhow - you need to convert each SRT_PAGE type emf record to a System.Drawing.Imaging.Metafile() and then use Graphics.DrawImage() in the print page event.
 
To do this, move the file stream to the start of the record and do:-
Dim emfPage As New System.Drawing.Imaging.Metafile(FileReader.BaseStream)
 
Hope this helps,
Duncan
 
'--8<------------------------
Ex Datis:
Duncan Jones
Merrion Computing Ltd

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 21 Aug 2006
Article Copyright 2005 by Duncan Edwards Jones
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid