none
Printing from windows service on windows 8 fails RRS feed

  • Question

  • I have a windows service application written in C# .NET. This application is used to generate a report pdf by printing document to local software printer that generates PDFs. This works well on Windows XP and Windows 7. Unfortunately I found that on Windows 8 it fails. Then I found out that printing to any (even physical) printer on Windows 8 fails when I print from my service. What is missing in my program to work? I'm printing this way:

    FlowDocument document = MyDocument;
    var source = document as IDocumentPaginatorSource;
    var documentPaginator = source.DocumentPaginator;
    
    using (var printServer = new LocalPrintServer())
    {
        PrintQueue queue = printServer.GetPrintQueue(printerName);
        XpsDocumentWriter docWriter = PrintQueue.CreateXpsDocumentWriter(queue);
    
        // Print ticket - Approach 1
        // PrintTicket printTicket = queue.DefaultPrintTicket.Clone();
    
        // Print ticket - Approach 2
        var printTicket = new PrintTicket
        {
            PageOrientation = PageOrientation.Landscape,
            PageMediaSize = new PageMediaSize(PageMediaSizeName.ISOA4), // set size of media (paper)
        };
    
    
        documentPaginator.PageSize = new Size(document.PageWidth, document.PageHeight);
        docWriter.Write(documentPaginator, printTicket);
    }

    Service is set to 'system account' without 'interacting with desktop' (but I tried that too or to login as local user).

    This results into exception on Windows 8. When using 'Print ticket - Approach 1':

    System.Printing.PrintQueueException: PrintTicket provider failed to bind to printer. Win32 error: -2147467231
    at MS.Internal.Printing.Configuration.PTProvider..ctor(String deviceName, Int32 maxVersion, Int32 clientVersion)
    at MS.Internal.Printing.Configuration.PTProviderBase.Create(String deviceName, Int32 maxVersion, Int32 clientVersion)
    at System.Printing.PrintTicketManager..ctor(String deviceName, Int32 clientPrintSchemaVersion)
    at System.Printing.PrintQueue.get_DefaultPrintTicket()

    Using 'Print ticket - Approach 2':

    Exception encountered: System.Printing.PrintQueueException: Fehler beim Binden des PrintTicket-Anbieters an den Drucker. Win32-Fehler: -2147467231
    bei MS.Internal.Printing.Configuration.PTProvider..ctor(String deviceName, Int32 maxVersion, Int32 clientVersion)
    bei MS.Internal.Printing.Configuration.PTProviderBase.Create(String deviceName, Int32 maxVersion, Int32 clientVersion)
    bei System.Printing.PrintTicketManager..ctor(String deviceName, Int32 clientPrintSchemaVersion)
    bei System.Printing.PrintQueue.get_UserPrintTicket()
    bei System.Printing.PrintQueue.get_CurrentJobSettings()
    bei System.Printing.PrintQueue.CreateSerializationManager(Boolean isBatchMode, Boolean mustSetJobIdentifier)
    bei System.Windows.Xps.XpsDocumentWriter.BeginWrite(Boolean batchMode, Boolean asyncMode, Boolean setPrintTicketHandler, PrintTicket printTicket, PrintTicketLevel printTicketLevel, Boolean printJobIdentifierSet)
    bei System.Windows.Xps.XpsDocumentWriter.Write(DocumentPaginator documentPaginator, PrintTicket printTicket)

    I would say that service is able to find those printers because when I have tried to print to non-existing printer and I got "invalid printer name" exception.

    edit:

    - sample removed as I'm not allowed to paste links -

    edit2:

    Interesting. When I tried a different printing code there is no error (unfortunately I'm not sure if it usable with my paginator code):

    using (var printDocument = new PrintDocument())
    {
        printDocument.PrinterSettings.PrinterName = printerName;
        printDocument.Print();
    }

    So my question 2 would be - how to print document through PrintDocument() with use of DocumentPaginator?


    Monday, April 8, 2013 9:39 AM

Answers

All replies

  • Try follow the suggestions here to see if it helps.
    Tuesday, April 9, 2013 9:09 AM
    Answerer
  • I have a similar problem. My C# console app fails on js.Close() in Windows 8. Works fine under Windows 7 professional.  The length of the jobstream is correct after the Write is completed. After the Close() is executed, the jobstream length has an exception and nothing is printed. Length '((System.Printing.PrintQueueStream)js).Length' threw an exception of type 'System.NullReferenceException' long {System.NullReferenceException}

     My code is:

    I have already tried all work-arounds posted there. Nothing works. My code:

    namespace printqueueWin8
    {
        class Program
        {
            static void Main(string[] args)
            {
                string szFileName = @"C:\temp\test.txt";
                string docname = "print me";
                // Create the printer server and print queue objects

                //using (var printq = defaultPrintQueue)
                using (var printq = LocalPrintServer.GetDefaultPrintQueue())
                {
                    PrintSystemJobInfo job = printq.AddJob(docname);
                    using (var memoryStream = new MemoryStream())
                    {
                        FileStream fs = new FileStream(szFileName, FileMode.Open, FileAccess.Read, FileShare.None);
                        fs.CopyTo(memoryStream);
                        fs.Close();
                        Byte[] myByteBuffer = memoryStream.ToArray();
                        // Write a Byte buffer to the JobStream and close the stream
                            using (var js = job.JobStream)
                            {
                                js.Write(myByteBuffer, 0, myByteBuffer.Length);
                                js.Close();
                            }
                    }
                }

            }
        }
    }

     
    Wednesday, March 5, 2014 7:27 PM
  • From the Remark of PrintQueue.AddJob() documentation, the Print Spooler will gain control of the Stream after .Close() is called. Perheps the job handle is freed to handover the stream and that's why you get NullReferenceException when checking .Length afterwards. 
    Friday, March 7, 2014 9:44 AM
    Answerer
  • Hello folks,

    I have been facing the same problem until right now. All above suggested methods failed (as it did for Jeff0123) . But after long research on that issue I think I found the reason (but no proper solution yet).

    MS Windows 8 and 2012 use a new printer driver generation based on XPS. Which means drivers like "generic text-only" won't work properly depending on the method the data is sent to the printer. In my case the same way like Jeff0123 tried to access the printers.

    See link http://support.microsoft.com/kb/2779300

    One solution might be to use API calls. I have also found a site which shows an example project for thermal slip printing. The VB.NET source code there features a wrapper class for all API calls. The functions you find behave pretty similar to the ones of the posted C# code example of Jeff0123. I did a small test so far and for my needs that works fine.

    Although the page is in German you can find the mentioned class by searching for "Public Class RawPrinter". Beside the comments the class methods are written in English. You find the class here: http://www.vbarchiv.net/tipps/tipp_2375-kassenbon-drucker-mit-vbnet-oder-c-per-esc-pos-befehle-ansprechen.html

    Hope that might help for at least a few of you. So long!

    Thursday, August 7, 2014 8:47 AM
  • If that's the case you can find simpler example code here and verify if that's in fact the root cause of your problem.
    Friday, August 8, 2014 3:06 AM
    Answerer