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

1.打印机虚脱机技术

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

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

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

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

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

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

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

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

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

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

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

  EnumPrinters();          //枚举打印机

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

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

  1. BOOL
  2. WINAPI
  3. EnumJobs(
  4. HANDLE hPrinter,
  5. DWORD FirstJob,
  6. DWORD NoJobs,
  7. DWORD Level,
  8. LPBYTE pJob,
  9. DWORD cbBuf,
  10. LPDWORD pcbNeeded,
  11. LPDWORD pcReturned
  12. );

  其中,参数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()函数来实现。该函数原型为:

  1. BOOL
  2. WINAPI
  3. OpenPrinter(
  4. LPSTR pPrinterName,
  5. LPHANDLE phPrinter,
  6. LPPRINTER_DEFAULTS pDefault
  7. );

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

3.2获取打印状态

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

  1. /*
  2. * 函数功能 : 显示打印机状态
  3. * 备 注 :
  4. * 作 者 : 博客园 依旧淡然
  5. */
  6. void CPrintDemoDlg::ShowPrinterStatus()
  7. {
  8. HANDLE printerHandle; //打印机设备句柄
  9.  
  10. //检测打开打印机设备是否成功
  11. if(!OpenPrinter(m_strPrinterName.GetBuffer(), &printerHandle, NULL))
  12. return;
  13.  
  14. DWORD nByteNeeded;
  15. DWORD nReturned;
  16. DWORD nByteUsed;
  17.  
  18. //通过调用GetPrinter()函数得到作业数量
  19. PRINTER_INFO_2* pPrinterInfo = NULL;
  20. GetPrinter(printerHandle, , NULL, , &nByteNeeded);
  21. pPrinterInfo = (PRINTER_INFO_2*)malloc(nByteNeeded);
  22. GetPrinter(printerHandle, , (LPBYTE)pPrinterInfo, nByteNeeded, &nByteUsed);
  23.  
  24. //通过调用EnumJobs()函数枚举打印任务
  25. JOB_INFO_2* pJobInfo = NULL;
  26. EnumJobs(printerHandle, , pPrinterInfo->cJobs, , NULL, ,
  27. (LPDWORD)&nByteNeeded, (LPDWORD)&nReturned);
  28. pJobInfo = (JOB_INFO_2*)malloc(nByteNeeded);
  29. ZeroMemory(pJobInfo, nByteNeeded);
  30. EnumJobs(printerHandle, , pPrinterInfo->cJobs, , (LPBYTE)pJobInfo, nByteNeeded,
  31. (LPDWORD)&nByteUsed, (LPDWORD)&nReturned);
  32.  
  33. //检测当前是否有打印任务
  34. if(pPrinterInfo->cJobs == )
  35. return;
  36.  
  37. //纸张类型
  38. CString strPageSize = _T("");
  39. if(pJobInfo[].pDevMode->dmPaperSize == DMPAPER_A4)
  40. strPageSize = _T("A4");
  41. else if(pJobInfo[].pDevMode->dmPaperSize == DMPAPER_B5)
  42. strPageSize = _T("B5");
  43.  
  44. //打印份数
  45. CString strPrintCopies = _T("");
  46. strPrintCopies.Format("%d", pJobInfo[].pDevMode->dmCopies);
  47.  
  48. //打印颜色
  49. CString strPrintColor = _T("");
  50. if(pJobInfo[].pDevMode->dmColor == DMCOLOR_COLOR)
  51. strPrintColor = _T("彩色");
  52. else if(pJobInfo[].pDevMode->dmColor == DMCOLOR_MONOCHROME)
  53. strPrintColor = _T("黑白");
  54.  
  55. //打印时间
  56. CString strSubmitted = _T("");
  57. strSubmitted.Format("%d-%d-%d %d:%d:%d",
  58. pJobInfo[].Submitted.wYear, pJobInfo[].Submitted.wMonth, pJobInfo[].Submitted.wDay,
  59. pJobInfo[].Submitted.wHour+, pJobInfo[].Submitted.wMinute, pJobInfo[].Submitted.wSecond);
  60.  
  61.   //更新打印机状态列表控件
  62. UpdateDataPrinterStatusListCtrl(pJobInfo[].pDocument, strPageSize,
  63. strPrintCopies, strPrintColor, strSubmitted);
  64.  
  65. free(pPrinterInfo);
  66.  
  67. //关闭打印机设备
  68. ClosePrinter(printerHandle);
  69. }

  可以看到,在上述代码中,我们首先调用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. Android 谈谈封装那些事 --BaseActivity 和 BaseFragment(二)

      1.前言 昨天谈了BaseActivity的封装,Android谈谈封装那些事--BaseActivity和BaseFragment(一)有很多小伙伴提了很多建议,比如: 通用标题栏可以自定义Vi ...

  2. UVALive 2453 Wall (凸包)

    题意:给你一个多边形的城堡(多个点),使用最短周长的城墙将这个城堡围起来并保证城墙的每个点到城堡上的每个点的距离都不小于l 题解:因为两点间的直线一定比折线短,所以这样做 先使用所有点求得一个凸包,接 ...

  3. redhat6下安装Lighttpd1.4.43

    学完了C语言,自信满满地冲着开源软件去了,首选了Lighttpd,这个软件代码量不多,适合初入开源的朋友 redhat下安装Lighttpd,一定要先安装依赖库,pcre和bzip2,这两个自行下载, ...

  4. Spark性能优化-coalesce(n)

    有时用Spark 运行Job 的时候,输出可能会出现一些空或者小内容.这时重新将输出的Partition 进行重新调整,可以减少RDD中Patition的数目. 两种方式: 1. coalesce(n ...

  5. [软件推荐]快速文件复制工具(Limit Copy) V4.0 绿色版

    快速文件复制工具(Limit Copy)绿色版是一款智能变频超快复制绿色软件. 快速文件复制工具(Limit Copy)功能比较完善,除了文件复制还可以智能变频,直接把要复制的文件拖入窗口即可,无需手 ...

  6. Attention:本博客暂停更新

    Attention:本博客暂停更新 2016年11月17日08:33:09 博主遗产 http://www.cnblogs.com/radiumlrb/p/6033107.html Dans cett ...

  7. js与多行字符串

    JS里并没有标准的多行字符串的表示方法,但是在用模板的时候,为了保证模板的可阅读性,我们又不可避免的使用多行字符串,所以出现了各种搞法,这里以一段jade的模板作为示例,简单总结和对比一下. 字符串相 ...

  8. 【Linux】Too many open files

    ZA 的BOSS 最近出现Too many open files 异常,这个异常一般是由于打开文件数过多引起, 最常见原因是某些连接一致未关闭 记录一些排查用到的指令 查看每个用户最大允许打开文件数量 ...

  9. XML的简介及其与HTML的区别及联系

    XML: Extensible Markup Language(可扩展标记语言) HTML:HyperText Markup Language(超文本标记语言) 两者都是由万维网联盟(W3C)推出的S ...

  10. 关于 IE6、 IE7兼容性总结(转)

    其实浏览器的不兼容,我们往往是各个浏览器对于一些标准的定义不一致导致的,因此,我们可以进行一些初始化,很多问题都很轻松解决. 下面是14条特殊情况仅供参考: 1. 文字本身的大小不兼容.同样是font ...