Search code examples
c#printingwindows-servicesbackgroundworker

Printing in windows service using background worker


I'm developing a Windows service that has to print some labels on a network printer. Here http://msdn.microsoft.com/en-us/library/5ekk3hse.aspx it says that printing in Windows service using System.Drawing.Printing classes is not supported (or rather shouldn't be done).

This Print html document from Windows Service in C# without print dialog seems like the solution, but they say there that it requires .Net Framework 4.0, and I have to use 2.0 (or I can change it to 3.5 if I really, really have to, but then the client will have to upgrade which I want to avoid).

I also read that to print from Windows service on network printer the domain account is required for the service, which I'm using anyway, so that's not the problem.

Every setting for the printer will be set in .config file and I hope that because of this no user dialog will be appearing/needed.

My questions:

Will I be able to print directly from Windows service using BackgroundWorker? Or do I need to call another app (for example console application) from inside of my service and do the printing there (I've read on the net that some people use this solution but I didn't found any code example)

Also I'm not good with threading and working with BackgroundWorkers so can someone give me some example how can I do it (I have requests to print coming asynchronously. How can I print them without loosing any?). Is the BackgroundWorker the best solution or are there some better ways to do it?


Solution

  • I haven't tested printing from another thread, but one of these two options should work. You might have to modify the code to work with .Net 2 since I only use 3.5 Sp1 or 4.

    Assuming you have a Print method and a Queue<ItemToPrint> where ItemToPrint is the class holding the print settings / information

        public Queue<ItemToPrint> PrintQueue = new Queue<ItemToPrint>();
        private BackgroundWorker bgwPrintWatcher;
    
        public void SetupBackgroundWorker()
        {
            bgwPrintWatcher = new BackgroundWorker();
            bgwPrintWatcher.WorkerSupportsCancellation = true;
            bgwPrintWatcher.ProgressChanged += new ProgressChangedEventHandler(bgwPrintWatcher_ProgressChanged);
            bgwPrintWatcher.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgwPrintWatcher_RunWorkerCompleted);
            bgwPrintWatcher.DoWork += new DoWorkEventHandler(bgwPrintWatcher_DoWork);
            bgwPrintWatcher.RunWorkerAsync();
        }
    
        void bgwPrintWatcher_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            while (!worker.CancellationPending)
            {
                // Prevent writing to queue while we are reading / editing it
                lock (PrintQueue)
                {
                    if (PrintQueue.Count > 0)
                    {
                        ItemToPrint item = PrintQueue.Dequeue();
                        // Two options here, you can either sent it back to the main thread to print
                        worker.ReportProgress(PrintQueue.Count + 1, item);
                        // or print from the background thread
                        Print(item);
                    }
                }
            }
        }
    
        private void Print(ItemToPrint item)
        {
            // Print it here
        }
    
        private void AddItemToPrint(ItemToPrint item)
        {
            lock (PrintQueue)
            {
                PrintQueue.Enqueue(item);
            }
        }
    
        void bgwPrintWatcher_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // Anything here will run from the main / original thread
            // PrintQueue will no longer be watched
        }
    
        void bgwPrintWatcher_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            // Anything here will run from the main / original thread
            ItemToPrint item = e.UserState as ItemToPrint;
            // e.ProgressPercentage holds the int value passed as the first param
            Print(item);
        }