1. 程式人生 > >驅動雜記1:對驅動物件,裝置物件,裝置棧的理解

驅動雜記1:對驅動物件,裝置物件,裝置棧的理解

Windows核心採用的是面向物件的程式設計方式,但使用的確是C語言。Windows核心認為許多東西都是“物件”,

比如一個驅動一個檔案一個裝置,“物件”相當於一個基類。

   一個驅動物件代表了一個驅動程式,或者說一個核心模組。驅動物件結構如下:

typedef struct _DRIVER_OBJECT{

//結構的型別和大小

CSHORT Type;

CSHORT Size;

......

//裝置物件,該驅動建立的裝置物件連結串列的開始

PDEVICE_OBJECT DeviceObject;

......

//該核心模組在核心空間中的開始地址和大小

PVOID DriverStart;

ULONG DriverSize;

......

//驅動的名字

UNICODE_STRING DriverName;

......

//FastIO例程

PFAST_IO_DISPATCH FastIoDispath;

......

//StartIO例程

PDRIVER_STARTIO DriverStartIo;

......

//解除安裝例程

PDRIVER_UNLOAD DriverUnload;

......

//普通分發函式,派遣例程

PDRIVER_DISPATH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION+1];

}DRIVER_OBJECT;

在驅動物件中我們可以看到其中有一個裝置物件成員

PDEVICE_OBJECT DeviceObject 它指向一個裝置物件連結串列的第一個物件,因為每個驅動物件可以建立若干個裝置物件,

這些裝置物件正是用連結串列形式連結起來(最後一個裝置物件指向NULL)。裝置物件即DEVICE_OBJECT ,簡稱DO。

在核心中,資訊主要以IRP(I/O請求包)方式傳遞,而裝置物件是唯一可以接受請求的實體。

那麼說到這裡我們再來看看裝置物件這個資料結構。

typedef struct _DEVICE_OBJECT{

......

//該裝置物件所屬的驅動物件

struct  _DRIVER_OBJECT *DriverObject;

//水平層次上的下一個裝置物件,即和該裝置物件同屬一個驅動物件

struct _DEVICE_OBJECT *NextDevice;

//垂直層次的上一個裝置物件,和該裝置物件不屬於同一個驅動物件

struct _DEVICE_OBJECT  *AttachedDevice;

//使用StartIO例程的時時候,此域指向的是當前IRP結構

struct _IRP *CurrentIrp;

ULONG Flags;

//裝置擴充套件物件,又程式設計師自己定義的結構體記錄一些裝置資訊,

//為避免使用全域性變數,可以將全域性變數存在裝置擴充套件裡面

struct _DEVOBJ_EXTENSION *DeviceObjectExtension;

}DEVICE_OBJECT;

從驅動物件和裝置物件的結構定義來看,裝置物件通過struct _DEVICE_OBJECT *NextDevice;

這個域將該驅動中的裝置物件連結起來。

驅動物件可以找到它建立的裝置連結串列頭,而裝置物件可以找到它所屬的驅動物件。

我們看到裝置物件中有一個struct _DEVICE_OBJECT  *AttachedDevice成員,它是跟裝置棧相關聯的。

裝置的建立順序是,先建立底層PDO(物理裝置物件),再建立FDO(功能裝置物件),PDO和FDO之間可能還有一些過濾驅動

(稱為FiDO Filter Device Object)。

每一層裝置物件由不同的驅動物件建立,這些驅動物件共同完成一個物理裝置的驅動任務。

這由下而上生長的裝置便形成了裝置棧。*AttachedDevice就指向上一層的裝置物件,如果為NULL表示已經是最頂層。

從底層向高層可以通過*AttachedDevice來尋找,從高層到底層,裝置物件沒有提供相關子域。這裡就可以通過裝置擴充套件

這個成員來自定義,在_DEVOBJ_EXTENSION 結構中定義一個指向低一層裝置的域。