有没有一种方法可以检查打印过程是否成功?

14

我有一个应用程序需要打印门票,每个门票必须是唯一的。该应用程序是Windows窗体应用程序,完全使用C#编写。我们的应用程序使用三星ML-2525激光单色打印机。

流程基本上如下:操作员选择产品/门票(唯一标识),然后按下按钮执行以下两个操作:

  1. 连接到数据库并将产品标记为已使用
  2. 打印门票(使用System.Drawing和GDI+实现)

不知何故,偶尔会出现未将需要打印的图像发送到打印机的情况。这种情况很少发生,但确实存在。

我尝试使用Win32_Printer(http://msdn.microsoft.com/en-us/library/Aa394363)连接打印机,但无法获取当前打印机的状态(在线、离线、低碳粉、卡纸等)。我只能检查打印机是否存在以及纸张大小是否正确安装。我尝试了类似以下代码的方法,但没成功:

    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;
    }

我试图获取打印机的API,但是我无法找到它。顺便说一下,打印机的软件确实会在Windows工具栏中指示不同的错误。

我的问题是,是否有人能指导我如何连接打印机并检查打印是否成功。

另外,如果有人知道其他一些特定的打印机,我可能会更换硬件以实现这一目标。

谢谢


2
@lopezbertoni 通过一些简单的谷歌搜索,您就可以学会如何在C#应用程序中使用这些链接的方法...例如http://www.codeproject.com/Articles/51085/Monitor-jobs-in-a-printer-queue-NET - John Arlen
1
你的情况是否允许你的“重新打印”按钮首先使后端无效化第一个“唯一”的产品,以便如果有人出示它,它将被拒绝,从而防止滥用?(这是与条形码有关的事情吗?) - tomfanning
1
@tomfanning 我们考虑过这个问题,但这会让POS机上的收银员重复打印同一张票(窃取)。即使该票据被拒绝,客户仍然支付了费用,却不知道收银员重新打印了它。这就是为什么我认为与打印机通信是使操作更容易的关键。希望这可以帮到你。是的,这涉及到条形码。 - lopezbertoni
好东西 - 觉得这个想法值得分享。祝你解决问题顺利! - tomfanning
为什么不试试这个? http://stackoverflow.com/questions/5563788/how-to-check-a-print-job-status-with-c-sharp - Antony Brahin
显示剩余6条评论
2个回答

5
要获取本地机器上打印队列的列表,请尝试使用PrintServer的GetPrintQueues方法。
一旦您拥有与相关打印机关联的PrintQueue对象的实例,您就可以使用它来访问打印机的状态(IsOffline、IsPaperOut等)。此外,您可以使用它来获取给定队列中作业的列表(GetPrintJobInfoCollection),然后再获取特定作业的状态信息(IsInError、IsCompleted、IsBlocked等)。
希望这能帮到您!

1
谢谢您的输入。我确实尝试了您提到的方法,但是没有成功。主要问题是作业进入队列后就从队列中消失了,打印机也没有完成打印作业。 - lopezbertoni
如果您在将作业发送到打印机之前开始监视队列,我想知道是否可以在作业出现在队列中时立即捕获它... - Ben Gribaudo
为什么这个没有标记为答案?这对我帮助很大。我通过查看从特定客户端PrintQueue.Submitter发送的作业数量来使其工作,然后在尝试打印后,我获取了新添加作业的列表,并简单地检查以确保它们已完成。您还可以通过此API获取每个作业或打印机本身的状态。甚至有作业ID和票据信息。 - B.K.
4
这并未标记为答案,因为这只是报告作业已发送到打印机,而不是打印机成功完成了作业。 - Bon

0

尝试打印您的PrintDocument(System.Drawing.Printing)后,请尝试检查打印作业的状态。

第一步:初始化您的printDocument。

第二步:从System.Drawing.Printing.PrinterSettings.InstalledPrinters.Cast<string>();获取打印机名称

并将其复制到printerDocument.PrinterSettings.PrinterName中

第三步:尝试打印并处理。

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

最后一步:在任务中运行检查(不要阻塞UI线程)。
 Task.Run(()=>{
     if (!IsPrinterOk(printerDocument.PrinterSettings.PrinterName,checkTimeInMillisec))
     {
        // failed printing, do something...
     }
    });

这是实现代码:

    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;    
    }

祝你好运。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接