【VC++技術雜談003】打印技術之打印機狀態監控

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

 

1.打印機虛脫機技術緩存

  在正式介紹如何對打印機狀態進行實時監控以前,咱們有必要先了解一下打印機虛脫機技術。函數

  獨佔設備是指在一個程序(做業、用戶)的整個運行期間獨佔設備,直到該程序(做業、用戶)完成。系統的獨佔設備是有限的(好比,一臺計算機只可以鏈接一臺打印機),每每不可以知足多進程的要求,會引發大量進程因爲等待某些獨佔設備而阻塞。另外一方面,申請到獨立設備的進程在其整個運行期間佔有設備,利用率卻很是低,形成獨佔設備長時間處於空閒狀態。學習

  爲了解決這種矛盾,最經常使用的辦法就是利用共享設備來模擬獨佔設備,從而提升系統效率和獨佔設備的利用率。該技術就是虛脫機技術(SPOOL:Simultaneous Peripaheral Operation On Line)。spa

  打印機是典型的獨佔設備,引入虛脫機技術後,用戶的打印請求傳遞給SPOOL系統,而不是真正的把打印機分配給用戶。SPOOL系統先在磁盤上申請一個空閒區域,把須要打印的數據傳輸到裏面,再把用戶的打印請求掛到打印機隊列上。若是打印機空閒,就會從打印機隊列中取出一個打印請求,再從磁盤的對應區域取出數據,執行打印操做。因爲磁盤是共享的,SPOOL系統能夠隨時響應打印請求並把數據緩存起來,以此實現獨佔設備模擬共享設備,從而提升系統效率和獨佔設備的利用率。線程

 

2.枚舉當前打印機的打印任務code

  在Windows API中提供了以下一些打印相關枚舉函數:orm

  EnumForms();         //枚舉當前打印機支持的全部頁型對象

  EnumJobs();           //枚舉當前打印機的打印任務blog

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

相關文章
相關標籤/搜索