在上一篇博文中我主要介紹瞭如何獲取以及設置系統的默認打印機,本文將介紹如何對打印機狀態進行實時監控,記錄下所打印的文檔、打印的份數以及打印時間等打印信息。編程
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能夠看出,目前咱們已經能夠獲得打印的文檔名稱、紙張類型、打印份數、打印顏色以及打印時間這些信息了。如何可以獲取獲得更多的打印信息呢?好比打印文檔的路徑、內容、大小、頁數等信息,又好比在打印文檔中加入自定義頁眉、頁腳或是水印等。這些功能我還在進一步研究學習,哪位博友如果有這方面的經驗,還望指點,我將不勝感激。