文章出處

  在上一篇博文中我主要介紹了如何獲取以及設置系統的默認打印機,本文將介紹如何對打印機狀態進行實時監控,記錄下所打印的文檔、打印的份數以及打印時間等打印信息。

 

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可以看出,目前我們已經可以得到打印的文檔名稱、紙張類型、打印份數、打印顏色以及打印時間這些信息了。如何能夠獲取得到更多的打印信息呢?比如打印文檔的路徑、內容、大小、頁數等信息,又比如在打印文檔中加入自定義頁眉、頁腳或是水印等。這些功能我還在進一步研究學習,哪位博友若是有這方面的經驗,還望指點,我將不勝感激。

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()