驱动中链表的使用

DDK中定义了LIST_ENTRY双向链表结构,这样把数据和链表分开的定义方法,降低了耦合度。

typedef struct LIST ENTRY {
PLIST
ENTRY Flink;
PLIST_ ENTRY Blink;
) LIST ENTRY *PLIST_ ENTRY;
链表的使用
在自己定义的结构体中包含已经定义好的LIST_ENTRY链表.

typedef struct _MYDATASTRUCT 
{
	 // List Entry需要作为MYDATASTRUCT结构体的一部分
	 LIST_ENTRY ListEntry;
	//下面是自定义的数据
	ULONG number;

}MYDATASTRUCT,*PMYDATASTRUCT;

链表的初始化
InitializeListHead(PLIST_ ENTRY pListHead)
参数为链表头的地址,该函数的作用就是把Flink和Blink都设置为链表头的地址。

判断链表是否为空
IsListEntry(PLIST_ ENTRY pListHead)
该函数的原理就是判断链表的Flink和Blink的值一样,如果不一样 说明链表不为空。

链表的插入

void InsertHeadtist (PLIST_ ENTRY pListHead,PLIST_ ENTRY Entry);
参数1:双向链表头部的指针
参数2:要插入数据的链表节点指针

在这里插入图片描述
尾部插入
void InsertTailtist (PLIST_ ENTRY pListHead,PLIST_ ENTRY Entry);
参数1:双向链表头部的指针
参数2:要插入数据的链表节点指针
在这里插入图片描述

链表的删除
可以使用MiProcessLoadEntry来进行链表的删除(第三个参数为FALSE),更加的安全.

RemoveHeadList(&pListHead);
参数:链表头的指针
该函数返回值为用户自定义数据的指针,在LIST_ENTRY是自定义结构第一个元素的情况下。
如果不是,那么就需要地址减去到结构头的大小。

DDK定义CONTAINING_RECORD宏,实现了无论LIST_ENTRY是否是自定义结构的第一个元素都能返回自定义数据开头的指针。
参数1:自定义数据的LIST_ENTRY地址
参数2:结构体的名字
参数3:结构体中的LIST_ENTRY的名字


#include<ntddk.h>

typedef struct _MYDATASTRUCT
{
	//下面是自定义的数据
	ULONG x;
	ULONG y;
	// 这里把链表定义在结构体非头部位置,事实上windows内核里面的很多结构都是这样定义的
	LIST_ENTRY ListEntry;


}MYDATASTRUCT, *PMYDATASTRUCT;

void DriverUnload(PDRIVER_OBJECT pDriverObject)
{
	DbgPrint("unload");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pReg)
{
	//定义链表头
	LIST_ENTRY ListHead;
	ULONG i = 0;
	//自定义的结构指针,用来指向分配后的内存
	PMYDATASTRUCT pMyData;
	pDriverObject->DriverUnload = DriverUnload;
	//初始化链表
	InitializeListHead(&ListHead);

	for (i; i<10; i++)
	{
		pMyData = (PMYDATASTRUCT)ExAllocatePool(PagedPool, sizeof(MYDATASTRUCT));
		if (!pMyData)
		{
			DbgPrint("申请内存失败\n");
			return STATUS_MEMORY_NOT_ALLOCATED;
		}
		pMyData->x = i;
		pMyData->y = i;
		//使用头部插入方式
		InsertHeadList(&ListHead, &pMyData->ListEntry);
	}

	while (!IsListEmpty(&ListHead))
	{
		//如果链表头有数据,就移除链表头并获得头部的数据指针,使用了CONTAINING_RECORD宏。
		PMYDATASTRUCT	pList = (PMYDATASTRUCT)CONTAINING_RECORD((PMYDATASTRUCT)RemoveHeadList(&ListHead), MYDATASTRUCT, ListEntry);
		DbgPrint("list in struct=%x\n",pList->y);
		ExFreePool(pList);
	}

	return STATUS_SUCCESS;
}


通过结构体中的链表地址获得结构体开始地址

一般来说直接减去结构体中链表的偏移即可,DDK提供了一个宏CONTAINING_RECORD来实现这个操作。

该宏一共有3个参数:
参数1:结构体中这个链表的地址
参数2:结构体名字
参数3:结构体中包含的链表字段
例如:

//结构体
typedef struct _IRP_ENTRY
{
	PIRP pIRP;
	LIST_ENTRY ListEntry;
}IRP_ENTRY, *PIRP_ENTRY;

CONTAINING_RECORD(	pList,链表地址
					IRP_ENTRY,  //结构体名
					ListEntry);	//链表字段名
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值