虛擬印表機開發報告

starive發表於2015-05-08


虛擬印表機開發報告


 


 


 


第一章 印表機體系結構和虛擬印表機


 


    1. Windows列印體系結構

      windows xp 的列印體系結構是由列印假離線和一系列列印驅動程式組成。應用程式通過裝置無關的Win32列印和GDI(圖形裝置介面)函式,建立列印作業並將其傳送到不同的裝置,如鐳射印表機、向量繪圖儀、光柵印表機以及傳真機。列印驅動程式包括一個允許使用者控制可選屬性的使用者介面。

      整個的列印流程如下: 應用程式通過呼叫GDI建立列印作業,應用程式對GDI的呼叫傳遞到GDI圖形引擎,該引擎將繪製指令離線處理為EMF檔案(增強型圖元檔案)或者直接連線到印表機驅動程式上,然後將列印影像傳遞到假離線系統。此時應用程式完成了列印文件的任務,使用者可以自由使用應用程式完成其他任務,而列印假離線則保證文件被列印。

      列印假離線將頁面佈局資訊和作業控制指令加入資料流,然後將資料流傳送到列印處理器,列印處理器檢查列印假離線檔案的格式,對於EMF檔案,它將內容的每一頁回放給GDIGDIGDI命令分解成DDI(圖形裝置介面)定義的繪製圖元,並把繪製圖元送到列印驅動程式,印表機驅動程式將繪製圖元繪製成印表機語言格式的原始資料,例如PCL等,接著原始資料被送到列印假離線系統。接著列印假離線將資料傳送到語言監視器,語言監視器把資料傳送到埠監視器,埠監視器用OS檔案系統API往硬體埠寫資料,最後資料被髮送到印表機。

      假離線和印表機元件式可以替換的,這使得硬體供應商可以很容易對新硬體進行支援。整個列印體系結構如圖1-1所示:

       

       

       

       

       

       

       

       

       

       

       

                                 

       

       



 


1-1 列印體系結構圖


 


 


在進行印表機驅動程式開發之前,首先需要明確的是:印表機驅動程式僅僅是Windows列印流程中的一箇中間環節。一個印表機驅動程式是對一種特定印表機提供了一個圖形函式集的動態連結庫(DLL),它所提供的介面函式可以將與裝置無關的輸出資訊轉變為與裝置相關的輸出資訊(指令和資料流)。為了能夠充分理解印表機驅動程式在一個實際列印作業中的地位與功能,從而很好的完成其設計與開發,Windows整個列印流程有一個系統的分析是非常必要的。下面的流程圖(1-2)給出的便是從一個應用程式發出列印請求開始,到本地的列印提供者將假離線檔案寫到磁碟,然後該假離線檔案將在合適的時間被解析成具體的指令和資料,最後由本地埠監視器將解析過的資料流通過它所控制的埠傳送到與之相連的印表機並最終完成列印的完整過程。



1-2 windows列印流程圖


 


 


下面步驟詳細描述整個列印流程:


1:應用程式建立一個裝置上下文並在其上繪製一個物件,然後呼叫GDI


中相應的函式介面向與此裝置上下文相對應的印表機發出一個列印請求。


2:GDI呼叫相應的印表機驅動程式來處理列印請求。


3:列印驅動程式建立一個列印作業,並呼叫GDI函式將處理結果返回GDI


4:GDI呼叫列印假離線系統。


5:列印假離線呼叫列印請求處理器以便將列印作業傳送到應用程式指定的印表機上。


6:列印請求處理器將列印作業傳送到本地列印提供者(目標印表機在本地)


或者網路列印列印提供者(目標印表機在網路中)


7:如果列印作業的型別是非直接列印,那麼本地列印提供者就將列印作業以


原始假離線檔案的格式存放在磁碟上,並且將後來的列印片段不斷的附加到假離線檔案中,直到應用程式呼叫了EndDoc函式終止一個列印作業為止。以上第一到第七步可能是重複多次來產生一個完整的假離線檔案。


8:本地列印提供者啟動一個後臺執行緒,列印主執行緒根據對列印假離線子系統


資源的監視情況,選定一個最佳的時刻觸發假離線檔案的解析過程。此時,列印主執行緒將呼叫StartDoc函式啟動列印處理器中的一個執行緒來開始解析工作。


9:印表機處理器執行緒呼叫ReadPrinter呼叫來啟用本地列印提供者以便從磁碟讀取前面所生成的列印假離線檔案。


10:列印處理器同時還呼叫了WritePrinter函式來啟用印表機作業的語言監視器以便將資料通過物理埠傳送到相應的印表機上。


11:列印語言監視器呼叫列印埠監視器的功能來給印表機傳送資料。


12:列印埠監視器監測物理埠,通過物理埠給印表機傳送資料。


13:埠監視器呼叫核心埠驅動程式完成物理埠與印表機間的通訊。


14:完成列印作業後解析執行緒終止。


 


    1. 虛擬印表機

      虛擬印表機同真實印表機一樣,安裝完畢,開啟控制皮膚中的印表機


和傳真,會看到所安裝的虛擬印表機,可以像使用一臺印表機一樣使用它們。滑鼠雙擊將其開啟,可以對其列印首選項屬性進行修改,從而設定是否共享、可使用時間、是否後臺列印和優先順序,以及紙張大小、版式安排等。它們同樣能截獲所有Windows程式的列印操作,或模擬列印效果,或完成某一特殊功能。有些軟體自帶虛擬印表機,有些則是專門的虛擬印表機,利用這些虛擬印表機,可以幫助我們完成很多特殊的任務。虛擬印表機的列印檔案是以某種特定的格式儲存在電腦


印表機是比較重要的輸出裝置,但有些時候,我們並不需要把東西真實地列印出來,而只是想通過列印預覽功能來看看輸出的效果。但如果計算機中沒有安裝印表機,那麼列印預覽也不能實現,就不能夠觀看到列印的效果,這給我們這些沒有印表機的朋友們帶來了很多不便。


但在實際應用中我們更經常的可能會遇到這樣的問題:我們有印表機,但是我們所使用的軟體只提供給我們列印的功能,我們在列印之前不能預覽。如果我們不想浪費紙、墨,一次又一次試驗呼叫效果,那麼解決辦法只有一個:安裝一個虛擬印表機。


簡單地說,虛擬印表機就是在你的機器中新增一個虛擬的印表機讓你可以使用它來列印。我說的這個虛擬印表機可不同於你以往新增的像hp LaserJet 2000那些只能用於列印預覽虛擬印表機:你可以用它來列印檔案,即使軟體並不支援列印預覽的功能!使用的方法就和你使用正常的印表機一樣.


當然,你不可能用虛擬印表機把檔案直接列印到紙上(否則印表機賣給誰),用虛擬印表機列印的結果是硬碟上的一個檔案,你可以用專門的閱讀器開啟那個檔案以檢視列印的效果。


虛擬印表機實際上並不存在的,只是為了工作需要而安裝的印表機。


 


虛擬印表機有三種定製方法:


1、驅動層(Driver)一種。修改Render plug-in,對渲染繪製過程進行特殊的處理。


2、列印假離線(splooer)層兩種。


 1)自定義列印處理器(PrintProcessor),一般是修改DDKgenprint的例子。將自定義的程式碼加入到PrintDocumentOnPrintProcessor中。


 2)在監視(Monitor)層。作者採用的方法,在後面介紹中讀者會看到。


列印假離線(splooer)層兩種的兩種實現方法驅動層一般都用微軟統一驅動程式(UniDrv)。通過列印測試頁可以瞭解安裝的列印驅動的各個方面:驅動程式、埠等。也可以通過印表機的屬性檢視。作者就是在監視器層進行的。


 


 


 


                  第二章  準備工作     


 


   工欲善其事,必先利其器。同樣在開發時也要選擇合適的整合環境。作者在虛擬列印開發任務中先後用過多款開發工具。如何選擇合適的整合環境,相信沒有唯一的答案。每個人都有自己偏好和標準。在這裡作者會介紹自己的開發工具。希望大家在以後的開發中能得到啟發和幫助。下面,作者一一介紹下工具。


2.1 安裝軟體


NSISNullsoft Scriptable Install System)是一個開源的 Windows 系統下安裝程式製作程式。它提供了安裝、解除安裝、系統設定、檔案解壓縮等功能。這如其名字所指出的那樣,NSIS 是通過它的指令碼語言來描述安裝程式的行為和邏輯的。NSIS 的指令碼語言和通常的程式語言有類似的結構和語法,但它是為安裝程式這類應用所設計的。在虛擬列印開發中,它建立安裝包,它裡面呼叫了windows自帶的功能安裝INF,完成虛擬印表機的安裝任務。NSIS軟體下載地址如下: http://www.flighty.cn/html/book/20100207_18.html )


 


2.2 整合開發工具


以前很多人一直都是用 VS2008 + DDKWizard + WinDbg 來進行驅動程式的開發除錯的,使用 DDKWizard 來搭配除錯環境,在 VS2008 下還算方便,因為不需要自己去設定一些什麼包含檔案和原始碼路徑之類的就可以直接編譯驅動程式原始碼,安裝好 DDKWizard 後在 VS2008 中就會自動出現一個開發驅動程式的專案框架,就跟選擇建立 WinForm 應用程式一樣的,建立好 DDK 專案後也是可以直接在 VS2008 下編譯的,所以在開發上方便,但是在除錯上的話,就麻煩了,在 WinDbg 中有一大堆東西要設定,在虛擬機器上也要設定一些命令。


但是在使用 DDKWizard + VS2008 進行驅動開發時,是不能夠直接通過 VS2008 來除錯的,而一般都是在 WinDbg 中設定好符號檔案的路徑以及原始碼的路徑,然後再驅動程式的原始碼中嵌入一些彙編程式碼,當然這些彙編程式碼只是簡單的用來實現一箇中斷,從而在 WinDbg 偵錯程式中會生成一個斷點。這樣除錯起來速度慢,也不好控制,所以有時候覺得在做開發的時候,在除錯上花去的時間太多了,會不爽。


在本專案中,將要介紹的是一個開源專案 VirtualDDK,通過這個開源專案即可以很好的實現在 VS2010 以及 VS2008 下直接除錯驅動程式,同時對於 VirtualDDK 的環境搭配也是很簡單的,下面提供的連結直接上一些圖片以及一些註解來說明,由於文章存在大量的截圖,所以讀者只要按著截圖來做基本上都可以成功的。VS2010 + VMware + DDK (安裝參見: http://techird.blog.163.com/blog/static/1215640362011112385241568/)


    Dev-c++開發工具不是必須的,讀者可自行選擇。下載地址:http://pan.baidu.com/share/link?shareid=524654&uk=3241605080)


 


2.3 埠監視器


    由於作者採用第三種方法來進行虛擬列印開發,因此作者要重點介紹下Monitor層方面的知識點。


2.3.1列印監視器介紹


在第一章曾經提到了列印監視器的概念。列印監視器主要負責把列印資料流


從列印假離線傳送到合適的埠驅動程式。列印監視器分為語言監視器和埠監


視器兩種。其中語言監視器的主要作用是支援印表機的雙向通訊,監視印表機的


狀態,獲取並處理一些事件;埠監視器的主要作用是管理配置列印埠並控制


印表機和物理埠之間的通訊。在印表機驅動系統體系中,這兩個監視器都是可


替換的,即開發人員可以根據需要編寫自己的語言和埠監視器。比如編寫語言


監視器提供對印表機雙向通訊的支援等。


在基於NT的作業系統下,使用者所看到的印表機檢視其實是一個列印佇列,一個或者多個物理印表機裝置可以與該佇列相連。埠就是列印佇列和一個列印


裝置之間的物理連線。印表機驅動程式中埠監視器模組負責和埠相關的操作。


每一個埠監視器支援一種或者多種埠型別的例項。當需要給印表機新增新類


型的埠例項時,就需要提供新的埠監視器。列印假離線通過呼叫AddPrinier


函式來把一個埠指派到埠監視器中。在列印過程中,各種型別的列印裝置都


被列在列印佇列中,列印假離線把列印作業傳送到第一個可用的埠。如果埠


監視器指示這個埠正忙或者發生錯誤,列印假離線把列印作業重新提交到列印


佇列,並指定該埠監視器支援的另外一個埠傳送列印資料。


2.3.2埠監視器構成


一個埠監視器由一些使用者模式下的動態連結庫組成。它的職責有兩方面,


一是負責管理和配置伺服器端的和印表機硬體連線的列印埠;二是為執行在用


戶模式下的列印假離線和執行在核心模式下的可以直接訪問FO硬體埠的埠


驅動之間建立通訊連結。


Windows2000和以後的作業系統而言,每一個埠監視器都被分為兩個


動態連結庫:


l:Port Monitor Ul DLL


埠監視器的介面動態連結庫包括功能性的使用者介面。這個動態連結庫存放


在客戶系統的System32資料夾中並且在印表機的客戶端系統上執行。


2:PortMonitorServerDLL


埠監視器的服務動態連結庫包括埠的通訊功能並且在印表機的伺服器端系統上執行。


以上兩個動態連結庫之間通過列印假離線的XcvData函式通訊。需要說明的是:雖然埠監視器被分成了兩個動態連結庫,但是在具體編寫埠監視器的過程中,卻可以有兩種方法:一是為新編寫的埠服務動態連結庫編寫全新的介面動態連結庫,而這樣的介面動態連結庫提供給使用者的管理介面只能對新新增的埠型別進行管理;第二種方法是使用原來的介面動態連結庫,這種情況下,新新增的埠型別會直接新增到原來的介面動態連結庫的列印佇列中,只需要為新新增的埠提供一個可以修改配置資訊的彈出對話方塊即可。這兩種方法在功能的實現方面沒有區別。第一種方法可能複雜一些,但是介面簡單整潔。下面兩幅圖描述了列印監視器在整個列印流程中所處的位置。其中圖2-1左側的是有語言監視器的情況,圖右側的是沒有語言監視器的情況。



 


                 2-1 列印處理機到印表機的資料流程圖


 


 


 


 


2.3.3 資料通訊模組


當一個列印監視器進行了正確的初始化並且正確新增了列印埠之後,監視器就可以開始與印表機物理埠的資料通訊工作。下面介紹資料通訊模組的核心工作。


每一個列印作業都會首先被列印假離線劃歸到某個語言或者埠監視器的


StartDocPortEndDocPort函式中。這兩個函式也就成了完成一個列印作業的開始和結束函式。這裡的開始和結束,僅僅是針對一個列印作業的,並不是指整個列印流程。所以在StartDocPort函式之前和EndDocP0rt之後,假離線還會呼叫其他的函式來完成整個列印流程。下面圖2-2展示了完成一個列印作業的基本流程.如圖所示,要完成一個列印作業需要經過以下幾個步驟:


1:開啟埠


列印假離線首先要呼叫埠監視器的OpenP0rt函式,該函式的主要功能是打


開一個埠並返回一個標識該埠的控制程式碼。在假離線的後續呼叫中,該控制程式碼將作為其他處理函式的輸入引數使用。針對某些埠,OpenP0rt函式還可以在列印假



2-2 埠監視器資料通訊流程圖


 


 


離線讀埠或寫埠之前完成一些初始化的工作,比如對那些支援可修改超時值的埠而言,每次埠超時值的設定就由OpenPort函式完成。當一個埠被正確開啟之後,該埠就可以被寫入資訊。列印假離線在同一時間只允許一條可用的通訊鏈路和一個列印埠連線。因此當假離線在埠監視器中呼叫了OpenPort函式之後,在關閉這個埠之前,它不會再次嘗試去開啟這個埠。而在埠被關閉之前,假離線可以傳送多個列印作業到這個埠。


2:開始列印作業


一個埠被開啟之後,列印假離線接著呼叫startDocPort函式來開始一個打


印作業。StartDocPort函式主要通過呼叫WindowsAPI提供的CreateFile函式來建立一條和核心埠驅動之間的資料連結。


3:/寫埠


當資料連結建立之後,列印假離線可以根據需要進行雙向操作,一種是向打


印機寫資料,這種情況下列印假離線先呼叫埠監視器的WritePort函式然後會多次呼叫WindowsAPI提供的WriteFlle函式來向核心埠驅動傳送資料;另一種


是從印表機讀資料,此時列印假離線先呼叫埠監視器的ReadPort函式然後再呼叫WindowsAPI提供的ReadFile函式從核心埠驅動那裡讀取硬體資訊。


4:資料傳送


不管是向印表機寫資料還是從印表機讀資料,列印假離線後面都會呼叫


GetPrinterDataFromPort函式,該函式的主要功能是通過呼叫WindowsAPI提供的DeviceIoControl函式來最終實現列印驅動程式和核心埠驅動之間的資料傳輸。


5:結束列印作業


以上操作完成之後,列印假離線呼叫EndDocPort函式來結束一個列印作業。


該函式的主要作用是釋放CreateFile函式建立的資料連結和StartDocPort函式中申請的所有資源。EndDocPort函式和StartDocPort函式總是成對出現的。


6:迴圈檢測


當按照上述過程完成了一個列印作業之後,列印假離線檢視和這個埠相連


的列印佇列中還有沒有其他的檔案需要列印。如果有,則程式返回到StartDocPort函式重複執行上述過程,如果沒有,列印假離線就關閉這個埠。


7:關閉埠


埠監視器的ClosePort函式用來關閉埠。該函式的主要作用是釋放在


OpenPort函式中申請的所有系統資源。ClosePort函式和OpenPort函式也總是成對出現。當與一個埠相關的列印佇列中所有的列印作業都完成之後,或者由於其他情況需要退出該埠的時候,ClosePort函式就被列印假離線呼叫


 


 


 


第三章  開發


 


3.1 專案原始碼


專案原始碼可自行選擇,網上有很多程式碼可供下載,比如大家常用的就是在DDKWIN2000)裡面有一個例子genprint,它是一個印表機驅動,只要我們在這個例子的程式碼中進行修改就可以實現自己想要的功能。但是本人採用的是ImagePrinter的原始碼。下載虛擬列印原始碼Imageprinter, 下載地址:  http://code-industry.net/downloads.php


 


3.2 配置開發環境


  3.2.1 若選用VS2010開發,引數配置較繁瑣,可參見:http://jingyan.baidu.com/article/b2c186c8eae112c46ef6ffb8.html


  3.2.2 若選用Dev-c++配置簡單,在此不復述。


 


3.3 編譯除錯


開發並編譯原始碼,生成imgport.dll檔案。


    開發時候會出現各種bug,希望大家有效地利用MSDN和論壇來解決各種問題。


 


 


第四章 安裝虛擬印表機


4.1 安裝廠商和印表機


4.1.1 安裝前系統配置


  安裝之前,電腦裡面沒有 埠 Imageprinter Port  廠商code-industry 及其印表機ImagePrinter的驅動程式,如下圖4-1到圖4-2



4-1



4-2



4-3


 


 


3.1.2 安裝


新建目錄,將專案編譯過的專案原始碼及其DLL檔案集中一起,imgport.dll檔案放入 ..\imgport\install\i386資料夾中。進入目錄:..\imgport\install


右擊滑鼠右鍵--》編譯NSIS指令碼檔案(注意: 編譯之前務必將專案編譯產生的imgport.dll拷貝到..\imgport\install\i386資料夾下,否則無法進行後續任務,因為NSIS軟體打包生成安裝包時會利用所有的DLLINFGPD等檔案),生成可執行安裝檔案setup.exe,如圖4-4



4-4


 


 


執行setup.exe檔案,安裝埠Imageprinter Port、廠商code-Industry和印表機ImagePrinter。安裝後系統配置,如下:4-5


在“新增或刪除程式“中可以看到:



4-5


 


埠、廠商及印表機驅動程式均已經安裝上,如下圖4-6、圖4-7



4-6


 



4-7


 


去“控制皮膚”-> “印表機和傳真,可以看到剛剛安裝的印表機 ImagePrinter


如圖4-8


 



4-8


可能會有人會問:沒有安裝INF檔案,怎麼就把虛擬印表機安裝好? 細心的讀者應該能發現,在虛擬列印開發中,NSIS軟體建立安裝包,它呼叫的各種檔案中包含了windows自帶的功能安裝INF,從而完成虛擬印表機的安裝任務。


 


4.2 測試印表機


  4.2.1 新建word文件,輸入要列印的文字,然後選擇列印”-》“ImagePrinter”印表機-》確定,如圖4-9



 


 


4.2.1 虛擬列印成功,如圖4-10



4-10


 


    至此虛擬列印成功。


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


 


第五章 總結


 


本文對Windows (XP)平臺下印表機裝置驅動程式的開發進行簡要的論述。以在Windows環境下完成一次列印任務的完整流程為線索,介紹了其中的各個功能模組,並深入分析了一個埠監視器例項的設計和實現,最後根據原始碼ImagePrinter應用實際設計完成了一個印表機驅程程式。一般來說,編寫一個完整的印表機驅動程式所要做的工作如下:


第一步:熟悉Windows操作的列印流程,明確驅動程式在這個流程中所處的位置。


第二步:閱讀WindowsDDK和其他相關文件,明確驅動程式各元件的功能劃分及相互間的關係。


第三步:明確驅動程式各元件的功能模組和設計方法,確定各模組間的介面函式。


第四步:分別編寫所需的功能模組和各個介面函式。


第五步:編譯、除錯驅動程式,生成可用的動態連結庫。


第六步:為所生成的驅動程式以及其他相關檔案生產一個安裝檔案(.inf)。或者選用其他工具安裝,作者就是採用NSIS來安裝的。


第七步:安裝,測試、修改、再重新編譯連結,重複這幾個步驟直到達到要求為止。


目前,印表機驅動程式的開發主要還是由各印表機生產廠家完成,出於商業保護的考慮,他們都隱藏了自己的技術細節。微軟雖然提供了一些印表機驅動方面的開發文件和源程式,但是都是一些最基本功能的實現,其它的參考文獻也大都是從Windows DDK翻譯而來,參差不齊。


由於本人的工作是從零開始的,以前沒有window底層的開發經驗,同時缺少很多資料,因而實現的印表機驅動程式只具有基本的虛擬列印功能,還需要繼續的補充和改進。


由於本人水平有限,對一些問題的理解還不夠深入,如有錯誤與不妥之處,敬請大家批評指正。


 


 


 


 


 


 


 


 


 


 


 


第六章 參考文獻


 


[1]張帆、史彩程, Windows驅動開發技術詳解,電子工業出版社,2008-7-1


[2]張佩、馬勇、董鑑源, 竹林蹊徑 深入淺出Windows驅動開發,電子工業出版社,2011-2


[3]MSDN 參考資料, http://msdn.microsoft.com/en-us/library/windows


/hardware/ff563806(v=vs.85).aspx


[4]孫守閣、徐勇,Windows裝置驅動程式技術內幕,清華大學出版社,2000


[5]何斌,黃進,陳其昌,Windows環境下印表機驅動程式設計,電子計算機與


外部裝置,20003


[6]田玉敏,燕紅鎖,Windows2000下印表機驅動程式開發,計算機工程,2002


3


[7]尤晉元,史美林,陳向群等,Windows作業系統原理,機械工業出版社,2001


[8]譚文,楊瀟等,寒江獨釣Windows核心安全程式設計,電子工業出版社,2009-6


[9]Johnson M.HartWindows系統程式設計(第三版),機械工業出版社,2010-10


 


 


 


 


 


 


 


 


 


 


 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26435490/viewspace-1629211/,如需轉載,請註明出處,否則將追究法律責任。

相關文章