最近工作中碰到一个需求,用户要求需要连续打印8000多张处方用于存档,但是考虑到程序发送文档到打印队列的速度远远大于打印机打印的速度,需要控制程序发送文档到打印队列的速度,这就需要检测打印机打印队列中的任务数,超过一定的任务数就停止发送,低于一定数量继续发送。同时,还得检测是否缺纸,用于提示用户。本文中的代码在惠普打印机中测试通过,废话不多说,直接上代码,相信你一定能看懂的。
方式1:使用Win32 API(我采用的方式)
其中
方法 public static int GetTaskNumber()是检测打印队列中的任务数
方法public static int GetPrinterStatusCodeInt()是检测打印机的状态码
- #region 方式1
- [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
- private static extern bool OpenPrinter(string pPrinterName, out IntPtr hPrinter, IntPtr pDefault);
-
-
- [DllImport("winspool.drv", SetLastError = true)]
- private static extern bool ClosePrinter(IntPtr hPrinter);
-
-
- [DllImport("winspool.drv", SetLastError = true)]
- private static extern bool GetPrinter(IntPtr hPrinter,
- int dwLevel, IntPtr pPrinter, int cbBuf, out int pcbNeeded);
-
-
- [DllImport("winspool.drv", CharSet = CharSet.Auto)]
- public static extern int EnumJobs(IntPtr hPrinter, int FirstJob, int NoJobs, int Level, IntPtr pInfo, int cdBuf,
- out int pcbNeeded, out int pcReturned);
-
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
- public struct PRINTER_INFO_2
- {
- public string pServerName;
- public string pPrinterName;
- public string pShareName;
- public string pPortName;
- public string pDriverName;
- public string pComment;
- public string pLocation;
- public IntPtr pDevMode;
- public string pSepFile;
- public string pPrintProcessor;
- public string pDatatype;
- public string pParameters;
- public IntPtr pSecurityDescriptor;
- public uint Attributes;
- public uint Priority;
- public uint DefaultPriority;
- public uint StartTime;
- public uint UntilTime;
- public uint Status;
- public uint cJobs;
- public uint AveragePPM;
- }
-
- ///
- /// 默认打印机的名称
- ///
- private static string printerName = new LocalPrintServer().DefaultPrintQueue.Name;
-
-
- ///
- /// 获取打印机的状态编码(方式1)
- ///
- ///
- public static int GetPrinterStatusCodeInt()
- {
- int intRet = 0;
- IntPtr hPrinter;
-
-
- if (OpenPrinter(printerName, out hPrinter, IntPtr.Zero))
- {
- int cbNeeded = 0;
- bool bolRet = GetPrinter(hPrinter, 2, IntPtr.Zero, 0, out cbNeeded);
- if (cbNeeded > 0)
- {
- IntPtr pAddr = Marshal.AllocHGlobal((int)cbNeeded);
- bolRet = GetPrinter(hPrinter, 2, pAddr, cbNeeded, out cbNeeded);
- if (bolRet)
- {
- PRINTER_INFO_2 Info2 = new PRINTER_INFO_2();
-
-
- Info2 = (PRINTER_INFO_2)Marshal.PtrToStructure(pAddr, typeof(PRINTER_INFO_2));
-
-
- intRet = System.Convert.ToInt32(Info2.Status);
- }
- Marshal.FreeHGlobal(pAddr);
- }
- ClosePrinter(hPrinter);
- }
-
-
- return intRet;
- }
- ///
- /// 检查打印机是否可用(方式1)
- ///
- ///
- ///
- public static bool CheckIsEnable(int intStatusCodeValue)
- {
- bool isEnable = false;
- if (PrinterHelper.GetTaskNumber() == 0)
- {
- return true;
- }
- if (intStatusCodeValue == 0x0008000 || intStatusCodeValue == 0x00000400 || intStatusCodeValue == 0x00004000)
- {
- return true;
- }
- return isEnable;
- }
-
-
- ///
- /// 获取打印机的状态信息(方式1)
- ///
- ///
- public static string GetPrinterStatusMessage(int intStatusCodeValue)
- {
- string strRet = string.Empty;
- switch (intStatusCodeValue)
- {
- case 0:
- strRet = "准备就绪(Ready)";
- break;
- case 0x00000200:
- strRet = "忙(Busy)";
- break;
- case 0x00400000:
- strRet = "被打开(Printer Door Open)";
- break;
- case 0x00000002:
- strRet = "错误(Printer Error)";
- break;
- case 0x0008000:
- strRet = "初始化(Initializing)";
- break;
- case 0x00000100:
- strRet = "正在输入,输出(I/O Active)";
- break;
- case 0x00000020:
- strRet = "手工送纸(Manual Feed)";
- break;
- case 0x00040000:
- strRet = "无墨粉(No Toner)";
- break;
- case 0x00001000:
- strRet = "不可用(Not Available)";
- break;
- case 0x00000080:
- strRet = "脱机(Off Line)";
- break;
- case 0x00200000:
- strRet = "内存溢出(Out of Memory)";
- break;
- case 0x00000800:
- strRet = "输出口已满(Output Bin Full)";
- break;
- case 0x00080000:
- strRet = "当前页无法打印(Page Punt)";
- break;
- case 0x00000008:
- strRet = "塞纸(Paper Jam)";
- break;
- case 0x00000010:
- strRet = "打印纸用完(Paper Out)";
- break;
- case 0x00000040:
- strRet = "纸张问题(Page Problem)";
- break;
- case 0x00000001:
- strRet = "暂停(Paused)";
- break;
- case 0x00000004:
- strRet = "正在删除(Pending Deletion)";
- break;
- case 0x00000400:
- strRet = "正在打印(Printing)";
- break;
- case 0x00004000:
- strRet = "正在处理(Processing)";
- break;
- case 0x00020000:
- strRet = "墨粉不足(Toner Low)";
- break;
- case 0x00100000:
- strRet = "需要用户干预(User Intervention)";
- break;
- case 0x20000000:
- strRet = "等待(Waiting)";
- break;
- case 0x00010000:
- strRet = "热机中(Warming Up)";
- break;
- default:
- strRet = "未知状态(Unknown Status)";
- break;
- }
- return strRet;
- }
-
- ///
- /// 获取打印机正在打印的任务数(方式1)
- ///
- ///
- public static int GetTaskNumber()
- {
- IntPtr handle;
- int FirstJob = 0;
- int NumJobs = 127;
- int pcbNeeded;
- int pcReturned = -1;
- OpenPrinter(printerName, out handle, IntPtr.Zero);
- // get num bytes required, here we assume the maxt job for the printer quest is 128 (0..127)
- EnumJobs(handle, FirstJob, NumJobs, 1, IntPtr.Zero, 0, out pcbNeeded, out pcReturned);
-
- // allocate unmanaged memory
- IntPtr pData = Marshal.AllocHGlobal(pcbNeeded);
-
- // get structs
- EnumJobs(handle, FirstJob, NumJobs, 1, pData, pcbNeeded, out pcbNeeded, out pcReturned);
-
- return pcReturned;
- }
-
-
-
-
-
- #endregion
方式2:使用LocalPrintServer
不过有一点需要注意的是,如果需要实时检测打印机的状态,每次检测状态码,都需要重新new LocalPrintServer对象,不然检测不到新的状态信息
- #region 方式2
- ///
- /// 获取打印机的状态编码(方式2)
- ///
- ///
- public static int GetPrinterStatusCodeInt2()
- {
- int statusCode = 0;
- PrintQueue queue = new LocalPrintServer().DefaultPrintQueue;
- if (queue.IsNotAvailable)
- {
- statusCode = 1;
- return statusCode;
- }
- if (queue.IsOutOfPaper)
- {
- statusCode = 2;
- return statusCode;
- }
-
- if (queue.IsBusy)
- {
- statusCode = 3;
- return statusCode;
- }
- if (queue.IsInError)
- {
- statusCode = 4;
- return statusCode;
- }
- if (queue.IsOffline)
- {
- statusCode = 5;
- return statusCode;
- }
- if (queue.IsOutOfMemory)
- {
- statusCode = 6;
- return statusCode;
- }
- if (queue.HasPaperProblem)
- {
- statusCode = 7;
- return statusCode;
- }
- if (queue.IsPaused)
- {
- statusCode = 8;
- return statusCode;
- }
-
- return statusCode;
- }
-
- ///
- /// 检查打印机是否可用(方式2)
- ///
- /// 打印机状态编码
- ///
- public static bool CheckIsEnable2(int intStatusCodeValue)
- {
- bool isEnable = false;
- if (intStatusCodeValue == 0)
- {
- return true;
- }
- return isEnable;
- }
-
-
- ///
- /// 获取打印机的状态信息(方式2)
- ///
- /// 打印机状态编码
- ///
- public static string GetPrinterStatusMessage2(int intStatusCodeValue)
- {
- string strRet = string.Empty;
- switch (intStatusCodeValue)
- {
- case 1:
- strRet = "打印机不可用";
- break;
- case 2:
- strRet = "打印机缺纸";
- break;
- case 3:
- strRet = "打印机正忙";
- break;
- case 4:
- strRet = "打印机正在处于错误状态";
- break;
- case 5:
- strRet = "打印机处于脱机状态";
- break;
- case 6:
- strRet = "打印机内存溢出";
- break;
- case 7:
- strRet = "遇到了未指定的纸张错误";
- break;
- case 8:
- strRet = "打印机打印队列暂停了";
- break;
- default:
- strRet = "未知状态(Unknown Status)";
- break;
- }
- return strRet;
- }
-
- ///
- /// 获取打印队列的任务数(方式2)
- ///
- ///
- public static int GetTaskNumber2()
- {
- return new LocalPrintServer().DefaultPrintQueue.NumberOfJobs;
- }
- #endregion
完整代码如下:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Management;
- using System.Printing;
- using System.Runtime.InteropServices;
- using System.Text;
-
- namespace iih.mp.dg.presbatchprint2.bp
- {
- ///
- /// 打印机状态帮助类
- ///
- public class PrinterHelper
- {
- #region 方式1
- [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
- private static extern bool OpenPrinter(string pPrinterName, out IntPtr hPrinter, IntPtr pDefault);
-
-
- [DllImport("winspool.drv", SetLastError = true)]
- private static extern bool ClosePrinter(IntPtr hPrinter);
-
-
- [DllImport("winspool.drv", SetLastError = true)]
- private static extern bool GetPrinter(IntPtr hPrinter,
- int dwLevel, IntPtr pPrinter, int cbBuf, out int pcbNeeded);
-
-
- [DllImport("winspool.drv", CharSet = CharSet.Auto)]
- public static extern int EnumJobs(IntPtr hPrinter, int FirstJob, int NoJobs, int Level, IntPtr pInfo, int cdBuf,
- out int pcbNeeded, out int pcReturned);
-
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
- public struct PRINTER_INFO_2
- {
- public string pServerName;
- public string pPrinterName;
- public string pShareName;
- public string pPortName;
- public string pDriverName;
- public string pComment;
- public string pLocation;
- public IntPtr pDevMode;
- public string pSepFile;
- public string pPrintProcessor;
- public string pDatatype;
- public string pParameters;
- public IntPtr pSecurityDescriptor;
- public uint Attributes;
- public uint Priority;
- public uint DefaultPriority;
- public uint StartTime;
- public uint UntilTime;
- public uint Status;
- public uint cJobs;
- public uint AveragePPM;
- }
-
- ///
- /// 默认打印机的名称
- ///
- private static string printerName = new LocalPrintServer().DefaultPrintQueue.Name;
-
-
- ///
- /// 获取打印机的状态编码(方式1)
- ///
- ///
- public static int GetPrinterStatusCodeInt()
- {
- int intRet = 0;
- IntPtr hPrinter;
-
-
- if (OpenPrinter(printerName, out hPrinter, IntPtr.Zero))
- {
- int cbNeeded = 0;
- bool bolRet = GetPrinter(hPrinter, 2, IntPtr.Zero, 0, out cbNeeded);
- if (cbNeeded > 0)
- {
- IntPtr pAddr = Marshal.AllocHGlobal((int)cbNeeded);
- bolRet = GetPrinter(hPrinter, 2, pAddr, cbNeeded, out cbNeeded);
- if (bolRet)
- {
- PRINTER_INFO_2 Info2 = new PRINTER_INFO_2();
-
-
- Info2 = (PRINTER_INFO_2)Marshal.PtrToStructure(pAddr, typeof(PRINTER_INFO_2));
-
-
- intRet = System.Convert.ToInt32(Info2.Status);
- }
- Marshal.FreeHGlobal(pAddr);
- }
- ClosePrinter(hPrinter);
- }
-
-
- return intRet;
- }
- ///
- /// 检查打印机是否可用(方式1)
- ///
- ///
- ///
- public static bool CheckIsEnable(int intStatusCodeValue)
- {
- bool isEnable = false;
- if (PrinterHelper.GetTaskNumber() == 0)
- {
- return true;
- }
- if (intStatusCodeValue == 0x0008000 || intStatusCodeValue == 0x00000400 || intStatusCodeValue == 0x00004000)
- {
- return true;
- }
- return isEnable;
- }
-
-
- ///
- /// 获取打印机的状态信息(方式1)
- ///
- ///
- public static string GetPrinterStatusMessage(int intStatusCodeValue)
- {
- string strRet = string.Empty;
- switch (intStatusCodeValue)
- {
- case 0:
- strRet = "准备就绪(Ready)";
- break;
- case 0x00000200:
- strRet = "忙(Busy)";
- break;
- case 0x00400000:
- strRet = "被打开(Printer Door Open)";
- break;
- case 0x00000002:
- strRet = "错误(Printer Error)";
- break;
- case 0x0008000:
- strRet = "初始化(Initializing)";
- break;
- case 0x00000100:
- strRet = "正在输入,输出(I/O Active)";
- break;
- case 0x00000020:
- strRet = "手工送纸(Manual Feed)";
- break;
- case 0x00040000:
- strRet = "无墨粉(No Toner)";
- break;
- case 0x00001000:
- strRet = "不可用(Not Available)";
- break;
- case 0x00000080:
- strRet = "脱机(Off Line)";
- break;
- case 0x00200000:
- strRet = "内存溢出(Out of Memory)";
- break;
- case 0x00000800:
- strRet = "输出口已满(Output Bin Full)";
- break;
- case 0x00080000:
- strRet = "当前页无法打印(Page Punt)";
- break;
- case 0x00000008:
- strRet = "塞纸(Paper Jam)";
- break;
- case 0x00000010:
- strRet = "打印纸用完(Paper Out)";
- break;
- case 0x00000040:
- strRet = "纸张问题(Page Problem)";
- break;
- case 0x00000001:
- strRet = "暂停(Paused)";
- break;
- case 0x00000004:
- strRet = "正在删除(Pending Deletion)";
- break;
- case 0x00000400:
- strRet = "正在打印(Printing)";
- break;
- case 0x00004000:
- strRet = "正在处理(Processing)";
- break;
- case 0x00020000:
- strRet = "墨粉不足(Toner Low)";
- break;
- case 0x00100000:
- strRet = "需要用户干预(User Intervention)";
- break;
- case 0x20000000:
- strRet = "等待(Waiting)";
- break;
- case 0x00010000:
- strRet = "热机中(Warming Up)";
- break;
- default:
- strRet = "未知状态(Unknown Status)";
- break;
- }
- return strRet;
- }
-
- ///
- /// 获取打印机正在打印的任务数(方式1)
- ///
- ///
- public static int GetTaskNumber()
- {
- IntPtr handle;
- int FirstJob = 0;
- int NumJobs = 127;
- int pcbNeeded;
- int pcReturned = -1;
- OpenPrinter(printerName, out handle, IntPtr.Zero);
- // get num bytes required, here we assume the maxt job for the printer quest is 128 (0..127)
- EnumJobs(handle, FirstJob, NumJobs, 1, IntPtr.Zero, 0, out pcbNeeded, out pcReturned);
-
- // allocate unmanaged memory
- IntPtr pData = Marshal.AllocHGlobal(pcbNeeded);
-
- // get structs
- EnumJobs(handle, FirstJob, NumJobs, 1, pData, pcbNeeded, out pcbNeeded, out pcReturned);
-
- return pcReturned;
- }
-
-
-
-
-
- #endregion
-
-
- #region 方式2
- ///
- /// 获取打印机的状态编码(方式2)
- ///
- ///
- public static int GetPrinterStatusCodeInt2()
- {
- int statusCode = 0;
- PrintQueue queue = new LocalPrintServer().DefaultPrintQueue;
- if (queue.IsNotAvailable)
- {
- statusCode = 1;
- return statusCode;
- }
- if (queue.IsOutOfPaper)
- {
- statusCode = 2;
- return statusCode;
- }
-
- if (queue.IsBusy)
- {
- statusCode = 3;
- return statusCode;
- }
- if (queue.IsInError)
- {
- statusCode = 4;
- return statusCode;
- }
- if (queue.IsOffline)
- {
- statusCode = 5;
- return statusCode;
- }
- if (queue.IsOutOfMemory)
- {
- statusCode = 6;
- return statusCode;
- }
- if (queue.HasPaperProblem)
- {
- statusCode = 7;
- return statusCode;
- }
- if (queue.IsPaused)
- {
- statusCode = 8;
- return statusCode;
- }
-
- return statusCode;
- }
-
- ///
- /// 检查打印机是否可用(方式2)
- ///
- /// 打印机状态编码
- ///
- public static bool CheckIsEnable2(int intStatusCodeValue)
- {
- bool isEnable = false;
- if (intStatusCodeValue == 0)
- {
- return true;
- }
- return isEnable;
- }
-
-
- ///
- /// 获取打印机的状态信息(方式2)
- ///
- /// 打印机状态编码
- ///
- public static string GetPrinterStatusMessage2(int intStatusCodeValue)
- {
- string strRet = string.Empty;
- switch (intStatusCodeValue)
- {
- case 1:
- strRet = "打印机不可用";
- break;
- case 2:
- strRet = "打印机缺纸";
- break;
- case 3:
- strRet = "打印机正忙";
- break;
- case 4:
- strRet = "打印机正在处于错误状态";
- break;
- case 5:
- strRet = "打印机处于脱机状态";
- break;
- case 6:
- strRet = "打印机内存溢出";
- break;
- case 7:
- strRet = "遇到了未指定的纸张错误";
- break;
- case 8:
- strRet = "打印机打印队列暂停了";
- break;
- default:
- strRet = "未知状态(Unknown Status)";
- break;
- }
- return strRet;
- }
-
- ///
- /// 获取打印队列的任务数(方式2)
- ///
- ///
- public static int GetTaskNumber2()
- {
- return new LocalPrintServer().DefaultPrintQueue.NumberOfJobs;
- }
- #endregion
-
-
- #region 方式3
- public static void ToDo()
- {
- //获取所有打印机信息
- //string query = string.Format("SELECT * from Win32_Printer ");
- //var searcher = new ManagementObjectSearcher(query);
- //var printers = searcher.Get();
-
- //foreach (var printer in printers)
- //{
- // Console.WriteLine(printer.Properties["Name"].Value);
- // foreach (var property in printer.Properties)
- // {
- // Console.WriteLine(string.Format("\t{0}: {1}", property.Name, property.Value));
- // }
- // Console.WriteLine();
- //}
- }
- #endregion
- }
- }