驱动开发中经常遇到的链表,主要是双向循环链表;LIST_ENTRY的结构定义如下:
(2)一个LIST_ENTRY类型的链表头;使用链表头和以下宏来控制链表
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink; // 指向下一个节点
struct _LIST_ENTRY *Blink; // 指向前一个节点
} LIST_ENTRY, *PLIST_ENTRY;
(1)定义链表的节点,在节点中添加LIST_ENTRY类型的变量(不一定放在第一位,但通常是这样)
(2)一个LIST_ENTRY类型的链表头;使用链表头和以下宏来控制链表
InitializeListHead,初始化链表头
IsListEmpty,判断链表是否为空
InsertHeadList,从链表头部插入节点
InsertTailList,从链表尾部插入节点
RemoveHeadList,从链表头部删除节点
RemoveTailList,从链表尾部删除节点
CONTAINING_RECORD,根据结构体中的某成员的指针来推算出该结构体的指针
代码示例:
#ifdef __cplusplus
extern "C" {
#endif
#include <ntddk.h>
#include <string.h>
#ifdef __cplusplus
}; // extern "C"
#endif
#include "ListEntry.h"
VOID LISTENTRY_DriverUnload(
IN PDRIVER_OBJECT DriverObject
)
{
KdPrint(("LISTENTRY_DriverUnload...."));
}
typedef struct _DATA{
LIST_ENTRY listEntry;
ULONG uData;
}DATA,*PDATA;
VOID listTest( )
{
LIST_ENTRY listHead;
PDATA pData= NULL;
InitializeListHead(&listHead);
for (int i=0;i<10;i++)
{
pData = (PDATA)ExAllocatePool(NonPagedPool,sizeof(DATA));
pData->uData = i;
InsertTailList(&listHead,&(pData->listEntry));
KdPrint(("Insert Data:%d ",pData->uData));
}
KdPrint(("\n\n",pData->uData));
while (!IsListEmpty(&listHead))
{
PLIST_ENTRY pEntry = RemoveTailList(&listHead);
//CONTAINING_RECORD 根据结构体中的某成员的指针来推算出该结构体的指针
/*
#define CONTAINING_RECORD(address, type, field) ((type *)( (PCHAR)(address) - (ULONG_PTR)(&((type *)0)->field)))
address:结构体某变量地址
type:结构体类型
field:在结构体中对应的变量
*/
((DATA *)( (PCHAR)(pEntry) - (ULONG_PTR)(&((DATA *)0)->listEntry)))
pData = CONTAINING_RECORD(pEntry,DATA,listEntry);
KdPrint(("ReomveData:%d ",pData->uData));
ExFreePool(pData);
pData = NULL;
}
}
#ifdef __cplusplus
extern "C" {
#endif
NTSTATUS DriverEntry(
IN OUT PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
PDEVICE_OBJECT pdoDeviceObj = 0;
NTSTATUS status = STATUS_UNSUCCESSFUL;
KdPrint(("DriverEntry...."));
listTest();
DriverObject->DriverUnload = LISTENTRY_DriverUnload;
return STATUS_SUCCESS;
}
#ifdef __cplusplus
}; // extern "C"
#endif