链表的使用
链表是驱动开发中经常遇到的一个数据结构,主要是双向循环链表;要使用链表,需要用到一个LIST_ENTRY的结构,其定义如下:
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink; // 指向下一个节点
struct _LIST_ENTRY *Blink; // 指向前一个节点
} LIST_ENTRY, *PLIST_ENTRY;
在实际的编程中,我们需要自己定义链表的节点,并把节点的第一个成员设置为LIST_ENTRY类型的变量(不一定放在第一位,但通常是这样);此外,我们还需要一个LIST_ENTRY类型的链表头;其他的就靠下面的函数或者宏来操作了:
InitializeListHead,初始化链表头
IsListEmpty,判断链表是否为空
InsertHeadList,从链表头部插入节点
InsertTailList,从链表尾部插入节点
RemoveHeadList,从链表头部删除节点
RemoveTailList,从链表尾部删除节点
CONTAINING_RECORD,从RemoveHeadList或者RemoveTailList返回的数据获取一个指向删除节点的指针
示例代码:
typedef struct _LIST_NODE
{
LIST_ENTRY ListEntry;
ULONG ulData;
} LIST_NODE, *PLIST_NODE;
VOID LinkListTest()
{
LIST_ENTRY listHead;
PLIST_NODE pListNode = NULL;
ULONG i = 0;
InitializeListHead(&listHead);
DebugPrint(("Begin insert to link list\r\n"));
for (i = 0; i < 10; ++i)
{
pListNode = (PLIST_NODE)
ExAllocatePool(PagedPool, sizeof(LIST_NODE));
pListNode->ulData = i;
InsertHeadList(&listHead, &pListNode->ListEntry);
}
DebugPrint(("Begin remove from link list\r\n"));
while (!IsListEmpty(&listHead))
{
PLIST_ENTRY pEntry = RemoveTailList(&listHead);
pListNode = CONTAINING_RECORD(pEntry,
LIST_NODE,
ListEntry);
DebugPrint(("Delete Node's Value: %d\r\n", pListNode->ulData));
ExFreePool(pListNode);
}
}
代码中用宏表示的:
//LIST_ENTRY的结构表头必须要用InitializeListHead初始化
NPROT_INIT_LIST_HEAD(&Globals.OpenList);