[Windows驱动开发](三)基础知识——驱动例程
一、NT式驅動的基本例程
1. 驅動入口函數——DriverEntry
[cpp]?view plaincopyDriverEntry的主要工作是對驅動程序進行初始化。它由系統進程System調用的。
驅動被加載的時候會創建一個驅動對象,查詢此驅動程序對應的注冊表項。
DriverEntry被調用的時候會傳進兩個參數。他們分別是剛才創建的驅動對象的指針和指向設備服務鍵的鍵名字符串指針。這個字符串的內容一般是\RESGISTRY\MACHINE\SYSTEM\ControlSet\Services\[服務名]。在驅動程序中,字符串一般以UNICODE形式存在:
注:設備服務鍵的鍵名有時候需要保存下來,當函數返回的時候此值可能會被清空。DriverEntry等內核函數的返回值一般是NTSTATUS類型的。使用宏NT_SUCCESS(NTSTATUS status)可檢測返回狀態是否成功。
在DriverEntry中,一般需要做一下幾件事情:
a. 設置驅動卸載例程
b. IRP的派發函數
c. 創建設備對象
其中,驅動卸載例程與IRP派發函數都是對驅動對象設置的。設備對象中有一個MajorFunction數字,用來存放哥哥IRP派發函數的函數指針。
在NT式驅動中,創建設備對象可以調用IoCreateDevice:
[cpp]?view plaincopy DriverObject:當前驅動對象指針。
DeviceExtensionSize:設備擴展的大小。IO管理器會根據這個大小在內存中創建設備擴展,并與驅動對象關聯。
DeviceName:設備對象的名稱。
DeviceCharacteristics:設備對象的特征。
Exclusive:設備對象是否為內核模式下使用,一般固定為TRUE。
DeviceObject:創建好的設備對象指針。
注:設備名稱字符串必須是\Device\[設備名]的形式。
讓用戶態的應用程序能識別設備一般有兩種方法:
a.?符號鏈接 b. 設備接口(在NT式驅動很少使用)符號鏈接可以理解為設備對象在用戶態的名稱。即:設備名稱在內核態使用,符號鏈接在用戶態使用。
創建符號鏈接可以使用IoCreateSymbolicLink:
[cpp]?view plaincopySymbolicLinkName:符號鏈接名。
DeviceName:設備對象名。
注:在內核態,符號鏈接是以“\??\”或者“\DosDevices\”開頭的。而在用戶模式下則是以“\\.\”開頭的。
設備擴展在被使用時可使用如下的代碼:
2.?驅動卸載例程——DriverUnload
此例程在驅動卸載的時候被調用。在NT式驅動里面負責刪除在DriverEntry中創建的設備對象,并且刪除與其相關聯的符號鏈接。同時還負責某些資源的回收工作。
刪除設備對象的函數是IoDeleteDevice
[cpp]?view plaincopyDeviceObject:要被刪除的設備對象指針。
刪除符號鏈接的函數是IoDeleteSymbolicLink
[cpp]?view plaincopySymbolicLinkName:已經被注冊的、待刪除的符號鏈接。
根據驅動對象可以遍歷所有由該驅動創建的設備對象。通過驅動對象的DeviceObject域可以找到驅動對象的第一個設備,然后根據設備對象的NextDevice域,就可以找到設備鏈表中其他的設備對象。
二、WDM式驅動的基本例程
在WDM模型中,一個設備的操作至少需要兩個設備對象共同來完成。一個是物理設備對象(Physical Device Object,簡稱PDO),一個是功能設備對象(Function?Device?Object,簡稱FDO)。當計算機插入某個設備的時候,總線驅動會自動創建PDO。PDO不能單獨操作設備,必須與FDO一起使用。當Windows提示要安裝驅動的時候,實際上安裝的是WDM驅動程序,負責創建FDO,并附加到PDO上。
當一個FDO附加在PDO的時候,PDO的AttachedDevice會記錄FDO的位置。PDO是底層驅動(下層驅動),FDO是高層驅動(上層驅動)。
在FDO與PDO之間還會存在過濾驅動。在FDO上面的叫做上層過濾驅動,在FDO下層的叫做下層過濾驅動。一個WDM驅動可以有很多個上層過濾驅動和下層過濾驅動。設備對象的StackSize子域表明該設備對象到最下層的物理設備中間還存在的設備對象數。
1.?WDM驅動的入口函數——DriverEntry
和NT式驅動一樣,WDM驅動的入口程序也是DriverEntry。但是創建設備對象的功能并不在DriverEntry中執行,而是交給了新的例程——AddDevice;同時增加了對IRP_MJ_PNP處理的派發函數。
AddDevice例程是WDM特有的,在DriverEntry中需要設置AddDevice例程的函數地址。設置的方式是在驅動對象的DriverExtension子域的AddDevice子域保存AddDevice實際例程的函數地址。AddDevice例程的名字可以隨意命名。
[cpp]?view plaincopy 2.?驅動卸載例程——DriverUnload()
? ? a.?IRP_MN_REMOVE_DEVICE處理 ? ? 驅動橫須內部是由IRP驅動的,IRP_MN_REMOVE_DEVICE這個IRP是當設備需要被卸載的時候,由即插即用管理器創建,并發送到驅動程序中的。IRP一般由兩個號碼指定該IRP的具體意義,一個是主IRP號(Major IRP),一個是輔IRP號(Minor IRP)。 ? ? 當設備需要被卸載的時候,會先后發出多個IRP_MJ_PNP。這些IRP的輔IRP號會有所不同。其中之一的IRP_MN_REMOVE_DEVICE。 ? ? 在WDM驅動程序中,對設備的卸載一般是在對IRP_MN_REMOVE_DEVICE的出口函數中進行卸載。其除了需要刪除學部,取消符號鏈接外,還需要將FDO從PDO的堆棧中移除。需要調用IoDetachDevice: [cpp]?view plaincopy
AddDevice基本步驟: 1. AddDevice通過IoCreateDevice函數創建FDO,創建FDO的符號鏈接 2. 在驅動設備擴展保存剛才創建的FDO的地址。 3. 調用IoAttachDeviceToDeviceStack()將FDO附加到PDO上。 [cpp]?view plaincopy
[cpp]?view plaincopy
4. 設置設備擴展pFunctionDeviceObject->Flags。 ? ? DO_BUFFERED_IO:緩沖內存設備 ? ? ~DO_DEVICE_INITIALIZING:這個必須設置,表示完成Flags的初始化。
總結
以上是生活随笔為你收集整理的[Windows驱动开发](三)基础知识——驱动例程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [Windows驱动开发](二)基础知识
- 下一篇: [Windows驱动开发](四)内存管理