設備驅動程序通知應用程序的幾種方法

摘要 在目前流行的Windows操做系統中,設備驅動程序是操縱硬件的最底層軟件接口。爲了共享在設備驅動程序設計過程當中的經驗,給出設備驅動程序通知應用程序的5種方法,詳細說明每種方法的原理和實現過程,並給出實現的部分核心代碼。但願可以給設備驅動程序的設計者提供一些幫助。安全

關鍵詞 設備驅動程序 異步I/O Virtual Device Driver(VxD) Windows Driver Model(WDM)網絡

  在DOS操做系統中,應用程序能夠直接與硬件打交道,包括I/O端口讀寫、中斷請求與響應以及DMA操做等[1]。這種對硬件過於直接的操做方式給軟件設計提供了必定的便利,但也有它自身的一些缺點。首先,一些非法操做有可能改寫某些硬件寄存器的內容,致使操做系統崩潰,從而使操做系統變得不安全,性能不穩定;其次,應用程序的可移植性變差。爲了保證操做系統的安全性和穩定性以及應用程序的可移植性,Windows操做系統不容許應用程序直接訪問系統的硬件資源,而是必須藉助於相應的設備驅動程序。設備驅動程序能夠直接操做硬件,若是應用程序和設備驅動程序之間實現了雙向通訊,也就達到了應用程序控制底層硬件設備的目的。它們之間的通訊包括兩個方面:一方面是應用程序傳送給設備驅動程序的數據;另外一方面是設備驅動程序發送給應用程序的消息。前者的實現較容易,經過CreateFile()函數獲取設備驅動程序的句柄後,就可使用Win32函數,如DeviceIoControl()、ReadFile()或WriteFile()等實現應用程序與設備驅動程序之間的通訊[2]。DDK和MSDN對它們有詳細的描述,讀者能夠參考相關資料。後者的實現遠比前者複雜,同時介紹這方面狀況的文章較少。這不等於說它不重要,相反,它在有些應用場合發揮着重要的做用。例如,在數據採集系統中,應用程序向設備驅動程序發送採集數據的命令後,創建一個輔助線程等待數據採集完成,而應用程序自己則可繼續幹其它的工做。設備驅動程序完成數據的採集工做後,須要立刻通知應用程序,以便應用程序可以及時將數據取走並進行處理。諸如此類狀況,不一而足。數據結構

  鑑於設備驅動程序通知應用程序的重要性,做者結合一些經驗和已有的資料[3~5],對它進行了總結,概括出5種方法:異步過程調用(APC)、事件方式(VxD)、消息方式、異步I/O方式和事件方式(WDM)。下面分別說明這幾種方式的原理,並給出實現的部分源代碼。app

1  異步過程調用(APC)異步

  Win32應用程序使用CreateFile()函數動態加載設備驅動程序,而後定義一個回調函數backFunc(),而且將回調函數的地址&backFunc()做爲參數,經過DeviceIoControl()傳送給設備驅動程序。設備驅動程序得到回調函數的地址後,將它保存在一個全局變量(如callback)中,同時調用Get_Cur_Thread_Handle()函數獲取它的應用程序線程的句柄,而且將該句柄保存在一個全局變量(如appthread)中。當條件成熟時,設備驅動程序調用_VWIN32_QueueUserApc()函數,向Win32應用程序發送消息。這個函數帶有三個參數:第一個參數爲回調函數的地址(已經註冊);第二個參數爲傳遞給回調函數的消息;第三個參數爲調用者的線程句柄(已經註冊)。Win32應用程序收到消息後,自動調用回調函數(實際是由設備驅動程序調用)。回調函數的輸入參數是由設備驅動程序填入的,回調函數在這裏主要是對消息進行處理。函數

2  事件方式(VxD)性能

  首先,Win32應用程序建立一個事件的句柄,稱其爲Ring3句柄。因爲虛擬設備驅動程序使用事件的Ring0句柄,所以,須要建立Ring0句柄。用LoadLibrary()函數加載未公開的動態連接庫Kernel32.dll,得到動態連接庫的句柄。而後,調用GetProcAddress(), 找到函數OpenVxDHandle()在動態連接庫中的位置。接着,用OpenVxDHandle()函數將Ring3事件句柄轉化爲Ring0事件句柄。Win32應用程序用CreateFile()函數加載設備驅動程序。若是加載成功,則調用DeviceIoControl()函數將Ring0事件句柄傳給VxD;同時,建立一個輔助線程等待信號變成有信號狀態,自己則可去幹其它的事情。當條件成熟時,VxD置Ring0事件爲有信號狀態(調用_VWIN32_SetWin32Event()函數),這立刻觸發對應的Ring3事件爲有信號狀態。一旦Ring3事件句柄爲有信號狀態,Win32應用程序的輔助線程就對這個消息進行相應的處理。測試

3  消息方式spa

  Win32應用程序調用CreateFile()函數動態加載虛擬設備驅動程序。加載成功後,經過調用DeviceIoControl()函數將窗體句柄傳送給VxD,VxD利用這個句柄向窗體發消息。當條件知足時,VxD調用SHELL_PostMessage()函數向Win32應用程序發送消息。要讓該函數使用成功,必須用#define來自定義一個消息,而且也要照樣在應用程序中定義它;還要在消息循環中使用ON_MESSAGE()來定義消息對應的消息處理函數,以便消息產生時,可以調用消息處理函數。SHELL_PostMessage()函數的第一個參數爲Win32窗體句柄,第二個參數爲消息ID號,第3、四個參數爲發送給消息處理函數的參數,第5、六個參數爲回調函數和傳給它的參數。Win32應用程序收到消息後,對消息進行處理。操作系統

4  異步I/O方式

  Win32應用程序首先調用CreateFile()函數加載設備驅動程序。在調用該函數時,將倒數第2個參數設置爲FILE_ATTRIBUTE_NORMAL FILE_FLAG_ OVERLAPPED,表示之後能夠對文件進行重疊I/O操做。當設備驅動程序文件建立成功後,建立一個初始態爲無信號、須要手動復位的事件,而且將這個事件傳給類型爲OVERLAPPED的數據結構(如Overlapped)。而後,將Overlapped做爲一個參數,傳給DeviceIoControl()函數。設備驅動程序把這個I/O請求包(IRP)設置爲掛起狀態,而且設置一個取消例程。若是當前IRP隊列爲空,則將這個IRP傳送給StartIo()例程;不然,將它放到IRP隊列中。設備驅動程序作完這些工做後,結束這個DeviceIoControl()的處理,因而Win32應用程序可能不等待IRP處理完,就從DeviceIoControl()的調用中返回。經過判斷返回值,獲得IRP的處理狀況。若是當前IRP處於掛起狀態,則主程序先作一些其它的工做,而後調用WaitForSingleObject()或WaitForMultipleObject()函數等待Overlapped中的事件成爲有信號狀態。設備驅動程序在適當的時候處理排隊的IRP,處理完成後,調用IoCompleteRequest()函數。該函數將Overlapped中的事件設置爲有信號狀態。Win32應用程序對這個事件立刻進行響應,退出等待狀態,而且將事件復位爲無信號狀態,而後調用GetOverlappedResult()函數獲取IRP的處理結果。

5  事件方式(WDM)

  Win32應用程序首先建立一個事件,而後將該事件句柄傳給設備驅動程序,接着建立一個輔助線程,等待事件的有信號狀態,本身則接着幹其它事情。設備驅動程序得到該事件的句柄後,將它轉換成可以使用的事件指針,而且把它寄存起來,以便後面使用。當條件具有後,設備驅動程序將事件設置爲有信號狀態,這樣應用程序的輔助線程立刻知道這個消息,因而進行相應的處理。當設備驅動程序再也不使用這個事件時,應該解除該事件的指針。

  本刊網絡補充版(http://www.dpj.com.cn)中,介紹了各部分實現的部分代碼。

結語

  在目前流行的Windows操做系統中,設備驅動程序是操縱硬件的最底層軟件接口。它向上提供與硬件無關的用戶接口,向下直接進行I/O、硬件中斷、DMA和內存訪問等操做。它將應用程序與硬件細節屏蔽開來,使軟件不依賴於硬件而且可在多個不一樣的平臺之間移植。本文介紹了5種設備驅動程序通知應用程序的方法,其中前3種方法主要用於VxD中,後2種方法主要用於WDM。這5種方法都通過實際測試。測試結果代表,它們都可以達到設備驅動程序通知應用程序的目的。

參考文獻

1  歐青立,徐建波,李方敏,等. 虛擬設備驅動程序VxD的研究與開發[J]. 計算機工程,2003,28(3): 45~46
2  (美)Chris Cant. Windows WDM設備驅動程序開發指南[M]. 孫義, 馬莉波, 國雪飛等譯. 北京: 機械工業出版社, 2000. 20~50
3  Karen Hazzan. Windows VxD與設備驅動權威指南[M]. 孫喜明譯. 北京: 中國電力出版社, 1999. 28~100
4  Walter Oney. Programming the Microsoft Windows Driver Model[M]. (美)Microsoft Press, 1999. 35~180
5  李和平. 基於DSP的ICT圖像重建系統研究[D]. 北京: 北京航空航天大學機械工程及自動化學院, 2002

周正幹  博士、教授,主要研究方向爲計算機測控技術和數字圖像處理技術。 李和平  碩士,研究方向爲數據採集與圖像處理。 安振剛  博士後,研究方向爲機電控制及自動化。

相關文章
相關標籤/搜索