在上一篇博文中我主要介绍了如何获取以及设置系统的默认打印机,本文将介绍如何对打印机状态进行实时监控,记录下所打印的文档、打印的份数以及打印时间等打印信息。

1.打印机虚脱机技术

  在正式介绍如何对打印机状态进行实时监控之前,我们有必要先了解一下打印机虚脱机技术。

  独占设备是指在一个程序(作业、用户)的整个运行期间独占设备,直到该程序(作业、用户)完成。系统的独占设备是有限的(比如,一台计算机只能够连接一台打印机),往往不能够满足多进程的要求,会引起大量进程由于等待某些独占设备而阻塞。另一方面,申请到独立设备的进程在其整个运行期间占有设备,利用率却非常低,造成独占设备长时间处于空闲状态。

  为了解决这种矛盾,最常用的办法就是利用共享设备来模拟独占设备,从而提高系统效率和独占设备的利用率。该技术就是虚脱机技术(SPOOL:Simultaneous Peripaheral Operation On Line)。

  打印机是典型的独占设备,引入虚脱机技术后,用户的打印请求传递给SPOOL系统,而不是真正的把打印机分配给用户。SPOOL系统先在磁盘上申请一个空闲区域,把需要打印的数据传输到里面,再把用户的打印请求挂到打印机队列上。如果打印机空闲,就会从打印机队列中取出一个打印请求,再从磁盘的对应区域取出数据,执行打印操作。由于磁盘是共享的,SPOOL系统可以随时响应打印请求并把数据缓存起来,以此实现独占设备模拟共享设备,从而提高系统效率和独占设备的利用率。

2.枚举当前打印机的打印任务

  在Windows API中提供了如下一些打印相关枚举函数:

  EnumForms();         //枚举当前打印机支持的所有页型

  EnumJobs();           //枚举当前打印机的打印任务

  EnumMonitors();         //枚举可用监视器

  EnumPorts();          //枚举可用的打印端口

  EnumPrinterDrivers();     //枚举打印机驱动程序

  EnumPrinters();          //枚举打印机

  EnumPrinterProcessors();   //枚举打印进程

  我们要监控打印机状态,需要用到EnumJobs()函数,用来枚举当前打印机的打印任务。该函数的原型如下:

 BOOL
WINAPI
EnumJobs(
HANDLE hPrinter,
DWORD FirstJob,
DWORD NoJobs,
DWORD Level,
LPBYTE pJob,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pcReturned
);

  其中,参数hPrinter表示打印机对象句柄;参数FirstJob表示作业列表中要枚举的第一个作业的索引(索引号从0开始);参数NoJobs表示要枚举的作业数量;参数Level表示级别(取值可以是1或2);参数pJob表示JOB_INFO_x结构的缓冲区(x由参数Level决定);参数cbBuf表示JOB_INFO_x结构的缓冲区大小;参数pcbNeeded用于保存请求的缓冲区长度;参数pcReturned则表示了载入缓冲区的结构数量。

3.具体编程实现

  了解了EnumJobs()函数之后,我们就可以开始编写具体的代码了。

3.1获得打印机对象句柄

  我们知道,EnumJobs()函数的第一个参数是打印机对象句柄hPrinter,所以在调用EnumJobs()函数之前,我们需要获得打印机对象句柄,这可以通过调用OpenPrinter()函数来实现。该函数原型为:

 BOOL
WINAPI
OpenPrinter(
LPSTR pPrinterName,
LPHANDLE phPrinter,
LPPRINTER_DEFAULTS pDefault
);

  其中,参数pPrinterName是打印机的名称;参数phPrinter就是我们想要得到的打印机对象句柄。

3.2获取打印状态

  获取得到打印机对象句柄之后,我们便可以使用EnumJobs()函数来枚举打印任务,从而得到打印状态了。具体实现方法如下:

 /*
* 函数功能 : 显示打印机状态
* 备 注 :
* 作 者 : 博客园 依旧淡然
*/
void CPrintDemoDlg::ShowPrinterStatus()
{
HANDLE printerHandle; //打印机设备句柄 //检测打开打印机设备是否成功
if(!OpenPrinter(m_strPrinterName.GetBuffer(), &printerHandle, NULL))
return; DWORD nByteNeeded;
DWORD nReturned;
DWORD nByteUsed; //通过调用GetPrinter()函数得到作业数量
PRINTER_INFO_2* pPrinterInfo = NULL;
GetPrinter(printerHandle, , NULL, , &nByteNeeded);
pPrinterInfo = (PRINTER_INFO_2*)malloc(nByteNeeded);
GetPrinter(printerHandle, , (LPBYTE)pPrinterInfo, nByteNeeded, &nByteUsed); //通过调用EnumJobs()函数枚举打印任务
JOB_INFO_2* pJobInfo = NULL;
EnumJobs(printerHandle, , pPrinterInfo->cJobs, , NULL, ,
(LPDWORD)&nByteNeeded, (LPDWORD)&nReturned);
pJobInfo = (JOB_INFO_2*)malloc(nByteNeeded);
ZeroMemory(pJobInfo, nByteNeeded);
EnumJobs(printerHandle, , pPrinterInfo->cJobs, , (LPBYTE)pJobInfo, nByteNeeded,
(LPDWORD)&nByteUsed, (LPDWORD)&nReturned); //检测当前是否有打印任务
if(pPrinterInfo->cJobs == )
return; //纸张类型
CString strPageSize = _T("");
if(pJobInfo[].pDevMode->dmPaperSize == DMPAPER_A4)
strPageSize = _T("A4");
else if(pJobInfo[].pDevMode->dmPaperSize == DMPAPER_B5)
strPageSize = _T("B5"); //打印份数
CString strPrintCopies = _T("");
strPrintCopies.Format("%d", pJobInfo[].pDevMode->dmCopies); //打印颜色
CString strPrintColor = _T("");
if(pJobInfo[].pDevMode->dmColor == DMCOLOR_COLOR)
strPrintColor = _T("彩色");
else if(pJobInfo[].pDevMode->dmColor == DMCOLOR_MONOCHROME)
strPrintColor = _T("黑白"); //打印时间
CString strSubmitted = _T("");
strSubmitted.Format("%d-%d-%d %d:%d:%d",
pJobInfo[].Submitted.wYear, pJobInfo[].Submitted.wMonth, pJobInfo[].Submitted.wDay,
pJobInfo[].Submitted.wHour+, pJobInfo[].Submitted.wMinute, pJobInfo[].Submitted.wSecond);   //更新打印机状态列表控件
UpdateDataPrinterStatusListCtrl(pJobInfo[].pDocument, strPageSize,
strPrintCopies, strPrintColor, strSubmitted); free(pPrinterInfo); //关闭打印机设备
ClosePrinter(printerHandle);
}

  可以看到,在上述代码中,我们首先调用OpenPrinter()函数得到了打印机设备句柄printerHandle,然后通过调用GetPrinter()函数来为PRINTER_INFO_2结构体对象pPrinterInfo赋值,从而进一步通过pPrinterInfo->cJobs得到打印机作业数量。随后,我们通过调用EnumJobs()函数枚举打印任务,为JOB_INFO_2结构体对象pJobInfo赋值。JOB_INFO_2结构体中便存储了我们需要得到的一系列打印机状态信息。最后,我们调用了UpdateDataPrinterStatusListCtrl()函数,将打印机状态信息显示在一个列表控件上。

  程序运行结果如图1所示。在打印机选择下拉列表中,会列出当前系统中的所有打印机,选择要监听的打印机之后,点击开始监听按钮,便会创建一个子线程,对打印机状态进行监听(我这里因为没有连接打印机,所以使用的是虚拟打印机Adobe PDF)。当有文档被打印时,打印状态便会实时的显示在列表中。

图1 打印机状态监控

  由图1可以看出,目前我们已经可以得到打印的文档名称、纸张类型、打印份数、打印颜色以及打印时间这些信息了。如何能够获取得到更多的打印信息呢?比如打印文档的路径、内容、大小、页数等信息,又比如在打印文档中加入自定义页眉、页脚或是水印等。这些功能我还在进一步研究学习,哪位博友若是有这方面的经验,还望指点,我将不胜感激。

【VC++技术杂谈003】打印技术之打印机状态监控的更多相关文章

  1. 关于ASP.NET页面打印技术的总结【转】

    B/S结构导致了Web应用程序中打印的特殊性. • 程序运行在浏览器中,打印机在本地,而文件确可能在服务器上,导致了打印控制不是很灵活. • 格式如何控制和定制等,是我们开发中可能会面对的问题. 打印 ...

  2. 3D打印技术在医疗上的实际应用与实验室研究

    2018-01-17 Chris 免费3D打印模型资源站 预计阅读时间:5-10分钟 关键字:3D打印髋关节.脊柱置换产品,3D打印技术辅助精准截骨,义齿,生物墨水(BioInk),干细胞   随着& ...

  3. 3D打印技术之切片引擎(5)

    [此系列文章基于熔融沉积( fused depostion modeling, FDM )成形工艺] 从这一篇文章開始,就開始说填充.在3D打印切片技术中,填充算法是最核心的部分.3D打印技术的经常使 ...

  4. 后端技术杂谈10:Docker 核心技术与实现原理

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  5. 后端技术杂谈3:Lucene基础原理与实践

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  6. 3D打印技术的火爆,真的会让传统模具行业没落吗?

    当一种新生事物出现时,人们除了赞美它带来的新畅想外,往往还会对"旧事物"贬低几分--各种淘汰观点总是不绝于耳.但可惜的是,新生事物取代旧事物的事儿并不会必然发生.比如,直到现在广播 ...

  7. 后端技术杂谈11:十分钟理解Kubernetes核心概念

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 本文转自 https://github.com/h2pl/Java-Tutorial 喜欢的 ...

  8. 后端技术杂谈9:先搞懂Docker核心概念吧

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  9. 后端技术杂谈8:OpenStack架构设计

    本文转自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutori ...

随机推荐

  1. vaadin学习,重要的网址

    比较重要的几个:UI组件及示例程序:http://demo.vaadin.com/samplerBook of Vaadin:https://vaadin.com/bookAPI:https://va ...

  2. 使用CocoaPods过程中 Unable to find a specification for

    文章转自:http://blog.csdn.net/zhangao0086/article/details/39703083 当把CocoaPods生成的workspace移动到上层目录时,需要改下P ...

  3. 求单链表L各结点的阶乘之和(c语言)

    链表需要用到指针 阶乘需要用到递归 链表中的注意事项: 1.链表L是否等于NULL ----------是循环结束的条件 2.链表L->Data ---------取链表L中各个结点的值 3.L ...

  4. Windows使用总结

    虚拟桌面快捷键: 新建虚拟桌面 Control+Win+D 切换虚拟桌面 Control+Win+左/右方向键 关闭虚拟桌面 Control+Win+F4 显示虚拟桌面列表 Win+Tab  

  5. 工厂模式(Factory)

    一.分类 工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的. 工厂模式主要分为三个,简单工厂模式(Simple Factory)/ 工厂方法模式(Fac ...

  6. webpack 使用教程--实时刷新测试

    学习webpack,基本始终是围绕: 1.如何安装webpack 2.如何使用webpack 3.如何使用loader 4.如何使用开发服务器 可能我们会在如何使用开发服务器的时候,遇到诸如调试的相关 ...

  7. HDU 5008 Boring String Problem(后缀数组+二分)

    题目链接 思路 想到了,但是木写对啊....代码 各种bug,写的乱死了.... 输出最靠前的,比较折腾... #include <cstdio> #include <cstring ...

  8. xampp常见安装失败问题

    遇到这两个错误后不管它,继续安装.完成后下载Microsoft Visual C++ 2008 Redistributable Package (x86),可以到这里下载:Microsoft Visu ...

  9. The Practical Guide to Empathy Maps: 10-Minute User Personas

    That’s where the empathy map comes in. When created correctly, empathy maps serve as the perfect lea ...

  10. Python2 基本数据结构源码解析

    Python2 基本数据结构源码解析 Contents 0x00. Preface 0x01. PyObject 0x01. PyIntObject 0x02. PyFloatObject 0x04. ...