章四 驅動程式的基本結構(上)

2021-06-10 04:59:00 字數 4472 閱讀 3072

以下內容全部來自《windows驅動開發技術詳解》,作者張帆、史彩成等,屬摘抄型筆記。

///資料結構是電腦程式的核心,i/o管理器定義了一些資料結構,這些資料結構是編寫驅動程式時所必須掌握的。

1.驅動物件結構

每個驅動程式都會有唯一的驅動物件與之對應,驅動物件在驅動載入時,被核心中的i/o管理器載入。

//驅動物件,以結構體的形式存在於核心驅動程式

typedef struct _driver_object

driver_object;

typedef struct _driver_object *pdriver_object;

deviceobject:每個驅動程式會有乙個或多個裝置物件,每個裝置物件都有乙個指標指向下乙個驅動物件,最後乙個裝置物件指向空。裝置物件是由程式設計師自己建立的,而且非作業系統完成;在驅動被解除安裝的時候,遍歷每個裝置物件,並將其刪除

devicename:驅動程式的名字

hardwaredatabase:硬體資料庫鍵名

fastiodispatch:檔案驅動的派遣函式

majorfunction:函式指標陣列,處理irp派遣函式

2.裝置物件結構

每個驅動程式會建立乙個或多個裝置物件,用device_object資料結構表示;每乙個裝置物件都會有乙個指標指向下乙個裝置物件,形成裝置鏈。

typedef struct _device_object 

queue;

ulong alignmentrequirement;

kdevice_queue devicequeue;

kdpc dpc;

ulong activethreadcount;

psecurity_descriptor securitydescriptor;

kevent devicelock;

ushort sectorsize;

ushort spare1;

struct _devobj_extension *deviceobjectextension;

pvoid reserved;

} device_object;

driverobject:指向驅動程式中的驅動物件(同屬於乙個驅動程式的裝置物件指向的是統一驅動物件)

attacheddevice:指向更高一層的裝置物件

flags:32位無符號整形

deviceextension:指向裝置拓展物件

devicetype:裝置型別,當寫虛擬裝置時,型別為file_device_unknown

從下圖可以更清楚裝置物件之間的關係。

3.裝置拓展

每個裝置物件都會指定乙個裝置拓展物件,記錄裝置自己定義的特殊結構體。在驅動程式中,盡量避免使用全域性變數,對全域性變數進行同步會產生較大的代價。最好的方法是將全域性變數存在裝置拓展中。

拓展裝置由程式設計師指定內容和大小,由i/o管理器建立,並儲存在非分頁記憶體中,在驅動程式的標頭檔案中定義。

4.驅動入口函式driverentry

driverentry主要是對驅動程式進行才初始化工作,它是由系統程序所呼叫的。

ntstatus driverentry(in pdriver_object pdriverobject, in punicode_string pregpath)
驅動載入的時候,系統程序system啟動新的執行緒,呼叫執行體元件只能夠的物件管理器,建立乙個驅動物件(結構driver_object),並進行初始化。

而pregpath至存在於函式生命週期內,如果之後需要使用,則需要將其拷貝到安全的地方。

至於unicode_string結構:

typedef struct _unicode_string 

unicode_string;

length:記錄這個字串用多少位元組記錄,如果字串有n個字元,那麼length為2n。

maximumlength:記錄buffer的大小,此結構能記錄的最大位元組數。

buffer:使用的是unicode字串。

在驅動中可以直接列印unicode的資訊,

kdprint(("%s\n", pregpath->buffer));
driverentry返回值為ntstatus的資料,typedef long ntstatus;,被定義為32位長整型。

其中0x000000000--0x7fffffff被認為是正確的狀態;而0x80000000--0xffffffff被認為是錯誤的狀態。

#define nt_success(status) ((ntstatus)(status) >= 0)
nt_success()是乙個判斷返回是否正確的巨集,可以在驅動中嘗試使用。

以下為常用的ntstatus值,除過第乙個是正確數值,其他都代表不同的錯誤。

5.建立裝置物件

在nt式驅動中,建立裝置物件是由iocreatedevice核心函式完成的。

ntstatus

iocreatedevice(

in pdriver_object driverobject,

in ulong deviceextensionsize,

in punicode_string devicename optional,

in device_type devicetype,

in ulong devicecharacteristics,

in boolean exclusive,

out pdevice_object *deviceobject

);

driverobject:每個驅動有唯一驅動物件,確可以有多個裝置物件,此指標指向驅動物件。

devicename:設定裝置物件的名字。

iocreatedevice(pdriverobject, sizeof(pdevice_extension), 

&devname, file_device_unknown,

0, true, &pdeviceobject);

pdeviceobject->flags |= do_buffered_io;

如果在iocreatedevice中沒有指定裝置物件 的名字,i/o管理器會自動分配乙個數字作為裝置的裝置名。如果指定了裝置名,只能被核心程式識別,應用程式無法識別這個裝置,如果需要應用程式能夠識別,還需要通過符號鏈結將裝置名稱暴露。

在建立裝置物件時,裝置型別設定的為file_device_unknown,說明此裝置為常用裝置之外的裝置,一般虛擬裝置常使用此作為裝置型別。

而此後將flags設定為do_buffer_io緩衝區裝置。

6.driverunload例程

nt式驅動,driverunload一般負責刪除在driverentry中建立的裝置物件,並且將裝置物件所關聯的符號鏈結刪除。

#pragma pagecode

void frameunload(in pdriver_object pdriverobject)

}

7.用winobj觀察驅動物件和裝置物件

在微軟的sysinternalssuite工具包中有乙個winobj工具,可以檢視驅動物件、裝置物件、符號鏈結,以及裝置物件的名字。

8.用devicetree觀察驅動物件和裝置物件

ddk自帶的工具包有乙個devicetree,比winobj能獲得更詳細的資訊。

驅動物件頁面,基本上所需的資訊都能看到。

裝置物件頁面

之後可能做各種實驗都要用的這個工具,真是十分給力啊。

驅動程式的基本結構

對於 driverobject 它是驅動的核心部分,每乙個驅動程式,都會對應有乙個驅動物件,每乙個驅動物件都會派生出乙個或對個的裝置物件。也可以說 裝置物件重屬於驅動物件 物件又可以分成3類 1 檔案物件 2 裝置物件 3 驅動物件 裝置物件 deviceobject 它的flags 有幾個域在過濾...

Windows驅動程式的基本結構

以下均為個人見解,如果有誤,敬請指正,謝謝 windows驅動程式的兩個重要的資料結構,驅動裝置物件driver object 裝置物件結構device object,這裡簡略了兩個結構體中的成員,具體的網上都是,自己去搜吧 1 typedef struct driver objectdriver ...

3 1 NT式驅動程式基本結構

標頭檔案 include ntddk.h 函式宣告 void demounload in pdriver object driverobject ntstatus democreateclose in pdevice object deviceobject,in pirp irp ntstatus ...