问:

如何监控打印机的打印队列,可以获得正在打印文档的文档名,状态,所有者,页数,大小等。

答:

1、C++代码

一、API介绍:

API是Application Programming Interface的缩写,也就是应用程序调用系统功能的接口。Windows API主要包括系统定义的函数、消息及与之相关的数据类型。我们使用各种开发工具归根结底都是和API打交道。

二、与打印状态相关的API:

Api函数名 函数说明 W3.x W9x NT 
EnumJobs 获取打印作业信息 否 是 是 
OpenPrinter 获取指定打印机的句柄 否 是 是

在 Windows NT 版本以及 Windows 9x 中,增加了一批全新的、专门用来处理打印机及打印机队列状态的 API 函数。在这里,将通过 API 函数 OpenPrinter 与 EnumJobs,来确定打印机打印作业状态所需的信息。

OpenPrinter,用来获取给定打印机的句柄,通过该句柄可以实现对相应打印机的操作。

函数 EnumJobs,用来列出所指定打印机上正在打印的作业信息,这里给定打印机的引用就是通过使用上述OpenPrinter函数反馈回来的打印机句柄。

EnumJobs函数介绍:

EnumJobs (ByVal hPrinter As Long, ByVal FirstJob As Long, ByVal NoJobs As Long, ByVal Level As Long, pJob As Long, ByVal cbBuf As Long, pcbNeeded As Long, pcReturned As Long)

API函数EnumJobs用于列举给定打印机当前所有正在打印的任务状态信息,该函数可以列举给定打印机简要的或者详细的(Level决定)队列任务状态信息。在引用该函数时,通常先把cbBuf变量设置为0,以获得打印机队列任务的字节数,该字节数存储在pcbNeeded里以决定pJob变量大小,然后再次引用该函数,获得打印机队列任务的详细信息。

参数:

hPrinter
打印机句柄。

FirstJob
统计打印机队列任务数的起始点,0表示从第一个任务开始统计列举所有的打印任务。

NoJobs
需要列举的最大打印任务数。一般设为127。

Level
标示存储在pJob里的信息格式。如果该值为1,数据以JOB_INFO_1的格式存储;如果该值为2,数据以JOB_INFO_2的格式存储。

pJob
数组变量,保存打印任务的所有信息;cbBuf设为0时,该值也为0。Level变量的值决定pJob的数据格式(JOB_INFO_1 OR JOB_INFO_2)

cbBuf
该值通常为0。

pcbNeeded
存储打印机里打印任务的字节数。

pcReturned
用来存放打印任务数量的变量。

通过上表可以看出,这两个API函数只用使用在Windows 9x 以及 Windows NT环境中。

三、开发工具:

C++ Builder作为快速开发Windows平台下应用程序的工具,已经为越来越多的开发者采用。但是,如果要开发出专业的Windows应用软件,还需要使用大量的Windows API函数,以下是笔者应用C++ Builder以及Windows API函数来实现对打印机状态的时时监控。

选择C++ Builder的理由:

一:由于Windows API 都是用C或C++编写的,C++ Builder更易于底层应用。

二:C++ Builder对于Windows API的引用更加简单,这一点是Visual Basic所欠缺的。

四、程序实例:
1、启动C++ Builder程序,新创建一个工程;

2、进入工程,在当前窗体分别添加一个CheckListBox控件、一个Timer控件;

3、在CheckListBox控件的Item属性添加打印机名称列表(假设在网络中HostPrinter主机上有三台打印机Printer1、Printer2、Printer3),则Item项目里内容格式为:\\HostPrinter\Printer1、\\HostPrinter\\Printer2、\\HostPrinter\\Printer3 ;

4、Timer的Interval属性设置为60000(一分钟),在Timer的OnTimer事件加入如下代码:

{
HANDLE hPrinter; //打印机句柄
JOB_INFO_2 jobs[30]; //保留打印作业详细信息
DWORD size=sizeof(jobs);
JOB_INFO_2 *jobs1=NULL; //动态数组用于对大于size的任务进行操作
DWORD pcbNeeded=0; //所有打印字节数
int actNeed=0;
DWORD pcReturned=0; //打印任务数
char buf[19]; //指向打印机或机器名
int ret1; //获得打印机句柄返回值
int ret; //获得打印机任务返回值
TDateTime startTime;
Word Hour=0;
Word Hour1=0;
Word Min=0;
Word Min1=0;
Word Sec=0;
Word MSec=0;
int StartTime=0; //任务开始时间
int NowTime=0; //当前时间
int TotalTime=0; //任务停留时间
String str;
int length;
int PrintCount;
int InitCount=15; //设定的打印队列数量--------报警底线
int InitTime=10; //设定的打印队列事件--------报警底线(分钟)
PrintCount =CheckListBox1->Count ;
for (int i=0; i < PrintCount; i++)
{
//..............取得列表里的打印机
str=CheckListBox1->Items->Strings[i] ;
length=str.Length() ;
//................字符串到字符的转换,
StrPLCopy(buf,str,length);
//................获得打印机句柄
ret1= OpenPrinter(buf, &hPrinter, NULL);
//................获得打印任务数
ret= EnumJobs(hPrinter, 0, 127, 2,0, 0, &pcbNeeded, &pcReturned); //必要的一步,先取出打印机里任务的字节数,然后决定jobs1变量大小。//--------------------------①
//.................重定义Jobs1, 根据pcbNeeded决定使用哪个变量
if (pcbNeeded>size)
{
actNeed=pcbNeeded;
jobs1=new JOB_INFO_2[actNeed];
ret= EnumJobs(hPrinter, 0, 127, 2,(LPBYTE)jobs1, actNeed, &pcbNeeded, &pcReturned);
startTime=SystemTimeToDateTime(jobs1[0].Submitted); //------------------②
delete jobs1;
}
else
{
ret= EnumJobs(hPrinter, 0, 127, 2,(LPBYTE)jobs, size, &pcbNeeded, &pcReturned);//-----------------------------③
if (pcReturned>0)
startTime=SystemTimeToDateTime(jobs[0].Submitted);
}
//.................pcbNeeded>size结束
//................如果队列里有打印任务,比对数量与时间
if (pcReturned>0)
{
//.................时间转换,计算一天内的时间差
{
//............时间比较运算处理;
//............时间转换StartTime转换成分钟
}
DecodeTime(Now(),Hour1, Min1, Sec,MSec);
NowTime=Hour1*60+Min1;
TotalTime=NowTime-StartTime;
}
//依据条件判断是否报警
if ((pcReturned>InitCount) |(TotalTime >InitTime))
{
Beep();
}
pcReturned=0;
pcbNeeded=0;
}
//..........................pcReturned>0结束
}//....................................................for结束

5、编译并运行上述程序:

①程序中,此处的获得打印机任务的目的主要是获得打印机作业的字节数------ pcbNeeded,该变量里字节的大小,将决定进一步获得打印机里作业的状态时所用的变量是Jobs还是Jobs1。

②当pcbNeeded>size,给Jobs1分配空间,然后获得打印机当前作业的状态。

③当pcbNeeded<size,用Jobs作为变量,获得当前打印机作业状态。

用C++ Builder编程监控打印机队列状态:
只需要转换成vc++即可

注:②、③参数引用与①不同。

五、应用分析:

可以说IT技术在制造业得到了广泛的应用,而打印控制与监控则是制造业中众多应用中的较为典型的应用。通常,在生产制造过程中,都有很多打印机用于打印生产排序单、装配单、铭牌、标签等等。因此打印机的时时状态(缺纸、墨尽、卡纸)在这里就显得尤为重要了,如果不能及时的监控到打印机的状态势必会影响生产的正常持续运行。所以为了保证生产正常运行拥有一套用于监控打印机时时状态的程序是很有必要的。

2、VC++的代码

BOOL GetJobs(HANDLE hPrinter,        /* Handle to the printer. */ JOB_INFO_2 **ppJobInfo, /* Pointer to be filled.  */ int *pcJobs,            /* Count of jobs filled.  */ DWORD *pStatus)         /* Print Queue status.    */ {DWORD               cByteNeeded,nReturned,cByteUsed;JOB_INFO_2          *pJobStorage = NULL;PRINTER_INFO_2       *pPrinterInfo = NULL;/* Get the buffer size needed. */ if (!GetPrinter(hPrinter, 2, NULL, 0, &cByteNeeded)){if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)return FALSE;}pPrinterInfo = (PRINTER_INFO_2 *)malloc(cByteNeeded);if (!(pPrinterInfo))/* Failure to allocate memory. */ return FALSE;/* Get the printer information. */ if (!GetPrinter(hPrinter,2,(LPSTR)pPrinterInfo,cByteNeeded,&cByteUsed)){/* Failure to access the printer. */ free(pPrinterInfo);pPrinterInfo = NULL;return FALSE;}/* Get job storage space. */ if (!EnumJobs(hPrinter,0,pPrinterInfo->cJobs,2,NULL,0,(LPDWORD)&cByteNeeded,(LPDWORD)&nReturned)){if (GetLastError() != ERROR_INSUFFICIENT_BUFFER){free(pPrinterInfo);pPrinterInfo = NULL;return FALSE;}}pJobStorage = (JOB_INFO_2 *)malloc(cByteNeeded);if (!pJobStorage){/* Failure to allocate Job storage space. */ free(pPrinterInfo);pPrinterInfo = NULL;return FALSE;}ZeroMemory(pJobStorage, cByteNeeded);/* Get the list of jobs. */ if (!EnumJobs(hPrinter,0,pPrinterInfo->cJobs,2,(LPBYTE)pJobStorage,cByteNeeded,(LPDWORD)&cByteUsed,(LPDWORD)&nReturned)){free(pPrinterInfo);free(pJobStorage);pJobStorage = NULL;pPrinterInfo = NULL;return FALSE;}/**  Return the information.*/ *pcJobs = nReturned;*pStatus = pPrinterInfo->Status;*ppJobInfo = pJobStorage;free(pPrinterInfo);return TRUE;}BOOL IsPrinterError(HANDLE hPrinter){JOB_INFO_2  *pJobs;int         cJobs,i;DWORD       dwPrinterStatus;/**  Get the state information for the Printer Queue and*  the jobs in the Printer Queue.*/ if (!GetJobs(hPrinter, &pJobs, &cJobs, &dwPrinterStatus))return FALSE;/**  If the Printer reports an error, believe it.*/ if (dwPrinterStatus &(PRINTER_STATUS_ERROR |PRINTER_STATUS_PAPER_JAM |PRINTER_STATUS_PAPER_OUT |PRINTER_STATUS_PAPER_PROBLEM |PRINTER_STATUS_OUTPUT_BIN_FULL |PRINTER_STATUS_NOT_AVAILABLE |PRINTER_STATUS_NO_TONER |PRINTER_STATUS_OUT_OF_MEMORY |PRINTER_STATUS_OFFLINE |PRINTER_STATUS_DOOR_OPEN)){return TRUE;}/**  Find the Job in the Queue that is printing.*/ for (i=0; i < cJobs; i++){if (pJobs[i].Status & JOB_STATUS_PRINTING){/**  If the job is in an error state,*  report an error for the printer.*  Code could be inserted here to*  attempt an interpretation of the*  pStatus member as well.*/ if (pJobs[i].Status &amp;(JOB_STATUS_ERROR |JOB_STATUS_OFFLINE |JOB_STATUS_PAPEROUT |JOB_STATUS_BLOCKED_DEVQ)){return TRUE;}}}/**  No error condition.*/ return FALSE;}

3、确定打印队列的状态(C++代码)

问题
  有时,程序员需要显示存在于系统中的各种打印机中打印作业的状态,但似乎不能找到一种方法来查询当前哪些打印机是可用的以及在这些打印机上正在运行哪些作业。
  那么,如何利用 Windows API 函数来查询可用的打印机及其所处的工作状态呢?

方法
  在 Windows NT 版本以及 Windows 9x 中,增加了一批全新的、专门用来处理打印机及打印机队列状态的 API 函数。在本节中,将讨论 API 函数 EnumPrinters 与 EnumJobs,这两个函数可提供给程序员确定打印作业状态所需的信息。
  在 Windows 9x 中添加的函数 EnumPrinters,用来列出所有正在有效运行的打印机的名称及其标识符,此函数可用于列出用户能够访问的无论是在本地工作的还是在网络上运行的所有打印机,在本节的例子中,我们只考虑本地打印机的情况。
  新的 Windows 9x API 中增加的另一个函数 EnumJobs,用来列出所指定打印机上正在打印的作业,为了能够使用这个函数,必须有打印机的句柄,这就需要使用另外一个 API 函数 OpenPrinter。
  需要注意的是,这几个 API 函数只能在 Windows 9x 以及 Windows NT 中使用。

步骤
  按照下列方法生成一个例子程序。选择菜单 Dialog,并从此菜单中选择菜单项 Printer Jobs,此时显示一个所有可用打印机的对话框,在第一个列表框中选择其中一个打印机后,即在第二个列表框中显示该打印机的作业列表。

  实现例子程序的步骤如下:
  1.在 Visual C++ 中利用 AppWizard 创建新的工程 Ld104。
  2.进入 AppStudio,创建新的对话框。把按钮 OK 与 Cancel 移动到对话框的底部。在对话框中添加两个列表框。
  3.进入 ClassWizard,为刚创建的对话模板生成新的对话框类,把此新类命名为 CPrintQDlg。
  4.在 ClassWizard 中,从下拉列表中选择类 CPrintQDlg,从对象列表中选择对象 CPrintQDlg,从消息列表中选择消息 WM_INITDIALOG,点击按钮 Add Function 添加新的函数 OnInitDialog。把下面的代码输入到类 CPrintQDlg 的方法 OnInitDialog 中。

BOOL CPrintQDlg::OnInitDialog()
{CDialog::OnInitDialog();int size=4096;unsigned long sizeNeeded=0;unsigned long numPrinters;PPRINTER_INFO_1 pPrinters;pPrinters=(PPRINTER_INFO_1)LocalAlloc((LMEM_FIXED/LMEM_ZEROINIT),size);int ret=EnumPrinters(PRINTER_ENUM_LOCAL,NULL,1,(LPBYTE)pPrinters,size,&sizeNeeded,&numPrinters);CListBox * list=(CListBox *)GetDlgItem(IDC_LIST1);for(int i=0;i<(int)numPrinters;++i)list->AddString(pPrinters[i].pName);LocalFree(pPrinters);return TRUE;  // return TRUE unless you set the focus to a control
}

  5.在 ClassWizard 中,从下拉列表中选择类 CPrintQDlg,从对象列表中选择对象 IDC_LIST1,从消息列表中选择消息 LBN_SELCHANGE,点击按钮 Add Function 添加新的函数 OnSelectPrinter。把下面的代码输入到类 CPrintQDlg 的方法 OnSelectPrinter 中。

void CPrintQDlg::OnSelectPrinter()
{HANDLE handle;JOB_INFO_1 jobs[10];CListBox * list1=(CListBox *)GetDlgItem(IDC_LIST1);char buf[256];list1->GetText(list1->GetCurSel(),buf);if(!OpenPrinter(buf,&handle,NULL)){MessageBox("Could not open printer","Error",MB_OK/MB_ICONINFORMATION);return;}DWORD size=sizeof(jobs);DWORD numBytes=0;DWORD numEntries=0;int ret=EnumJobs(handle,0,10,1,(LPBYTE)jobs,size,&numBytes,&numEntries);CListBox * list2=(CListBox *)GetDlgItem(IDC_LIST2);for(int i=0;i<(int)numEntries;++i){char buf[80];sprintf(buf,"Job %ld",jobs[i].JobId);if(jobs[i].pStatus!=NULL)strcat(buf,jobs[i].pStatus);else{switch(jobs[i].Status){case JOB_STATUS_PAUSED:strcat(buf," Paused");break;case JOB_STATUS_PRINTED:strcat(buf," Printed");break;case JOB_STATUS_PRINTING:strcat(buf," Printing");break;case JOB_STATUS_SPOOLING:strcat(buf," Spooling");break;}}list2->AddString(buf);}
}

  6.把下面一行代码添加到文件 PrintQDlg.cpp 的顶端。
  #include "winspool.h"
  7.进入 AppStudio 并在菜单 IDR_MAINFRAME 中添加新菜单 Dialog。在此菜单中添加标题为 Printer Jobs 的菜单项,标识符命名为 ID_PRINTER_JOBS。
  8.进入 ClassWizard,从下拉组合框中选择对象 CMainFrame,从对象列表中选择对象 ID_PRINTER_JOBS,从消息列表中选择消息 COMMAND,点击按钮 Add Function 添加新的函数 OnPrinterJobs,把下面的代码输入到此方法中。

void CMainFrame::OnPrinterJobs()
{CPrintQDlg dlg;dlg.DoModal();
}

  9.把下面一行代码添加到文件 MainFrame.cpp 的顶端。
  #include "PrintQDlg.h"
  10.编译并运行此例子程序。

4、更完整的例子可以参考微软的文章:

http://support.microsoft.com/support/kb/articles/Q158/8/28.asp
http://support.microsoft.com/support/kb/articles/Q228/7/69.asp

整理自:https://bbs.csdn.net/topics/50015663

打印系统开发(66)——监控打印机的打印队列相关推荐

  1. 打印系统开发(39)——检查打印机状态

    public class Printer {/// <summary> /// 构造函数 /// </summary> /// <param name="nam ...

  2. 在你计算机上没有配置打印机,打印机没有打印设置,详细教您打印机无法打印怎么解决...

    打印机是越来越普遍了,经常有网友问打印机驱动安装完了怎么不能打印?打印机无法打印是打印机最常见的一种问题,其实这个问题的因素是多方面的,下面,小编就来跟大家介绍打印机无法打印的解决方法了. 在网上会时 ...

  3. 计算机无法打印所有素数的原因,打印机无法打印是什么原因 打印机无法打印解决办法【详细介绍】...

    打印机是现在比较常用到的办公设备,但是长时间使用打印机有时候会遇到打印机无法打印的情况,面对这种情况,很多不明白的人会无从下手.其实打印机无法打印很多情况下是因为设置不当,或者病毒驱动损坏等情况造成的 ...

  4. 计算机名改后远程打印不了,解决远程打印机无法打印问题,不仅仅是关机启动...

    共享打印机出现故障有很多,也是上班族经常遇到故障,但很多上班人员未必都知道如何处理,尽管是很简单故障,但是还需要呼叫维修人员,这样就会影响自己工作.那么更简便方法,就需要自己解决,希望本文能帮到你. ...

  5. 打印系统开发(55)——打印机监视器是什么,为什么安装不上?

    你指的是Print Spooler服务经常无故被停止吧?Print Spooler服务总是自动关闭 尝试访问 Windows 2000 打印服务器上的打印机时,Print Spooler 服务可能会频 ...

  6. API(1)——打印系统开发(32)——Windows API函数大全(精心总结)

    目录 1. API之网络函数 2. API之消息函数 3. API之文件处理函数 4. API之打印函数 5. API之文本和字体函数 6. API之菜单函数 7. API之位图.图标和光栅运算函数 ...

  7. 打印系统开发(60)——XPS格式文件

    工作中跟客户沟通时,对方发来了一个xps文件,经咨询得知:选用虚拟打印机xps打印出来的效果,就是xps文件. 以下内容摘自百科:https://baike.so.com/doc/5509346-57 ...

  8. 打印系统开发(25)——C#打印设置实现源码详解

    C#打印设置是如何在实际编程开发中体现的呢?C#打印设置需要注意什么呢?C#打印设置常用属性是如何进行操作的呢?让我们在实例中解决这些问题吧: C#打印设置实例代码: using System; us ...

  9. API(15)——打印系统开发(52)——WinForm开发(62)——C#通过调用WinApi打印PDF文档类,服务器PDF打印、IIS PDF打印

    其他网站下载来的类,可以用于Winform.Asp.Net,用于服务器端PDF或其他文件打印. 直接上代码: using System; using System.Collections.Generi ...

  10. 为什么打印还要另存为_为什么打印机一打印就会出现另存为

    1.一般的原因是默2113认打印机选错了,可能是安5261装了仿真打印机(4102虚拟打印机),可以进入进入控1653制面板,进入"打印机和传真",看看默认打印机是否是" ...

最新文章

  1. fso 拒绝访问_让虚拟主机免受FSO威胁(转)
  2. 当今世界最受人们重视的十大经典算法
  3. layui移动端适配_移动端适配方案
  4. 如何在关闭ssh连接的情况下,让进程继续运行?
  5. 拳王虚拟项目公社:网上比较容易挣到钱方式?虚拟资源项目是赚钱的最佳选择
  6. 详解 EnumWindows 与 EnumWindowsProc - 回复 SplendourChiang 的问题
  7. 什么是阿里云服务器系统盘和数据盘?
  8. 所有表单对象_表单太多汇总太累?请看这里,我们带你一键汇总
  9. java 出栈_Java开发中巧妙使用链表来实现模拟栈的入栈出栈操作
  10. 注解的引入以及注解的使用
  11. 瑞友天翼苹果手机(iPhone)客户端安装及使用
  12. Rethinking the smaller-norm-less-infromative assumption in channel pruning of convolution layers
  13. 在线聊天静态网页模板html Demo
  14. 如何统计网页的浏览量?Steins
  15. PDF文件如何修改,怎么裁剪PDF页面
  16. python pillow库画图_Pillow画图
  17. translate()方法
  18. 网站安全渗透测试团队公司解决防护方案
  19. git rebase 命令 常用_如何使用Git Rebase
  20. 让老公“寒心”的对话 (转)

热门文章

  1. 兼具教育耐心和AI匠心,看「网易有道词典笔2.0」的变革者角色
  2. 物流工程要学计算机吗,物流工程专业是文科还是理科
  3. wsimport命令生成webService java客户端代码
  4. 系列学习 Gateway 之第 3 篇 —— 过滤器 Filter,自定义全局过滤器
  5. ucore Lab2 物理内存管理
  6. 基于内容的图像检索系统设计与实现
  7. 第三方android 模拟器哪个好用吗,哪个安卓模拟器好用?6款最好用流畅稳定的安卓模拟器推荐...
  8. 3D打印是什么?如何工作的?
  9. 微信小程序点击事件传递参数
  10. 可信计算理论与技术--远程证明技术