在驅動程式開發中, 經常使用這種資料結構. DDK 為使用者提供兩種鏈表的資料結構, 簡化了對鏈表的操作. 鏈表中可以記錄將整型, 浮點, 字元型或者程式員自訂的資料結構. 鏈表透過指標將這些資料結構組成一條"鏈", 鏈中的每個元素對應著記錄的資料. 對於單向鏈表, 每個元素有一個 Next 指標指向下一個元素. 對於雙向鏈表, 每個元素有兩個指標 : BLINK 指標指向前一個元素 ; FLINK 指向下一個元素. 這裡介紹主要以使用雙向鏈表為主, 單向鏈表操做類似.
鏈表結構 :
DDK 提供了標準的雙向鏈表, 雙向鏈表可以將鏈表形成一個環. BLINK 指標指向前一個元素, FLINK 指標指向下一個元素 :
以下是 DDK 提供的雙向鏈表的資料結構 :
- typedef struct _LIST_ENTRY {
- struct _LIST_ENTRY *Flink;
- struct _LIST_ENTRY *Blink;
- } LIST_ENTRY, *PLIST_ENTRY;
每個雙向鏈表都是以一個鏈表頭做為鏈表的第一個元素. 初次使用鏈表頭需要進行初始化. 主要將鏈表頭的 Flink 和 Blink 兩個指標都指向自己. 這意味著鏈表頭所代表的鏈是空鏈. 而初始化鏈表頭用 InitializeListHead 巨集實做.
如何判斷鏈表是否為空, 可以透過上面定義來判斷鏈表頭的 Flink 和 Blink 是否指向自己. DDK 為程式設計師提供了一個巨集簡化這種檢查, 這就是 IsListEmpty.
程式設計師需要自己定義鏈表中每個元素的資料類型, 並將 LIST_ENTRY 結構做為自訂結構的一個子域. LIST_ENTRY 的作用是將自訂的資料結構串成一個鏈表.
- 從首部插入鏈表
對鏈表的插入有兩種方式, 一種是在鏈表的頭部插入, 一種是在尾部插入. 在頭部插入鏈表使用語句 InsertHeadList, 用法如下 :
InsertHeadList(&head, &mydata->ListEntry);
其中 head 是 LIST_ENTRY 結構的鏈表頭, mydata 是使用者定義的資料結構, 而它的子Field:ListEntry 就是 LIST_ENTRY 的資料結構. 假設鏈表中已經有一個元素 Entry1, 如下圖. 現在將另一個元素 Entry2 插入鏈表, 使用 InsertHeadList 插入, 則可得到下面第二個圖 :
- 從尾部插入鏈表
另一種插入方法是在鏈表的尾部進行插入. 在尾部插入鏈表使用語句 InsertTailList, 用法如下 :
InsertTailList(&head, &mydata->ListEntry);
其中 head 是 LIST_ENTRY 結構的鏈表頭, mydata 是使用者定義的資料結構, 而它的 Field:ListEntry 是 LIST_ENTRY 資料結構. 假設鏈表中已經有一個元素 Entry1, 如下圖一所示, 現在將另一個 Entry2 使用 InsertTailList 插入鏈表, 則可得下圖二 :
- 從鏈表刪除
和插入鏈表一樣, 刪除也有兩種對應方式. 一種是從鏈表頭刪除, 一種是從鏈表尾刪除. 分別對應 RemoveHeadList 和 RemoveTailList 函式. 其原型如下 :
而使用方法如下 :
PLIST_ENTRY pEntry = RemoveHeadList(&head);
及
PLIST_ENTRY pEntry = RemoveTailList(&head);
其中 head 是鏈表頭, pEntry 是從鏈表刪除下來的元素中的 ListEntry. 這裡有一個問題就是如何從 pEntry 得到使用者自定資料結構的指標. 這裡有兩種情況 :
(1) 自定義資料結構的第一個欄位是 LIST_ENTRY 時, 如 :
- typedef struct _MYDATASTRUCT {
- LIST_ENTRY ListEntry;
- ULONG x;
- ULONG y;
- } MYDATASTRUCTURE, *PMYDATASTRUCTURE;
- PLIST_ENTRY pEntry = RemoveHeadList(&head);
- PMYDATASTRUCTURE pMyData = (PMYDATASTRUCTURE) pEntry;
- typedef struct _MYDATASTRUCT2 {
- ULONG x;
- ULONG y;
- LIST_ENTRY ListEntry;
- } MYDATASTRUCTURE2, *PMYDATASTRUCTURE2;
- PLIST_ENTRY pEntry = RemoveHeadList(&head);
- PMYDATASTRUCTURE2 pMyData = (PMYDATASTRUCTURE2) pEntry; // 發生錯誤
- PLIST_ENTRY pEntry = RemoveHeadList(&head);
- PIRP pIrp = CONTAINING_RECORD(pEntry, MYDATASTRUCTURE2, ListEntry);
實驗 :
在介紹完記易體分配和鏈表操作後, 下面進行實驗. 實驗目的在於熟悉驅動程式中, 初始化鏈表, 自定義鏈表資料結構. 而該結構包含一個整型數位, 這個實驗演示了鏈表進行插入, 刪除等操作, 主要代碼如下 :
請將上述程式碼放到 HelloDDK 中的 DriverEntry 中. 驅動載入後可以看對應 log 資訊如下圖 :
沒有留言:
張貼留言