Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Print to XPS from Code

4.64/5 (7 votes)
5 Nov 2013CPOL3 min read 47.5K   3.1K  
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)