Windows打印管理解決方案


需求

從需求出發,我們的目的是在電腦上提供一個虛擬打印機,然后讓用戶選擇這個虛擬機打印時產生的中間文件被攔截下來,之后進行進一步處理后在執行真實的打印。

Windows打印體系

首先附上查找Windows打印相關內容的鏈接,這個分類下包含了Windows打印的方方面面

https://msdn.microsoft.com/en-us/library/windows/hardware/ff561035(v=vs.85).aspx

Windows2000以后的打印體系結構都是由一個打印機假脫機程序(Spooler)和一系列的打印驅動組成。應用程序通過調用設備無關的函數,就能創建打印任務,並發送到打印設備中。包括激光打印機、矢量繪圖機、光柵打印機和傳真機。

其中打印驅動包括一個渲染組件和一個配置組件。

渲染組件負責將應用程序傳來的每一頁的繪制命令(GDI命令)轉換成打印機用來渲染的命令數據(打印機才能識別的命令)發送到打印機中。

配置組件又包含一個可以讓用戶進行打選項配置的用戶接口組件和一個將打印機的配置和特征傳遞給應用程序的程序接口。

當GDI程序執行打印時,通過調用API來傳遞GDI繪圖指令到繪圖引擎,繪圖引擎要么和打印驅動一起合作來緩存這些繪制指定到一個EMF文件中,要么直接渲染成一個可打印的圖片發送到spooler中。Spooler解釋EMF文件,並將頁面布局和作業控制指令信息插入到數據流中,然后發送這些數據里到序列化、並行化或者網絡形式的打印機關聯的端口上。(XPS設備會有一點不同,這里不進行介紹)。

由於Spooler和打印驅動都是可以被單獨取代,所以硬件廠商們可以很容易的增加對新硬件的支持。當需要增加對新款打印機的支持時,通常只需要創建根據微軟所提供的打印驅動類型中相關聯的數據類型就可以了。

下圖是Windows提供的內置打印驅動程序:

image

 

大致了解了Windows打印體系組成之后,來分別看一下Spooler和打印驅動。

Spooler

從Windows2000開始,打印假脫機程序由一系列的微軟提供的和可選的渲染組件組成,他們的作用包括:

1、檢測是否打印任務是在本地處理還是跨網絡處理。

2、接受GDI和打印驅動為特定類型的打印機所提供的數據流。

3、緩沖繪制數據到文件中。

4、從邏輯打印隊列中選出第一個有效的物理打印機。

5、將緩沖的數據流(如EMF)轉換成能唄打印機硬件所識別的格式(如PCL)。

6、發送打印數據流到打印機硬件中。

7、為假脫機組件和打印機的相關信息維護一個基於注冊表的數據庫

 

Spooler主要組成結構如下圖所示:

image

Application通過調用GDI函數來創建打印任務,通過調用Winspool.drv提供的API接口,將打印內容路由到PrintProvider中。

PrintProvider負責管理本地打印和遠程打印,同時要管理打印任務堆里的啟動、停止和枚舉打印隊列。

我們這里只討論本地打印流程,它提供了下面的能力:

1、打印任務緩沖和解析到打印隊列

2、為Win2000以后的操作系統的打印驅動體系提供支持。

3、為廠商提供的打印處理器的提供支持

4、為場上提供的打印監視器的提供支持

下圖提供了本地打印任務處理流程:

imageimage

如圖所示,應用程序通過GDI接口創建打印任務后,不管是否需要輸出為EMF,本地的PrintProvider任務創建API都會創建一個spool文件。然后,當任務被調度的時候,通過讀取這個spool文件,如果是EMF格式的話,就讓EMF打印處理器配合打印機的渲染驅動,將打印任務發送回去給GDI轉換成RAW格式,最后和沒有使用EMF格式的任務一樣,將數據流傳遞到端口監視器中執行最終打印。

我們通過定制自己的打印機,讓整個打印流程走如上圖中紅線描述的路徑,在打印處理器這一層攔截spool文件及其相關打印信息,來保留整個打印任務的相關數據,等待后續進行處理。

Printer Driver

Windows提供了三種類型的打印驅動,分別為:Universal Printer Driver、PostScript Printer Driver、Plotter Driver。原則上來說這三種類型的驅動已經能支持大多數打印機了,我們只需要簡單的為新的打印機提供對應驅動的DataFile即可。我們這里只討論Universal Printer Driver。

Universal Printer Driver由三部分組成:

1、Printer Graphics DLL: 負責和GDI一起渲染打印任務,並發送渲染數據流到打印假脫機程序中。

2、Printer Interface DLL: 提供打印機參數配置接口和假脫機能調用的用於通知打印系統事件的接口。

3、Printer Data Files:對於Universal Printer Driver而言,這個數據文件就是GPD文件,它用於創建UnidrvMiniDrivers,主要用於描述打印機的可選項配置。包括打印機屬性、相關命令、特征、可選項、字體描述、環境狀態等。

上面三個模塊對應的就是下圖中紅色矩形框住的部分。

image

由於我們不需要對打印渲染和用戶接口做過多的定制,只需要使用標准的Windows打印首選項對話框,所以無需自定義渲染插件和用戶接口插件。當然如果需要的話,也是能在https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff547298(v=vs.85).aspx中找到這些插件重定義的方式。

根據需求,我們只需要自己定制GPD文件,來實現對系統標准的打印機首選項對話框相關設置的定制。(這種方式應該就是UnidrvMiniDrivers)。

解決方案

綜上所述,我們的虛擬打印機要自己定制的模塊就只有打印處理器和GPD文件。

打印處理器負責攔截打印生成的中間文件,GPD文件負責定制打印可選項。

打印處理器定制文檔:https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff563807(v=vs.85).aspx

GPD文件說明文檔:https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff551750(v=vs.85).aspx

打印處理器

WDK提供了支持相關示例,我們在這個示例的基礎上直接更改,主要要更改的地方是在winprint.cpp中,PrintDocumentOnPrintProcessor函數的實現中。我們可以看到打印處理器對一個打印任務的處理流程如下:image

由於我們這里的目的是攔截打印任務產生的中間文件保存下來,所以只需要調用GDI Functions in Print Processors,緩存好spool文件后直接返回(阻止傳遞數據流到spooler中去)。

GPD文件

前面介紹了,GPD文件是使用GPD語言去描述一台打印機,也就是說GPD文件有自己固定的格式,對應GPD語言也有固定的語法,其中主要包括下列信息:

1、Printer attributes: 描述打印機特征

2、Printer commands: 用於控制打印機的操作

3、Printer features: 描述能被通用打印驅動所控制的能力

4、Printer options: 呈現能用來設置Printer features值的狀態。

5、Printer font descriptions :描述和硬件相關連的字體

6、Conditional statements: 描述Printer attributes 和 打印機的配置之間的依賴關系。

此外,GPD語言也定義了一些用來控制一些操作的GPD文件設置,這種操作我們暫不需要。

 

根據上面的描述,要完全自定義一個GPD文件相對來說是比較困難的,這里我們可以通過參考其他打印機中有使用GPD文件的部分,或者參考WDK目錄下\src\print\mini中的GPD文件示例。然后根據需要去修改相應的部分更加簡單。

我這里只對自己所理解的部分進行闡述,更詳細的信息請參考MSDN。

首先GPD文件中最基本的值設置格式Entries,其格式為:image

其中的EntryName都是GPD解析器預定義好的關鍵字(不然GPD解析器無法識別你寫這么個關鍵字是要做什么),而EntryValue則只能是GPD所支持的值類型中的一種(不然GPD解析器無法判斷你這個關鍵字對應的內容正不正確)。關於類型,請自行參考https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff550568(v=vs.85).aspx

 

下面拿我們的GPD文件作為參考進行描述。


image

如圖所示,對於這種*AttributeName:AttributeValue格式的文本,都是前面描述的Printer Attribute,其中放在文件頭部,又更細分為Root-Level-Only Attributes,其各部分含義可參見https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff561989(v=vs.85).aspx


image

如圖所示,上面*%的部分都是注釋,后面的Attribute,則是細分在Printer Capability Attributes下的一些屬性,詳細描述參見https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff560780(v=vs.85).aspx


 

image

如圖所示,形如*Command:CommandName{CommandAttributes}的內容,則屬於Printer Commands。前面描述過這類型是用於控制打印機的操作,其中CommandName都是預定義的命令名,具體這些命令名稱的含義,參見https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff546117(v=vs.85).aspx中各類別的描述。


image

如圖所示,形如*Feature:FeatureName{FeatureAttributes}的內容,描述的便是我們打印機所提供的打印選項功能。Feature又分為標准類型和自定義類型,當然我們只需要提供標准的特征,所支持的標准特種參見https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff562697(v=vs.85).aspx,如截圖中所示即為標准特征中允許選擇紙張方向的特征,這里不僅僅描述了這個特征的說明,而且描述了這個特征是不是必須的和支不支持自定義選項。image

需要說明的是*rcNameID這個屬性段,表述的是對應特征(或者可選項)顯示在界面上的內容的ID,MSDN上也描述了可以使用*Name來直接指定內容。但是我們不需要自己指定。Unidrv驅動提供的stdname.gpd中包含了標准特征顯示的文本的ID,我們只需要引用其中的就可以的。


另外補充說明一下上面Feature中的Option,前面描述了Option對應的其實是Feature可以設置的選項的描述,對應的每一個選項也有固定的格式,可以參見https://msdn.microsoft.com/zh-cn/library/windows/hardware/ff559622(v=vs.85).aspx

對應上面Feature描述的界面效果如下:

image

類似的對應的*Feature:PaperSize產生的界面效果如下:

image


至此,關於GPD文件的描述就結束了。具體需要添加某項特征選項時,可在MSDN上找到對應選項的關鍵字段,然后根據描述設置相應的屬性即可。

參考資料

打印處理器緩沖spool文件相關資料http://www.undocprint.org/winspool/spool_files


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM