14

I have an application where I need to print a ticket. Each ticket must be unique. The application is windows forms and written entirely in c#. For our application we're using Samsung ML- 2525 laser monochromatic printers.

The flow is basically the following, the operator picks a product/ticket (which is unique) and then it presses a button that does 2 things:

  1. Connects to a database and updates the product as used
  2. Prints the ticket (this is done using System.Drawing and GDI+)

For some reason, every once in a while, the image that needs to be printed is not sent to the printer. It's a rare case, but it happens.

I tried to connect to the printer using Win32_Printer ( http://msdn.microsoft.com/en-us/library/Aa394363 ) but I can't get to get the current printer's state (online, offline, low toner, paper jam, etc). I can only check if the printer exists and that the paper size is installed correctly. I tried code similar to the following but it didn't work

    private string MonitorPrintJobWmi()
    {
        var jobMessage = String.Empty;
        var scope = new ManagementScope(ManagementPath.DefaultPath);
        scope.Connect();

        var selectQuery = new SelectQuery { QueryString = @"select *  from Win32_PrintJob" };

        var objSearcher = new ManagementObjectSearcher(scope, selectQuery);
        var objCollection = objSearcher.Get();

        foreach (var job in objCollection)
        {
            if (job != null)
            {
                jobMessage += String.Format("{0} \r\n", job["Name"].ToString());
                jobMessage += String.Format("{0} \r\n", job["JobId"].ToString());
                _jobId = Convert.ToInt32(job["JobId"]);
                jobMessage += String.Format("{0} \r\n", job["JobStatus"].ToString());
                jobMessage += String.Format("{0} \r\n", job["Status"].ToString());
            }
        }
        return jobMessage;
    }

I tried to get an API for the printer but I couldn't get a hold of it. By the way, the printer's software do indicate different errors in the windows toolbar.

My question is if anyone can lead me in the right direction as to how to connect to a printer and check if printing was successful.

Also, it would be helpful if someone know of some other specific printer in which I may accomplish this ie, changing hardware.

Thanks,

Mark Hall
  • 53,938
  • 9
  • 94
  • 111
lopezbertoni
  • 3,551
  • 3
  • 37
  • 53
  • See related: http://stackoverflow.com/questions/1921487/confirm-successful-print-programmatically-in-windows – Eugene Aug 02 '12 at 02:44
  • I did, but some sample code to get a head start would be beneficial. – lopezbertoni Aug 02 '12 at 03:04
  • 2
    @lopezbertoni A little Googling will show you how to use those linked methods in C# apps... like http://www.codeproject.com/Articles/51085/Monitor-jobs-in-a-printer-queue-NET – John Arlen Aug 02 '12 at 03:08
  • Thank you, found something here (http://blogs.msdn.com/b/martijnh/archive/2009/08/05/printmonitor-a-c-print-spooler-monitor.aspx) too. I'll give it a try and post my code as soon as I get something working or not. – lopezbertoni Aug 02 '12 at 03:12
  • Why not just implement a "reprint" button? – tomfanning Sep 07 '12 at 12:04
  • @tomfanning In my case, each ticket/product is unique with a unique code for access control, therefore it can only be printed once. Right now we're reverting transactions but that requires human intervention, it would be nice to have most of the process built into the code. – lopezbertoni Sep 07 '12 at 12:51
  • 1
    Would your scenario allow that your "reprint" button first invalidates the first "unique" product in the back-end, such that if someone were to present it, it would be rejected, thus preventing abuse? (is it something with a barcode?) – tomfanning Sep 07 '12 at 12:58
  • 1
    @tomfanning We thought about it but that would allow the cashier at the POS to reprint the same ticket several times (stealing). Even though the ticket might be rejected, the customer still paid for it and never knew that the cashier reprinted it. That's why we I believe that communicating to the printer is the key to make operations easier. Hope this helps. And yes, it's something with a barcode. – lopezbertoni Sep 07 '12 at 14:16
  • Good stuff - thought it was worth sharing the idea. Good luck with the problem! – tomfanning Sep 07 '12 at 16:05
  • Why don't you try this? http://stackoverflow.com/questions/5563788/how-to-check-a-print-job-status-with-c-sharp – Antony Brahin Sep 08 '12 at 10:45
  • @AntonyBrahin that solution applies only to Windows XP. – lopezbertoni Sep 08 '12 at 15:56

2 Answers2

5

To get a list of print queues on the local machine, try PrintServer's GetPrintQueues method.

Once you have an instance of the PrintQueue object associated with the relevant printer, you can use it to access the printer's status (IsOffline, IsPaperOut, etc.). Also, you can use it to get a list of the jobs in the given queue (GetPrintJobInfoCollection) which then will allow you to get job-specific status information (IsInError, IsCompleted, IsBlocked, etc.).

Hope this helps!

Ben Gribaudo
  • 5,057
  • 1
  • 40
  • 75
  • 1
    thank you for the input. I did try using the approach you mentioned but I was not successful. The main problem is that the job gets to the queue and then disappears from it, and the printer does not complete the print job. – lopezbertoni Sep 15 '12 at 19:00
  • If you start watching the queue before you send the job to the printer, I wonder if you can catch the job as soon as it appears in the queue.... – Ben Gribaudo Sep 17 '12 at 12:29
  • Why is this not marked as an answer? This has helped me so much. I was able to get this to work by looking at the number of jobs sent from the specific client `PrintQueue.Submitter`, then after attempting the printing, I got the list of the newly added jobs and simply checked to make sure they were completed. You can also get the status of every single job or the printer itself through this API. There's even a job id and ticket information. – B.K. Nov 04 '14 at 16:49
  • 4
    It isn't marked as an answer because this just reports that jobs were sent to the printer. Not that the printer actually completed it successfully. – Bon Jan 06 '16 at 17:41
0

After try to print your PrintDocument (System.Drawing.Printing), try to check status of printjobs.

First step: Initialize your printDocument.

Second step: Get your printer Name From System.Drawing.Printing.PrinterSettings.InstalledPrinters.Cast<string>();

And copy it into your printerDocument.PrinterSettings.PrinterName

Third step: Try to print and dispose.

printerDocument.Print();
printerDocument.Dispose();

Last step: Run the check in a Task (do NOT block UI thread).

 Task.Run(()=>{
     if (!IsPrinterOk(printerDocument.PrinterSettings.PrinterName,checkTimeInMillisec))
     {
        // failed printing, do something...
     }
    });

Here is the implementation:

    private bool IsPrinterOk(string name,int checkTimeInMillisec)
    {
        System.Collections.IList value = null;
        do
        {
            //checkTimeInMillisec should be between 2000 and 5000
            System.Threading.Thread.Sleep(checkTimeInMillisec);
            // or use Timer with Threading.Monitor instead of thread sleep

            using (System.Management.ManagementObjectSearcher searcher = new System.Management.ManagementObjectSearcher("SELECT * FROM Win32_PrintJob WHERE Name like '%" + name + "%'"))
            {
                value = null;

                if (searcher.Get().Count == 0) // Number of pending document.
                    return true; // return because we haven't got any pending document.
                else
                {
                    foreach (System.Management.ManagementObject printer in searcher.Get())
                    {
                        value = printer.Properties.Cast<System.Management.PropertyData>().Where(p => p.Name.Equals("Status")).Select(p => p.Value).ToList();
                        break; 
                    }
                }
            }
       }
       while (value.Contains("Printing") || value.Contains("UNKNOWN") || value.Contains("OK"));

       return value.Contains("Error") ? false : true;    
    }

Good luck.

Péter Hidvégi
  • 743
  • 6
  • 21