【问题标题】:GetPrintCapabilities will not return all page sizesGetPrintCapabilities 不会返回所有页面大小
【发布时间】:2010-06-04 10:44:35
【问题描述】:

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 对象是一种称为 PrintCapabilities 文档的特定类型 XML 文档的易于使用的表示。”但是文档比对象Full description拥有更多信息

【问题讨论】:

    标签: c# wpf xml printing


    【解决方案1】:

    您必须保存从 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>
    

    【讨论】:

      【解决方案2】:

      尽管这是一个较旧的线程,但当我们需要读取和更新自定义属性时,它有助于为我们指明正确的方向。

      以下代码改编自此线程: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
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-02-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-26
        • 2014-12-30
        • 2019-01-20
        • 1970-01-01
        相关资源
        最近更新 更多