Selecting the input tray when printing XPS documents

There are many examples on the web of how to print an XPS document, and for the most part they are relatively simple. But when my application needed to do something crazy (like…I don’t know…tell the document which tray to print to), the myriads of how-to’s proved pretty much worthless. In fact, the only useful information I found on the subject was from a post on MSDN forums. This post proved extremely helpful, even containing a c# code sample that I could use almost as-is.

But when I got to the point of implementing that code, I hit a snag. It seems that the document would always print to the last tray on the printer, even though I was telling it to print to a specific tray. It turns out, there was a little bit of detail missing from the sample code, namely a namespace attribute that needs to be added to the xml document that comprises the PrintTicket. The URI for that namespace is likely to be different for each printer your application prints to, so you need to discover it at runtime.

Here’s the updated sample, with my slight modifications:

public static class XpsPrinterUtils
{
private static string GetInputBinName(string printerName, int binIndex, out string nameSpaceURI)
{
string binName = string.Empty;
// get PrintQueue of Printer from the PrintServer
LocalPrintServer printServer = new LocalPrintServer();
PrintQueue printQueue = printServer.GetPrintQueue(printerName);
// get PrintCapabilities of the printer
MemoryStream printerCapXmlStream = printQueue.GetPrintCapabilitiesAsXml();
// read the JobInputBins out of the PrintCapabilities
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(printerCapXmlStream);
// create NamespaceManager and add PrintSchemaFrameWork-Namespace (should be on DocumentElement of the PrintTicket)
// Prefix: psf  NameSpace: xmlDoc.DocumentElement.NamespaceURI = "http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework"
XmlNamespaceManager manager = new XmlNamespaceManager(xmlDoc.NameTable);
manager.AddNamespace(xmlDoc.DocumentElement.Prefix, xmlDoc.DocumentElement.NamespaceURI);
nameSpaceURI = xmlDoc.ChildNodes[1].GetNamespaceOfPrefix("ns0000");
// and select all nodes of the bins
XmlNodeList nodeList = xmlDoc.SelectNodes("//psf:Feature[@name='psk:JobInputBin']/psf:Option", manager);
// fill Dictionary with the bin-names and values
if (nodeList.Count > binIndex)
{
binName = nodeList[binIndex].Attributes["name"].Value;
}
return binName;
}
public static PrintTicket ModifyPrintTicket(PrintTicket ticket, string featureName, string newValue, string nameSpaceURI)
{
if (ticket == null)
{
throw new ArgumentNullException("ticket");
}
// read Xml of the PrintTicket
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(ticket.GetXmlStream());
// create NamespaceManager and add PrintSchemaFrameWork-Namespace (should be on DocumentElement of the PrintTicket)
// Prefix: psf  NameSpace: xmlDoc.DocumentElement.NamespaceURI = "http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework"
XmlNamespaceManager manager = new XmlNamespaceManager(xmlDoc.NameTable);
manager.AddNamespace(xmlDoc.DocumentElement.Prefix, xmlDoc.DocumentElement.NamespaceURI);
// search node with desired feature we're looking for and set newValue for it
string xpath = string.Format("//psf:Feature[@name='{0}']/psf:Option", featureName);
XmlNode node = xmlDoc.SelectSingleNode(xpath, manager);
if (node != null)
{
if (newValue.StartsWith("ns0000"))
{
// add namespace to xml doc
XmlAttribute namespaceAttribute = xmlDoc.CreateAttribute("xmlns:ns0000");
namespaceAttribute.Value = nsNameSpaceURI;
xmlDoc.DocumentElement.Attributes.Append(namespaceAttribute);
}
node.Attributes["name"].Value = newValue;
}
// create a new PrintTicket out of the XML
MemoryStream printTicketStream = new MemoryStream();
xmlDoc.Save(printTicketStream);
printTicketStream.Position = 0;
PrintTicket modifiedPrintTicket = new PrintTicket(printTicketStream);
// for testing purpose save the printticket to file
//FileStream stream = new FileStream("modPrintticket.xml", FileMode.CreateNew, FileAccess.ReadWrite);
//modifiedPrintTicket.GetXmlStream().WriteTo(stream);
return modifiedPrintTicket;
}
}
// example of calling above code
string nameSpaceURI = string.Empty;
string selectedBin = XpsPrinterUtils.GetInputBinName(PrinterName, PaperBin, out nameSpaceURI);
PrintTicket myPrintTicket = XpsPrinterUtils.ModifyPrintTicket(defaultPrintTicket, "psk:JobInputBin", selectedBin, nameSpaceURI);
[adsense_id=”1″]

Firefox add-on: Open in IE

I just uploaded the newest version of my first add-on for the Firefox browser. The add-on is called “Open in IE”. It adds an item to the context menu for links giving you the option to open the link in Internet Explorer. It comes in handy for those few sites that just don’t want to play nice with the best browser out there. You can download the add-on here.

[adsense_id=”1″]