How do I get a PrintTicket

 It just came to my attention today that there's not really a good piece of text out there that answers this question, so here's a go at it:

A PrintTicket is, in some sense, just a bag of settings. Acquiring a PrintTicket requires you to supply the data that you want to have in the PrintTicket. Windows has, for the last... well, a long time... used a structure called DEVMODE to handle print job settings, the same basic stuff that PrintTicket holds. While you could construct a PrintTicket from scratch, and you could use a PrintTicket to get a PrintTicket, the most common starting point for working with PrintTicket is to take some saved settings that are already in a DEVMODE, and convert them. While it's not quite sample code, this should give you a pretty good idea of how to go about writing the code to get a PrintTicket from a DEVMODE.

1) Get the printer settings:

Windows stores print job settings in a couple of different ways, and depending on your scenario any of these might do. Usually what you want is the user default settings for the selected or default print queue. Start by getting a printer handle. You can do this with OpenPrinter, specifying a printer name. After you have the handle, call GetPrinter to access the DEVMODE. You have some choices to make here, because you can request levels 2, 8, and 9 to get a DEVMODE. Each does slightly different things. The MSDN ref is below.

2) Get a PrintTicket handle:

This is the easy part.  Take the same string that you used for OpenPrinter, and pass it to PTOpenProvider. The PrintTicket APIs won't accept a printer handle, they need a provider handle.

3) Get a stream object:

The PrintTicket APIs are all designed around streams. That means that to obtain the actual print ticket data, you'll need an IStream to write to. The quickest, easiest stream object to use is one provided by the CreateStreamOnHGlobal method.

4) Convert the DEVMODE to a PrintTicket:

The API you'll use here is PTConvertDevModeToPrintTicket. Pass your handle, your DEVMODE and a pointer to your IStream object.  The API will write to the stream.

5) Read the PrintTicket data

If you're using a stream from the CreateStreamOnHGlobal method, you'll need to use the Seek method on the object to seek back to the beginning of the stream before reading the data. If you use a custom IStream object, you could also make the stream write the data directly to where you want it.

MSDN docs for the methods described here:

OpenPrinter
https://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/prntspol_9qnm.asp

GetPrinter
https://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/prntspol_1gky.asp

CreateStreamOnHGlobal
https://msdn2.microsoft.com/en-us/library/ms886955.aspx

PTOpenProvider
https://search.msdn.microsoft.com/search/default.aspx?__VIEWSTATE=&query=PTOpenProvider&siteid=0&tab=0

PTConvertDevModeToPrintTicket
https://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/prntspol_PTConvertDevModeToPrintTicket.asp