【打印技术02】打印机状态监控

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

 

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(0), &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, 2, NULL, 0, &nByteNeeded);
21     pPrinterInfo = (PRINTER_INFO_2*)malloc(nByteNeeded);
22     GetPrinter(printerHandle, 2, (LPBYTE)pPrinterInfo, nByteNeeded, &nByteUsed);
23     
24     //通过调用EnumJobs()函数枚举打印任务
25     JOB_INFO_2* pJobInfo = NULL;
26     EnumJobs(printerHandle, 0, pPrinterInfo->cJobs, 2, NULL, 0, 
27         (LPDWORD)&nByteNeeded, (LPDWORD)&nReturned);
28     pJobInfo = (JOB_INFO_2*)malloc(nByteNeeded);
29     ZeroMemory(pJobInfo, nByteNeeded);
30     EnumJobs(printerHandle, 0, pPrinterInfo->cJobs, 2, (LPBYTE)pJobInfo, nByteNeeded, 
31         (LPDWORD)&nByteUsed, (LPDWORD)&nReturned);
32     
33     //检测当前是否有打印任务
34     if(pPrinterInfo->cJobs == 0)
35         return;
36     
37     //纸张类型
38     CString strPageSize = _T("");
39     if(pJobInfo[0].pDevMode->dmPaperSize == DMPAPER_A4)
40         strPageSize = _T("A4");
41     else if(pJobInfo[0].pDevMode->dmPaperSize == DMPAPER_B5)
42         strPageSize = _T("B5");
43 
44     //打印份数
45     CString strPrintCopies = _T("");
46     strPrintCopies.Format("%d", pJobInfo[0].pDevMode->dmCopies);
47 
48     //打印颜色
49     CString strPrintColor = _T("");
50     if(pJobInfo[0].pDevMode->dmColor == DMCOLOR_COLOR)
51         strPrintColor = _T("彩色");
52     else if(pJobInfo[0].pDevMode->dmColor == DMCOLOR_MONOCHROME)
53         strPrintColor = _T("黑白");
54 
55     //打印时间
56     CString strSubmitted = _T("");
57     strSubmitted.Format("%d-%d-%d %d:%d:%d",
58         pJobInfo[0].Submitted.wYear, pJobInfo[0].Submitted.wMonth, pJobInfo[0].Submitted.wDay,
59         pJobInfo[0].Submitted.wHour+8, pJobInfo[0].Submitted.wMinute, pJobInfo[0].Submitted.wSecond);
60 
61   //更新打印机状态列表控件
62     UpdateDataPrinterStatusListCtrl(pJobInfo[0].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可以看出,目前我们已经可以得到打印的文档名称、纸张类型、打印份数、打印颜色以及打印时间这些信息了。如何能够获取得到更多的打印信息呢?比如打印文档的路径、内容、大小、页数等信息,又比如在打印文档中加入自定义页眉、页脚或是水印等。这些功能我还在进一步研究学习,哪位博友若是有这方面的经验,还望指点,我将不胜感激。

客户端安装个软件。负责监控该电脑的打印动作。并把内容转成图片储存。并将图片传送到服务器机器上,并将打印内容传到服务器上面. 解决方案: 1. 先用api打印函数连接到指定的打印机.再试着用枚举函数()获得打印作业信息.根据信息得知打印的内容,及当前的状态. 2. 获知内容,得知打印内容所在的位置,再某种方式将数据导在图片;再传到服务器上. 技术问题: 1. 打印枚举函数中找不到JOB_INFO_1 或 JOB_INFO_2结构的定义.(已解决) 2. 怎么样获得打印内容.是通过原本的驱动还是其它办法, 其它: 文件传给pdf打印机之前已经存成raw格式了,应该是从缓冲池中直接读取数据 接下去要完成的应该是怎么把raw格式读出来, 具我推测在获得打印信息的时候肯定有某个参数跟这个RAW格式是对应的.读出某个参数后才能再继续读取对RAW文件读取 具微软件网站显示,打印机的格式应该分成5种.raw的三种格式,text,emf(增强型图元文件) RAW格式指是最原始的数据 CreateDC("WINSPOOL", printer, null, ref dv);//用DISPLAY,是获取整个屏幕的设备场景;2、用WINSPOOL,则是访问打印驱动 返回新设备场景句柄,若出错则为零 EMFStreamPrintDocument 实力问题:就算获得句柄也没有办法接下去要做什么.(想错了) 目前状态:EMF图片取出来,监控也可以实现了.但监控打印作业跟EMF图片不知道怎么产生关联.而且EMF图片读起出来比较慢. 取EMF图片本身spl就已经读入内存,但是有一种办法为了要读取图片只能将spl文件考出来再做成emf文件. 新的思路能不能将文件 shd文件中包含了一个作业ID RPC 命名管道 Server(服务器) Server 系统服务提供 RPC 支持以及文件、打印和命名管道在网络上的共享。Server 服务允许本地资源(如磁盘和打印机)共享,因此网络上的其他用户可以访问它们。它还允许在其他计算机上的应用程序与您计算机上的应用程序之间进行命名管道通信,这是用于 RPC 的。命名管道通信是为一个进程的输出(此输出用作另外一个进程的输入)而保留的内存。接受输入的进程不必是本地进程。
1. 该软件无须安装,直接将软件包解压缩到一个目录下,运行PrinterMon.exe程序即可。 2. 如果需要该程序随系统启动而自动启动,则在软件的“打印机列表”节点下, 勾选“用户登录系统后自动运行打印机监视程序”项即可。 3. 该软件除了可以监视本地的打印机之外,还可以监视网络中其他共享的打印机。 只要利用“添加打印机”中提供的三种方法之一枚举相关的打印机, 添加到监控打印机列表中即可。 4. 监控网络上的打印机时,要提供正确的登录认证设置,保证网络可连通并具有合适的权限。 5. 注意防火墙的设置,保证可以正常访问网络上的打印机。 6. 该软件为完全免费,除软件主窗口下部的信息区会尝试连接我们的网站 (http://www.3000soft.net)获取最新产品资料之外,不含有任何收集用户资料或其它恶意的代码。 任何情况下,我们都不为可能造成的任何可以预见或不可预见的损失承担责任。 如果您持有怀疑或担心,请选择不运行此软件,立即删除这些文件。 7. 该软件主要为企业管理者提供打印机、纸张、文件档案等公司资源的监控服务。 因为网络和系统的复杂性,监视到的打印作业资料不表示一定准确,请不要盲目地 依此作出什么结论性的判断。 8. 请不要超越您自己的权限与职责的范围去使用该软件,使用该软件的一切可能后果请自负。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值