以下內容全部來自《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 ...