GetPrintCapabilities不会返回所有页面大小

时间:2010-06-04 10:44:36

标签: c# wpf xml printing

PrintCapabilities printCapabilites = SelectedPrinter.GetPrintCapabilities();     IEnumerable pagesizeList = printCapabilites.PageMediaSizeCapability;

以上代码未列出打印机驱动程序支持的所有页面大小,这是我的问题。

作为示例,如果您使用Microsoft XPS打印机驱动程序,您会发现pagesizeList(上面)将缺少某些页面大小。 “Letter Small”是缺少页面大小之一(MS Word将成功列出此页面大小)。

作为 快速 检查,我将打印机功能转储到xml,如下所示:

long gpCLen = _selectedPrinter.GetPrintCapabilitiesAsXml().Length;
FileStream fs = File.OpenWrite(@"c:\test.txt");
MemoryStream ms = _selectedPrinter.GetPrintCapabilitiesAsXml();
byte[] b = new byte[gpCLen];
ms.Read(b, 0, (int)gpCLen);
fs.Write(b, 0, (int)gpCLen);
fs.Close();

生成的xml文件中的PageMediaSize节点确实具有所有页面大小和缺少的页面大小。

显示的网页似乎名称以psk开头:

<psf:Option name="psk:ISOA4" constrained="psk:None">

但未显示的网页似乎有:

<psf:Option name="ns0000:LETTERSMALL" constrained="psk:None">

未显示的Epson打印驱动程序页面类似:

<psf:Option name="epns200:IndexCard5x8" constrained="psk:None">

基本上,名称以“psk”PageMediaSizeCapability显示的页面显示,但如果它是制造自定义的,即epns200,ns0000,则不会列出。任何想法为什么以及如何解决这个问题?节点/页面在那里但是PageMediaSizeCapability不喜欢它!

提前致谢

编辑:

作为MS状态'PrintCapabilities对象是一种易于使用的表示某种类型的XML文档,称为PrintCapabilities文档。但是文档的信息比对象Full description

更多

2 个答案:

答案 0 :(得分:3)

您必须保存从PrintCapabilities xml读取的纸张名称,并使用它来创建PrintTicket xml(PrintTicket具有接受xml流的构造函数),然后使用PrintTicket。以下是PrintTicket XML的示例(ns0000:User0000000257是我创建的自定义纸张尺寸的名称):

    <psf:PrintTicket xmlns:psf="http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
           xmlns:psk="http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords"
           xmlns:ns0000="http://schemas.microsoft.com/windows/printing/oemdriverpt/Samsung_CLP-310 Series/5.1.2600.2180/" version="1">
  <psf:Feature name="psk:PageMediaSize">
    <psf:Option name="ns0000:User0000000257"></psf:Option>
  </psf:Feature>
</psf:PrintTicket>

答案 1 :(得分:1)

尽管这是一个较旧的主题,但在我们需要读取和更新自定义属性时,指向正确的方向很有帮助。

以下代码改编自此主题:XPS打印,托盘选择和InputBinCapability(InputBin)=问题:http://www.windows-tech.info/14/29c7cf575646cb39.php。 Jo0815底部的答案包含了你在下面看到的大部分内容,尤其是指向正确方向的XPath表达式。

此外,使用您的更改更新PrintQueue.UserPrintTicket,而不是DefaultPrintTicket。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Printing;
using System.Text;
using System.Windows;
using System.Xml;

// Adapted
// From: XPS Printing, Tray selection and InputBinCapability (InputBin) = Problem
// Link: http://www.windows-tech.info/14/29c7cf575646cb39.php - last answer at bottom by Jo0815

namespace WpfApplication1
{
    public static class WpfPrinterUtilities
    {
        #region GetPrintQueues

        /// <summary>
        /// Gets a dictionary of print queues where Key = print queue name
        /// and Value = the print queue object.
        /// </summary>
        /// <param name="printQueueTypes">EnumeratedPrintQueueTypes params array of the types of print queues being requested.</param>
        /// <returns>Dictionary of requested print queues where Key = print queue name and Value = the print queue object itself.</returns>
        public static Dictionary<string, PrintQueue> GetPrintQueues(params EnumeratedPrintQueueTypes[] printQueueTypes)
        {
            var server = new PrintServer();
            return server.GetPrintQueues(printQueueTypes).ToDictionary(pq => pq.ShareName != null ? pq.ShareName : pq.Name);
        }

        #endregion

        #region GetInputBins

        /// <summary>
        /// Reads print queue configuration xml to retrieve the current list of input bins.
        /// </summary>
        /// <param name="printQueue">The print queue to query.</param>
        /// <returns></returns>
        public static Dictionary<string, string> GetInputBins(PrintQueue printQueue)
        {
            Dictionary<string, string> inputBins = new Dictionary<string, string>();

            // Get the print queue PrintCapabilities.
            XmlDocument xmlDoc = null;
            using (MemoryStream stream = printQueue.GetPrintCapabilitiesAsXml())
            {
                // Read the JobInputBins out of the PrintCapabilities.
                xmlDoc = new XmlDocument();
                xmlDoc.Load(stream);
            }

            // 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);

            // Select all job input bins.
            XmlNodeList nodeList = xmlDoc.SelectNodes("//psf:Feature[@name='psk:JobInputBin']/psf:Option/psf:Property", manager);

            // Load the Dictionary with the bin values and names. The names will be used to modify the print ticket if necessary.
            foreach (XmlNode node in nodeList)
            {
                inputBins.Add(node.LastChild.InnerText, node.ParentNode.Attributes[0].Value);
            }

            return inputBins;
        }

        #endregion

        #region ModifyPrintTicket

        /// <summary>
        /// Modifes a print ticket xml after updating a feature value.
        /// 
        /// Sample usage:
        /// Get Dictionary with Inputbins by calling the other method
        /// and get "value" for the desired inputbin you'd like to use...
        /// ...
        /// desiredTray is then something like "NS0000:SurpriseOption7" for example.
        /// defaultPrintTicket is the (Default)PrintTicket you want to modify from the PrintQueue for example
        /// PrintTicket myPrintTicket = WpfPrinterUtils.ModifyPrintTicket(defaultPrintTicket, "psk:JobInputBin", desiredTray);
        /// </summary>
        /// <param name="ticket"></param>
        /// <param name="featureName"></param>
        /// <param name="newValue"></param>
        /// <param name="printQueueName">Optional - If provided, a file is created with the print ticket xml. Useful for debugging.</param>
        /// <param name="folder">Optional - If provided, the path for a file is created with the print ticket xml. Defaults to c:\. Useful for debugging.</param>
        /// <param name="displayMessage">Optional - True to display a dialog with changes. Defaults to false. Useful for debugging.</param>
        /// <returns></returns>
        public static PrintTicket ModifyPrintTicket(PrintTicket ticket, string featureName, string newValue, string printQueueName = null, string folder = null, bool displayMessage = false)
        {
            if (ticket == null)
            {
                throw new ArgumentNullException("ticket");
            }

            // Read Xml of the PrintTicket xml.
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(ticket.GetXmlStream());

            // Create NamespaceManager and add PrintSchemaFrameWork-Namespace hinzufugen (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 (node.Attributes["name"].Value != newValue)
                {
                    if (displayMessage)
                    {
                        System.Windows.MessageBox.Show(string.Format("OldValue: {0}, NewValue: {1}", node.Attributes["name"].Value, newValue), "Input Bin");
                    }
                    node.Attributes["name"].Value = newValue;
                }
            }

            // Create a new PrintTicket out of the XML.
            PrintTicket modifiedPrintTicket = null;
            using (MemoryStream stream = new MemoryStream())
            {
                xmlDoc.Save(stream);
                stream.Position = 0;
                modifiedPrintTicket = new PrintTicket(stream);
            }

            // For testing purpose save the print ticket to a file.
            if (!string.IsNullOrWhiteSpace(printQueueName))
            {
                if (string.IsNullOrWhiteSpace(folder))
                {
                    folder = "c:\\";
                }
                // Colons are not valid in a file name.
                newValue = newValue.Replace(':', ';');
                printQueueName = string.Format("{0} PrintTicket {1}.xml", Path.Combine(folder, printQueueName), newValue);
                if (File.Exists(printQueueName))
                {
                    File.Delete(printQueueName);
                }
                if (!Directory.Exists(Path.GetDirectoryName(printQueueName)))
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(printQueueName));
                }
                using (FileStream stream = new FileStream(printQueueName, FileMode.CreateNew, FileAccess.ReadWrite))
                {
                    modifiedPrintTicket.GetXmlStream().WriteTo(stream);
                }
            }

            return modifiedPrintTicket;
        }

        #endregion
    }
}