代码之家  ›  专栏  ›  技术社区  ›  E Rolnicki

打印XAML-缺少字体问题[重复]

  •  1
  • E Rolnicki  · 技术社区  · 15 年前

    我正在尝试从上的windows服务打印XPS文档。net框架。因为Microsoft不支持使用系统打印。绘画使用系统打印nor。正在打印(WPF),我正在使用本机XPSPrint API。 这是Aspose在 http://www.aspose.com/documentation/.net-components/aspose.words-for-.net/howto-print-a-document-on-a-server-via-the-xpsprint-api.html

    当我尝试从windows服务打印XPS文档时,结果包含奇怪的字符,而不是我想要的文本。

    我尝试了不同的打印机(包括虚拟打印机,例如PDFCreator)、不同的用户和服务用户权限、不同的xps生成器(aspose、word 2007、word 2010)、不同的平台(windows 7、windows 2008 R2),但都有相同的结果。

    有人知道怎么解决这个问题吗?任何帮助都将不胜感激!

    对于那些想尝试的人,我通过以下方式共享了一些文件:

    https://docs.google.com/leaf?id=0B4J93Ly5WzQKNWU2ZjM0MDYtMjFiMi00NzM0LTg4MTgtYjVlNDA5NWQyMTc3&hl=nl

    • 文件xps:要打印的xps文档
    • document\u printed\u to\u pdfcreator。pdf:显示问题所在的打印文档
    • XpsPrintTest。zip:带有示例代码的VS2010示例解决方案

    托管windows服务的示例代码为:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Diagnostics;
    using System.Linq;
    using System.ServiceProcess;
    using System.Text;
    using System.IO;
    using System.Threading;
    using System.Runtime.InteropServices;
    
    namespace PrintXpsService
    {
    public partial class XpsPrintService : ServiceBase
    {
        // Change name of printer here
        private String f_printerName = "PDFCreator";
    
        // path to some file where logging is done
        private String f_logFile = @"C:\temp\testdoc\xps_printing_service_log.txt";
    
        // path to xps file to print
        private String f_xpsFile = @"C:\temp\testdoc\document.xps";
    
        public XpsPrintService()
        {
            InitializeComponent();
        }
    
        private void Log(String fmt, params Object[] args)
        {
            try
            {
                DateTime now = DateTime.Now;
    
                using (StreamWriter wrt = new StreamWriter(f_logFile, true))
                {
                    wrt.Write("{0} {1} - ", now.ToShortDateString(), now.ToShortTimeString());
                    wrt.WriteLine(fmt, args);
                }
            }
            catch (Exception ex)
            {
            }
        }
    
        protected override void OnStart(string[] args)
        {
            // uncomment to allow to connect debugger
            //int i = 0;
            //while (i == 0)
            //{
            //    if (i == 0)
            //    {
            //        Thread.Sleep(1000);
            //    }
            //}
    
            Log("Starting Service");
            try
            {
                Log("Printing xps file {0}", f_xpsFile);
    
                using (Stream stream = new FileStream(f_xpsFile, FileMode.Open, FileAccess.Read))
                {
                    Log("Starting to print on printer {0}", f_printerName);
                    String jobName = f_xpsFile;
                    this.Print(stream, jobName);
                }
                Log("Document printed");
            }
            catch (Exception ex)
            {
                Log("Exception during execution: {0}", ex.Message);
                Log("  {0}", ex.StackTrace);
                Exception inner = ex.InnerException;
                while (inner != null)
                {
                    Log("=== Inner Exception: {0}", inner.Message);
                    Log("    {0}", inner.StackTrace);
                    inner = inner.InnerException;
                }
            }
        }
    
        protected override void OnStop()
        {
        }
    
        public void Print(Stream stream, String jobName)
        {
            String printerName = f_printerName;
            IntPtr completionEvent = CreateEvent(IntPtr.Zero, true, false, null);
            try
            {
                IXpsPrintJob job;
                IXpsPrintJobStream jobStream;
    
                StartJob(printerName, jobName, completionEvent, out job, out jobStream);
                CopyJob(stream, job, jobStream);
                WaitForJob(completionEvent, -1);
                CheckJobStatus(job);
            }
            finally
            {
                if (completionEvent != IntPtr.Zero)
                    CloseHandle(completionEvent);
            }
        }
    
        private void StartJob(String printerName,
            String jobName, IntPtr completionEvent,
            out IXpsPrintJob job,
            out IXpsPrintJobStream jobStream)
        {
            int result = StartXpsPrintJob(printerName, jobName, null, IntPtr.Zero, completionEvent,
                null, 0, out job, out jobStream, IntPtr.Zero);
            if (result != 0)
                throw new Win32Exception(result);
        }
    
    
        private void CopyJob(Stream stream, IXpsPrintJob job, IXpsPrintJobStream jobStream)
        {
            try
            {
                byte[] buff = new byte[4096];
                while (true)
                {
                    uint read = (uint)stream.Read(buff, 0, buff.Length);
                    if (read == 0)
                        break;
                    uint written;
                    jobStream.Write(buff, read, out written);
    
                    if (read != written)
                        throw new Exception("Failed to copy data to the print job stream.");
                }
    
                // Indicate that the entire document has been copied.
                jobStream.Close();
            }
            catch (Exception)
            {
                // Cancel the job if we had any trouble submitting it.
                job.Cancel();
                throw;
            }
        }
    
        private void WaitForJob(IntPtr completionEvent, int timeout)
        {
            if (timeout < 0)
                timeout = -1;
    
            switch (WaitForSingleObject(completionEvent, timeout))
            {
                case WAIT_RESULT.WAIT_OBJECT_0:
                    // Expected result, do nothing.
                    break;
    
                case WAIT_RESULT.WAIT_TIMEOUT:
                    // timeout expired
                    throw new Exception("Timeout expired");
    
                case WAIT_RESULT.WAIT_FAILED:
                    throw new Exception("Wait for the job to complete failed");
    
                default:
                    throw new Exception("Unexpected result when waiting for the print job.");
            }
        }
    
        private void CheckJobStatus(IXpsPrintJob job)
        {
            XPS_JOB_STATUS jobStatus;
            job.GetJobStatus(out jobStatus);
            switch (jobStatus.completion)
            {
                case XPS_JOB_COMPLETION.XPS_JOB_COMPLETED:
                    // Expected result, do nothing.
                    break;
                case XPS_JOB_COMPLETION.XPS_JOB_IN_PROGRESS:
                    // expected, do nothing, can occur when printer is paused
                    break;
                case XPS_JOB_COMPLETION.XPS_JOB_FAILED:
                    throw new Win32Exception(jobStatus.jobStatus);
                default:
                    throw new Exception("Unexpected print job status.");
            }
        }
    
        [DllImport("XpsPrint.dll", EntryPoint = "StartXpsPrintJob")]
        private static extern int StartXpsPrintJob(
            [MarshalAs(UnmanagedType.LPWStr)] String printerName,
            [MarshalAs(UnmanagedType.LPWStr)] String jobName,
            [MarshalAs(UnmanagedType.LPWStr)] String outputFileName,
            IntPtr progressEvent,   // HANDLE
            IntPtr completionEvent, // HANDLE
            [MarshalAs(UnmanagedType.LPArray)] byte[] printablePagesOn,
            UInt32 printablePagesOnCount,
            out IXpsPrintJob xpsPrintJob,
            out IXpsPrintJobStream documentStream,
            IntPtr printTicketStream);  // This is actually "out IXpsPrintJobStream", but we don't use it and just want to pass null, hence IntPtr.
    
        [DllImport("Kernel32.dll", SetLastError = true)]
        private static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName);
    
        [DllImport("Kernel32.dll", SetLastError = true, ExactSpelling = true)]
        private static extern WAIT_RESULT WaitForSingleObject(IntPtr handle, Int32 milliseconds);
    
        [DllImport("Kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(IntPtr hObject);
    }
    
    /// <summary>
    /// This interface definition is HACKED.
    /// 
    /// It appears that the IID for IXpsPrintJobStream specified in XpsPrint.h as 
    /// MIDL_INTERFACE("7a77dc5f-45d6-4dff-9307-d8cb846347ca") is not correct and the RCW cannot return it.
    /// But the returned object returns the parent ISequentialStream inteface successfully.
    /// 
    /// So the hack is that we obtain the ISequentialStream interface but work with it as 
    /// with the IXpsPrintJobStream interface. 
    /// </summary>
    [Guid("0C733A30-2A1C-11CE-ADE5-00AA0044773D")]  // This is IID of ISequenatialSteam.
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    interface IXpsPrintJobStream
    {
        // ISequentualStream methods.
        void Read([MarshalAs(UnmanagedType.LPArray)] byte[] pv, uint cb, out uint pcbRead);
        void Write([MarshalAs(UnmanagedType.LPArray)] byte[] pv, uint cb, out uint pcbWritten);
        // IXpsPrintJobStream methods.
        void Close();
    }
    
    [Guid("5ab89b06-8194-425f-ab3b-d7a96e350161")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    interface IXpsPrintJob
    {
        void Cancel();
        void GetJobStatus(out XPS_JOB_STATUS jobStatus);
    }
    
    [StructLayout(LayoutKind.Sequential)]
    struct XPS_JOB_STATUS
    {
        public UInt32 jobId;
        public Int32 currentDocument;
        public Int32 currentPage;
        public Int32 currentPageTotal;
        public XPS_JOB_COMPLETION completion;
        public Int32 jobStatus; // UInt32
    };
    
    enum XPS_JOB_COMPLETION
    {
        XPS_JOB_IN_PROGRESS = 0,
        XPS_JOB_COMPLETED = 1,
        XPS_JOB_CANCELLED = 2,
        XPS_JOB_FAILED = 3
    }
    
    enum WAIT_RESULT
    {
        WAIT_OBJECT_0 = 0,
        WAIT_ABANDONED = 0x80,
        WAIT_TIMEOUT = 0x102,
        WAIT_FAILED = -1 // 0xFFFFFFFF
    }
    }
    

    注意:有关更多信息,请访问以下链接:

    0 回复  |  直到 9 年前
        1
  •  6
  •   Steven    14 年前

    我与microsoft讨论了这个问题,我们发现这个问题与打印机后台处理程序中不正确的字体替换有关。当打印机设置为不假脱机文档时,也可以通过windows服务正确打印文档。否则,除arial(可能还有其他一些)以外的所有字体都会被另一种字体替代。在我提供的示例中,calibri被wingdings替代。

    因此,他们承认这是一个错误,但目前他们不会解决它。这将取决于有多少人将遭受此错误的折磨,以便他们决定是否愿意修复它。。。

    推荐文章