一,、Overview
KDriver類提供了一個設備驅動程序的框架。這個類的職責包括初始化驅動程序,,把I/O請求傳遞給它們的目標設備對象,。 KDriver是一個抽象類,驅動編寫人員必須寫一個新的類來繼承它,。新的子類必須重寫DriverEntry函數(shù),,這是當系統(tǒng)載入驅動程序時框架要調用的函數(shù)。這個派生類會有一個構造函數(shù),,但是構造函數(shù)不允許有參數(shù),。一般來說,,最好不要寫這么一個構造函數(shù)。把一切的初始化工作放在DriverEntry函數(shù)里來進行,。對于任何給定的驅動,,只能有一個KDriver類的實例存在,而且這個實例是框架自動創(chuàng)建的,。任何調用者可以通過調用DriverInstance靜態(tài)函數(shù)來獲得一個指向這個唯一實例的指針,。 驅動編寫人員必須做的另一件事情是通知框架:哪個類作為驅動框架來提供服務??蚣芴峁┝硕x了一個宏定義DECLARE_DRIVER_CLASS來實現(xiàn)這個事情,。任何一個驅動程序里都必須調用一次且只能調用一次這個宏,一般是在擁有DriverEntry函數(shù)的組件里,。這個宏必須放在任何函數(shù)之外,,因為它事實上聲明一個可以被框架調用的函數(shù)。宏的參數(shù)應該是繼承了KDriver類的那個類的名字,。 除了DriverEntry,,KDriver還有其他兩個成員函數(shù)來做初始化的工作:RequestReinitialization() 和 Reinitialize()。一個驅動程序在DriverEntry函數(shù)里調用RequestReinitialization()函數(shù)來指示系統(tǒng)調用 Reinitialize()函數(shù),,作為第二級初始化,。而Reinitialize()函數(shù)是一個可被重寫的虛函數(shù),。 如果想要系統(tǒng)具有卸載(Unload)驅動的功能,,就要在function.h文件里做一個聲明:#define DRIVER_FUNCTION_UNLOAD。這是虛函數(shù)Unload()的得到聲明,。這個函數(shù)在基類中的實現(xiàn)代碼調用了DeleteDevices() 函數(shù)來為這個驅動程序創(chuàng)建的每個設備調用析構函數(shù),。 其他成員函數(shù)對驅動程序創(chuàng)建的設備進行管理。GetDeviceListHead()函數(shù)取得驅動創(chuàng)建的一系列設備對象中的第一個(head),。DeleteDevices()遍歷列表,,并為每一個設備對象調用析構函數(shù)。IsDevicePresent()使驅動程序確認設備是否已經(jīng)被刪除,。 盡管通常情況下框架會將I/O請求直接派遣給目標設備對象,,KDriver還是保留了一個特性:可以派生一個成員函數(shù)在I/O請求被派遣給設備對象之前對它進行檢測或預處理。這個特性通過調用EnableDispatchFilter()函數(shù)來啟用,這會使所有的I/O請求被重寫的DispatchFilter()函數(shù)處理后再派遣,。另外,,要啟用這個特性,還必須在function.h文件中聲明:#define DRIVER_FUNCTION_DISPATCH_FILTERING,。 總結:不要在KDriver的子類中定義構造函數(shù)和析構函數(shù),,把初始化工作放在DriverEntry函數(shù)里,清理工作放在Unload函數(shù)里,。 二,、Member Functions 1,、DriverEntry (Initializes the driver) 框架自動調用這個函數(shù)進行初始化工作,所有繼承KDriver的子類必須重寫這個函數(shù),。 【函數(shù)原型】 NTSTATUS DriverEntry( PUNICODE_STRING RegistryPath ); 【Parameters】 RegistryPath 系統(tǒng)儲存驅動信息的注冊表路徑 【Returns】 返回值用來說明驅動的初始化工作是否成功,。除了STATUS_SUCCESS之外的返回值將阻止系統(tǒng)加載這個驅動程序。如果這個函數(shù)里調用了 RequestReinitialization函數(shù),,那么不太可能返回一個STATUS_SUCCESS之外的值,。
【Comments】 DriverEntry的職責使初始化驅動程序。具體工作有三點:(1)從注冊表中提取參數(shù)(2)保告和分配資源的使用(3)創(chuàng)建設備對象,。如果可能的話,,系統(tǒng)會把驅動的參數(shù)儲存在注冊表中相應的驅動目錄下的Parameters鍵里。KRegistryKey類封裝了操作注冊表的方法,。 資源使用情況報告有助于沖突檢測,。在兩個驅動同時要求分配資源時,這個報告將會成為系統(tǒng)有限給哪個驅動分配資源的一個依據(jù),。關于更多的報告和分配資源的細節(jié),,可以參看KResourceRequest和KResourceAssignment類中的描述。 這個函數(shù)在PASSIVE_LEVEL級別上運行,。 2,、AddDevice (Plug and Play entry point called to configure new device object (WDM only))
當即插即用子系統(tǒng)檢測倒該驅動對應的設備時,框架會自用調用這個函數(shù),。 前提是必須在function.h文件里聲明#define DRIVER_FUNCTION_ADD_DEVICE 【函數(shù)原型】 NTSTATUS AddDevice( PDEVICE_OBJECT PnPDeviceObject ); 【Parameters】 PnPDeviceObject 一個指向系統(tǒng)創(chuàng)建的設備對象的指針,,來表示檢測到的設備。 【Returns】 成功就返回TRUE,。 【Comments】 這個函數(shù)里進行什么操作依賴于驅動的類型,。迷你驅動(minidriver)由于在類驅動(class driver)或總線驅動(bus driver)的上層,一般會創(chuàng)建一個設備對象并把它壓到設備堆棧里,,這個堆棧是物理設備所屬的總線所擁有的,。 對大多數(shù)驅動,參數(shù)PnPDeviceObject代表物理設備對象(PDO),。PDO是物理設備在在操作系統(tǒng)中的設備表現(xiàn)形式,。系統(tǒng)用對象來模仿對設備的即插即用操作,比如使設備開始(starting),、停止(stopping),、把設備刪除(removing)、減低電源消耗(powering down),。 AddDevice經(jīng)常創(chuàng)建一個新的設備對象叫做功能設備對象(FDO),。FDO的目的是使應用程序和更高級別上的驅動程序能夠通過PDO控制設備。PDO是物理設備在驅動程序里的表現(xiàn)形式,。因此,,對于同樣的物理設備有兩種設備對象來表示:PDO是為了系統(tǒng)的使用,,F(xiàn)DO是為了驅動的使用。 為了創(chuàng)建FDO,,驅動要創(chuàng)建一個KPnpDevice類的派生類的實例,。KPnpDevice類和KDevice類很相似,但是增加了更強大的處理IRP_MJ_PNP和IRP_MJ_POWER這兩種IRP的功能,。 為了建立一個PDO和FDO之間的聯(lián)系,,AddDevice還經(jīng)常要創(chuàng)建一個KPnpLowerDevice類的實例,或者它的派生類的實例,。這個實例的創(chuàng)建將FDO連接到PDO,,或者連接到最后一個設備,而這個設備連接到了PDO,。然后驅動就可以處理發(fā)給PDO的IRP,。在表示FDO的類的實例中嵌入一個KPnpLowerDevice類或者它的子類的實例,是一個不錯的選擇,。 對于有些類型的迷你驅動,,比如說HID(人機交互設備),這個參數(shù)代表的就是FDO而不是PDO。這是因為類驅動在迷你驅動上設置了鉤子(hooks),鉤住了迷你驅動的AddDevice入口并創(chuàng)建了FDO,。詳細請看KPnpLowerDevice類,。
3、Unload (Clean up)
當系統(tǒng)卸載驅動時框架自動調用這個函數(shù) 前提是必須在function.h文件中聲明 #define DRIVER_FUNCTION_UNLOAD 【函數(shù)原型】 VOID Unload( void ); 【Comments】 這是一個虛函數(shù),。它在基類中的實現(xiàn)代碼中調用了DeleteDevices()函數(shù),。 在function.h文件中聲明 DRIVER_FUNCTION_UNLOAD 使系統(tǒng)可以卸載驅動。但并不強制重寫這個函數(shù),,因為它不是一個純虛函數(shù),。換句話說,如果你定義了DRIVER_FUNCTION_UNLOAD而不重寫函數(shù),,也可以得到默認的卸載行為(刪除設備)。但是如果你有其他的需要,,就要重寫這個函數(shù),。如果重寫了這個函數(shù),它應該調用子類的函數(shù)或者自己調用DeleteDevices()函數(shù),。 Unload函數(shù)應該負責釋放驅動程序中申請的所有對象占用的內存,。 如果驅動在初始化時通過 KResourceRequest 請求了資源,那么在Unload函數(shù)里應該釋放資源,,細節(jié)參看ReleaseResources()函數(shù),。 總之,Unload要確保在卸載驅動時釋放所有的系統(tǒng)對象(包括內存)和未處理的事件(它們會使系統(tǒng)調用驅動程序),。最好的做法是析構頂級對象,,而不是析構它們包含的子級對象,。 這個函數(shù)運行在PASSIVE_LEVEL級別上。 4,、Reinitialize (Secondary initialization operations)
框架調用這個函數(shù)作為先前調用RequestReinitialization函數(shù)的回復,。Reinitialize函數(shù)給當前驅動提供了一個在系統(tǒng)其他驅動都初始化完畢之后再進行二次初始化的機會。 前提是必須在function.h文件中聲明#define DRIVER_FUNCTION_REINITIALIZATION,。 【函數(shù)原型】 VOID Reinitialize( PVOID Context, ULONG Count ); 【Parameters】 Context 是傳給RequestReinitialization函數(shù)的參數(shù),。 Count 指這個函數(shù)調用的次序號,系統(tǒng)每調用一次這個函數(shù)就會給傳進來的這個參數(shù)加1,。 【Comments】 這是一個純虛函數(shù)(pure virtual function),,在繼承KDriver的子類里必須提供這個函數(shù)。 需要前后兩次初始化的驅動程序把這個函數(shù)安排在DriverEntry()函數(shù)中調用了RequestReinitialization函數(shù)以后執(zhí)行,。Context參數(shù)是調用RequestReinitialization函數(shù)時提供的參數(shù)傳遞過來的,。 這個例程可以通過成員變量m_RegistryPath來控制注冊表路徑。 這個例程可以在必須進行額外的初始化時調用RequestReinitialization函數(shù),。 這個函數(shù)運行在PASSIVE_LEVEL級別上,。 5、RequestReinitialization (Request secondary initialization)
這個函數(shù)的作用是:在系統(tǒng)其他驅動都初始化完畢后,,使當前驅動可以執(zhí)行一些額外的初始化代碼,。 前提是必須在function.h文件中聲明#define DRIVER_FUNCTION_REINITIALIZATION。 【函數(shù)原型】 VOID RequestReinitialization( PVOID Context ); 【Parameters】 Context 任意類型的參數(shù),,最終是要傳遞給Reinitialize函數(shù)處理的,,默認是NULL。 【Comments】 一些其行為依賴于其他驅動的驅動程序,,必須有能力在其他程序初始化之前和之后兩次進行初始化,。如果驅動有這樣的需求,它可以在DriverEntry里進行一部分初始化,,然后把另一部分初始化工作安排在后來調用的代碼中,。RequestReinitialization的調用使框架在所有驅動都執(zhí)行完它們的DriverEntry函數(shù)后調用Reinitialize()函數(shù)。 這個函數(shù)需要在DriverEntry函數(shù)里調用,。調用這個函數(shù)的話,,DriverEntry必須返回STATUS_SUCCESS。如果還有額外的初始化操作,,這個函數(shù)還有可能被Reinitialize函數(shù)調用,。 這個函數(shù)只能運行在PASSIVE_LEVEL級別上。 支撐它的系統(tǒng)服務是IoRegisterDriverReinitialization,。 6,、DisableUnload (Disable unloading of this driver)
這個函數(shù)將驅動對象的Unload例程的地址設為NULL。 前提是在function.h文件中聲明#define DRIVER_FUNCTION_UNLOAD 。 【函數(shù)原型】 VOID DisableUnload( void ); 【Comments】 調用這個函數(shù)是為了阻止驅動被卸載,。如果當前的設備狀態(tài)下,,當前驅動程序不能夠被完美的卸載掉,那么調用這個函數(shù)是有用的,。驅動只能等到隨后調用了EnableUnload()函數(shù)后才可以被卸載,。 7、EnableUnload (Enable unloading of this driver)
這個函數(shù)把Unload例程的地址寫回系統(tǒng)驅動對象,。 前提是在function.h文件中聲明#define DRIVER_FUNCTION_UNLOAD ,。 【函數(shù)原型】 VOID EnableUnload( void ); 【Comments】 在調用DisableUnload函數(shù)之后,用這個函數(shù)可以重新允許驅動被卸載,。 8,、GetDeviceListHead (Get head of list of devices created by driver)
獲得一個指向驅動創(chuàng)建的處于設備列表最前面的那個設備對象的指針。 【函數(shù)原型】 KDevice* GetDeviceListHead( void ); 【Returns】 返回一個指向當前驅動創(chuàng)建的KDevice派生類實例的指針,。如果驅動沒有創(chuàng)建任何設備對象,,函數(shù)返回NULL。 【Comments】 驅動創(chuàng)建的設備對象集合被連成一個鏈表,,鏈表最前面的那個(the head of the list)存儲在驅動對象里,。創(chuàng)建的這個鏈表可以使最后被創(chuàng)建的設備處于鏈表的最前端(the head)。 這個函數(shù)可以在任何中斷級別上調用(any IRQL),。 9,、DeleteDevices (Delete all devices created by driver)
函數(shù)刪除驅動創(chuàng)建的所有設備對象。 【函數(shù)原型】 VOID DeleteDevices( void ); 【Comments】 這個函數(shù)遍歷當前驅動的設備列表,,分別調用它們的析構函數(shù)并釋放它們的存儲空間,。需要注意的是KDevice的析構函數(shù)是虛函數(shù),一般來說一個驅動需要通告Unload()函數(shù)來間接調用它,。DeleteDevices也可用于清除一個在DriverEntry里初始化失敗的驅動程序,。 這個函數(shù)運行在PASSIVE_LEVEL級別上。 10,、ReleaseResources (Releases resources claimed by driver)
用于釋放驅動申請的資源,。 【函數(shù)原型】 NTSTATUS ReleaseResources( void ); 【Returns】 返回STATUS_SUCCESS表示資源釋放成功。 【Comments】 這個函數(shù)可以釋放任何通過 KResourceRequest::Submit 為驅動分配的資源,。如果資源是被一個或一些特殊的設備申請的,,你必須調用KDevice::ReleaseResources來釋放。 支撐它的系統(tǒng)調用是IoAssignResources,。 這個函數(shù)只能在PASSIVE_LEVEL級別上調用。 11,、EnableDispatchFilter (Enable dispatch filter)
這個函數(shù)可以使能或制止所有的I/O請求調用一個可重寫的DispatchFilter函數(shù),。 前提是必須在function.h文件中聲明#define DRIVER_FUNCTION_DISPATCH_FILTERING 。 【函數(shù)原型】 VOID EnableDispatchFilter( BOOLEAN enable ); 【Parameters】 enable 為TRUE就允許I/O請求調用DispatchFilter,,為FALSE就不允許,。 【Comments】 默認情況下,,類庫框架將所有派遣者調用(Read, Write, DeviceControl, etc.) 直接對應到目標設備對象的一個成員函數(shù)上。然而,,當派遣過濾器被使能后,,框架會調用虛函數(shù)DispatchFilter。這種做法只有在KDriver的DispatchFilter()函數(shù)被重寫的情況下才有意義,。這種機制允許驅動類(the driver class)在所有的I/O請求被傳遞給KDevice子類之前對它們進行預處理,。 這個函數(shù)可能在任何中斷級別上被調用(any IRQL)。 12,、DispatchFilter (Overridable dispatch entry point)
這是一個可以被重寫的虛函數(shù),,實現(xiàn)對發(fā)送給派遣函數(shù)的I/O請求進行預處理。 【函數(shù)原型】 NTSTATUS DispatchFilter( KDevice* pDevice, KIrp I, NTSTATUS (KDevice::*func)(KIrp) ); 【Parameters】 pDevice I/O請求發(fā)送的目標類KDevice派生類的實例的地址 I I/O請求 func 一般情況下*pDevice里處理該請求的成員函數(shù)的地址 【Returns】 返回值是一種STATUS_xxxx形式的常量,,用來告知I/O管理器I/O請求的當前狀態(tài),。 【Comments】 當派遣過濾器使能后,框架會將所有派遣者調用連到這個KDriver類的可重寫的函數(shù),。這使驅動類(the driver class)可以先于所有KDevice子類的函數(shù)看到I/O請求,,并且可能提供一個單一的處理點來監(jiān)聽驅動接收到的所有I/O請求。 這個函數(shù)負責處理I/O請求,,或者它自己處理,,或者傳遞給設備對象(the device object)提供的函數(shù)處理。它必須返回一個I/O請求的狀態(tài)給I/O管理器,。 它的基類的實現(xiàn)代碼中只是簡單的將I/O請求傳遞給了設備類(the device class): NTSTATUS KDriver::DispatchFilter( KDevice* pDevice, KIrp I, NTSTATUS (KDevice::*func)(KIrp) ) { return (pDevice->*func)(I); } 13,、DriverObject (Accessor to retrieve pointer to system driver object) 獲得一個和KDriver派生類實例一致的系統(tǒng)對象指針。 【函數(shù)原型】 PDRIVER_OBJECT DriverObject( void ); 【Returns】 當系統(tǒng)最初調用驅動時,,返回一個用來傳給框架使用的系統(tǒng)驅動對象指針,。 這個函數(shù)決不會返回NULL。 【Comments】 當調用一個系統(tǒng)服務,,用到系統(tǒng)驅動對象指針時,,就會用到這個函數(shù)。這個指針存儲在KDriver子類的唯一實例中,。 這個函數(shù)可能在任何中斷級別上被調用(any IRQL),。 14、RegistryPath (Accessor to retrieve registry path) 【函數(shù)原型】 PUNICODE_STRING RegistryPath( void ); 【Returns】 返回一個字符串指針來說明系統(tǒng)存儲與當前驅動相關信息的注冊表鍵,。 【Comments】 在系統(tǒng)最初調用驅動時,,這個函數(shù)相當于一個存儲在框架里的成員變量的存取器(accessor)。 這個函數(shù)可能在任何中斷級別上被調用(any IRQL),。但是,,這個字符串一旦被存在分頁內存里,它就只能在PASSIVE_LEVEL級別上被引用。 15,、DriverInstance (Accessor to return pointer to single instance of KDriver)
【函數(shù)原型】 KDriver* DriverInstance( void ); 【Returns】 返回KDriver派生類的唯一實例的地址,。 【Comments】 KDriver類的構造函數(shù)不允許多于一個的派生類實例出現(xiàn)??蚣軙詣觿?chuàng)建這個實例,。這個函數(shù)返回這個實例的地址。如果需要,,我們可以放心的把返回值強制轉換成KDriver派生類的類型,。 這個函數(shù)可能在任何中斷級別上被調用(any IRQL)。 16,、IsDevicePresent (Test if a device still exists or has been deleted)
測試一個設備仍然存在著還是已經(jīng)被刪除,。 【函數(shù)原型】 BOOLEAN IsDevicePresent( PDEVICE_OBJECT pDevice ); 【Parameters】 pDevice 被測試的系統(tǒng)設備對象的地址 【Returns】 如果被測試的設備對象存在于驅動創(chuàng)建的設備列表中,就返回TRUE,;否則返回FALSE,。 【Comments】 參數(shù)是一個系統(tǒng)設備對象的指針。KDevice類重載了一個類型轉換操作符(cast operator)使得編譯器可以自動把一個KDevice派生類的實例轉化成PDEVICE_OBJECT類型,。 一個驅動程序只能測試它自己創(chuàng)建的設備對象,。 這個函數(shù)可能在任何中斷級別上被調用(any IRQL)。 17,、DECLARE_DRIVER_CLASS (Macro to declare the driver class to the framework)
宏定義指明哪個類作為驅動程序框架,。 【宏原型】 DECLARE_DRIVER_CLASS( cpp_classname, driver_class_string ) 【Parameters】 cpp_classname 驅動類的名字(the driver class) driver_class_string 一個沒有終止符的Unicode字符串(null terminated),指明驅動的類,,用來存放系統(tǒng)注冊表資源信息,,可為NULL。 【Comments】 框架創(chuàng)建的每個驅動都指定一個類作為驅動類(the driver class),。這個類繼承自KDriver類,,并且當系統(tǒng)最初調用驅動時,框架會自動創(chuàng)建一個此類的唯一實例,。 框架要求驅動編寫人員用DECLARE_DRIVER_CLASS宏定義來指明驅動類,。這個宏調用必須出現(xiàn)在一個聲明了這個類的源文件的模塊里(通常是一個包含文件in an include file)。這個宏調用必須在所有{}之外,。 這個宏調用實際上定義了一個函數(shù),,動態(tài)分配一塊非分頁內存區(qū)給指定類的實例。這個宏定義假定這個類有一個缺省的構造函數(shù),,由于這個原因,,這個類不能定義一個帶參數(shù)的構造函數(shù)。 本文來自CSDN博客,,轉載請標明出處:http://blog.csdn.net/kaizitop/archive/2008/03/22/2206680.aspx
|
|
來自: wfsy1983 > 《Visual C》