none
Printing Documents by Windows Service RRS feed

  • Question

  • I am going to develop a Windows Service to print PDF files. However, according to https://msdn.microsoft.com/en-us/library/system.drawing.printing(v=vs.110).aspx, it is not suggested to use System.Drawing.Printing. Is there any library from .NET Framework C# are able to do it? Thanks.
    Tuesday, November 15, 2016 7:32 AM

Answers

All replies

  • Hi,

    I created a project with a library Spire.PDF, You can give below solution a try.

    Firstly, convert the PDF to XPS and then print the XPS document using the XpsPrint API. 

    public void PrintOnServer(string fileName)
            {
                MemoryStream ms = new MemoryStream();
                PdfDocument pdfDoc = new PdfDocument();
                pdfDoc.LoadFromFile(fileName);
                pdfDoc.SaveToStream(ms, FileFormat.XPS);
                ms.Position = 0;
                XpsPrint.XpsPrintHelper.Print(ms, @"\\192.168.1.104\HP LaserJet P1007", "SpireTest",true);
            }

    The XpsPrint API:

    using System;
    using System.ComponentModel;
    using System.IO;
    using System.Runtime.InteropServices;
    
    namespace XpsPrint
    {
        /// <summary>
        /// A utility class to print a file via Windows  XpsPrint API.
        /// </summary>
        public class XpsPrintHelper
        {
            /// <summary>
            /// No ctor.
            /// </summary>
            private XpsPrintHelper()
            {
            }
    
            /// <summary>
            /// Sends a stream that contains a document in the XPS format to a printer using the XpsPrint API.
            /// </summary>
            /// <param name="stream"></param>
            /// <param name="printerName"></param>
            /// <param name="jobName">Job name. Can be null.</param>
            /// <param name="isWait">True to wait for the job to complete. False to return immediately after submitting the job.</param>
            /// <exception cref="Exception">Thrown if any error occurs.</exception>
            public static void Print(Stream stream, string printerName, string jobName, bool isWait)
            {
                if (stream == null)
                    throw new ArgumentNullException("stream");
                if (printerName == null)
                    throw new ArgumentNullException("printerName");
    
                // Create an event that we will wait on until the job is complete.
                IntPtr completionEvent = CreateEvent(IntPtr.Zero, true, false, null);
                if (completionEvent == IntPtr.Zero)
                    throw new Win32Exception();
    
                try
                {
                    IXpsPrintJob job;
                    IXpsPrintJobStream jobStream;
                    StartJob(printerName, jobName, completionEvent, out job, out jobStream);
    
                    CopyJob(stream, job, jobStream);
    
                    if (isWait)
                    {
                        WaitForJob(completionEvent);
                        CheckJobStatus(job);
                    }
                }
                finally
                {
                    if (completionEvent != IntPtr.Zero)
                        CloseHandle(completionEvent);
                }
            }
            private static 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 static 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 static void WaitForJob(IntPtr completionEvent)
            {
                const int INFINITE = -1;
                switch (WaitForSingleObject(completionEvent, INFINITE))
                {
                    case WAIT_RESULT.WAIT_OBJECT_0:
                        // Expected result, do nothing.
                        break;
                    case WAIT_RESULT.WAIT_FAILED:
                        throw new Win32Exception();
                    default:
                        throw new Exception("Unexpected result when waiting for the print job.");
                }
            }
    
            private static 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_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);
        }
    
        [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
        }
    }
    

    Regards,

    Michael

    Tuesday, November 15, 2016 9:33 AM
  • Hi Polly,

    >>Is there any library from .NET Framework C# are able to do it?

    As far as I know, there is no other class or build namespace to help you implement in .Net Framework.

    Here are two viable solutions

    1. Write your own printing DLL using the Win32 API (in C/C++ for instance), then use it from your service with P/Invoke
    2. Write your own printing COM+ component, then uses it from your service. You also could try to find third party COM+ component

    In addition, here is a similar thread as below, please have a look.

    http://www.codeproject.com/Questions/444005/How-to-print-Document-through-Window-Services-in-C

    Some useful links: http://stackoverflow.com/questions/416314/print-html-document-from-windows-service-in-c-sharp-without-print-dialog.

    http://support.microsoft.com/kb/322091

    In a short summary, Printing from a service is a bad idea. You'd better use winfrom application instead.

    Best regards,

    Kristin


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • Proposed as answer by Kristin Xie Wednesday, November 16, 2016 9:48 AM
    • Marked as answer by Polly Law Friday, January 6, 2017 9:31 AM
    Wednesday, November 16, 2016 6:12 AM
  • Hi Polly,

    Any updates now? If yes, please post here. If no, please help close this thread by marking helpful reply as an answer. Thanks for your support and cooperation.

    With warm regards,


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    • Edited by Kristin Xie Monday, November 21, 2016 9:19 AM
    Monday, November 21, 2016 9:18 AM
  • It seems that there is no directly solution from .NET Framework.
    Friday, January 6, 2017 9:31 AM