Click here to Skip to main content
15,888,060 members
Articles / Programming Languages / C#
Tip/Trick

Print to XPS from Code

Rate me:
Please Sign up or sign in to vote.
4.64/5 (7 votes)
5 Nov 2013CPOL3 min read 46.6K   3.1K   17   5
Generate XPS documents from code using the XPS Passthrough driver.

This article appears in the Third Party Products and Tools section. Articles in this section are for the members only and must not be used to promote or advertise products in any way, shape or form. Please report any spam or advertising.

Introduction

The Windows XPS Document writer provides a handy tool for generating XPS documents. However, it is limited in its usage for projects, as it requires user intervention to enter a destination file name. This article provides a ready-to-use class that allows the production of an XPS document directly from code.

Background

Our project required XPS versions of documents contained within our ECM to be generated on a server-side process. Optimally, this process would be a Windows service. The Windows XPS Document Writer, as it stands, was not suitable due to its requiring user input for each document that was to be rendered.

A Google of this issue came up with the same solution just about everywhere - use the XPS Passthrough print driver, freely available from Frogmore. This was great, apart from the fact that none of the solutions describe how to use this driver from code. This article demonstrates the solution to that problem.

Using the Code

This code is centered around creating a virtual printer, and then letting this virtual printer know the location of the required output. It creates the output port on the "Local Port" monitor, using the extremely poorly documented "AddPortEx" API. Although this function has been deprecated, the Local Port monitor has not changed since the days of NT3, and is still exposed. If it does happen to go away, then this API call may need to be changed to use a WMI object.

The VirtualPrinter class can be used either as a single use output device, or can be persisted and have the output port (XPS file location) changed for individual print jobs. Note that the disposal function of the Virtual printer will destroy a virtual printer if and only if that instance created it. It will also destroy the operating system's knowledge of any ports it created.

To use the code, simply create an instance of the VirtualPrinter class, passing it a printer name and a filename to send the output to. Use this printer name to direct output to the specified XPS file. To create another XPS document, simply call the SetPort method of the Virtual printer, passing it the new file name.

using (VirtualPrinter printer = new VirtualPrinter("MyXPSPrinter", "File1.xps")) {
    PrintReport1To("MyXPSPrinter");
    printer.SetPort("File2.xps");
    PrintReport2To("MyXPSPrinter");
}

The "using" class above will cause the Dispose method of the VirtualPrinter to be called, which will delete "MyXPSPrinter" from the operating system's printers, as will as removing "File1.xps" and "File2.xps" from the operating system's available ports.

The sample code included demonstrates two different uses of the VirtualPrinter class. Firstly, it demonstrates initiating a print job, and printing some sort of output directly from the code. This uses the standard System.Printing functionality provided in the .NET framework. It should be noted that this functionality is not supported in a Windows Service - to print from a service, code would need to access the low level windows API's via PInvoke.

The second sample demonstrates printing of a file on disk using the default file association. First, it attempts to find a "printto" verb for the specified file type, and if it exists, then the command is issued to print to the specified virtual printer. Otherwise, it sets the default printer to the virtual printer, and executes the "print" verb for the specified file.

License

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


Written By
Software Developer
Australia Australia
Been programming for 40 years now, starting when I was 13 on DEC PDP 11 (back in the day of paper tape storage, and hex switch boot procedures). Got right into micro-computers from an early age, with machines like the Dick Smith Sorcerer and the CompuColor II. Started CP/M and MS-DOS programming in the mid 1980's. By the end of the '80's, I was just starting to get a good grip on OOP (Had Zortech C++ V1.0).

Got into ATL and COM programming early 2002. As a result, my gutter vocabulary has expanded, but it certainly keeps me off the streets.

Recently, I have had to stop working full time as a programmer due to permanent brain damage as a result of a tumour (I just can't keep up the pace required to meet KPI's). I still like to keep my hand in it, though, and will probably post more articles here as I discover various tricky things.

Comments and Discussions

 
Questionhow about xp? Pin
Greenlove11127-Nov-13 18:58
Greenlove11127-Nov-13 18:58 
AnswerRe: how about xp? Pin
Midi_Mick27-Nov-13 19:33
professionalMidi_Mick27-Nov-13 19:33 
SuggestionName of driver on windows 8 has changed Pin
Christoph Weber7-Nov-13 5:45
Christoph Weber7-Nov-13 5:45 
GeneralRe: Name of driver on windows 8 has changed Pin
Midi_Mick7-Nov-13 13:33
professionalMidi_Mick7-Nov-13 13:33 
GeneralRe: Name of driver on windows 8 has changed Pin
Christoph Weber7-Nov-13 20:28
Christoph Weber7-Nov-13 20:28 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.