驱动链表(LIST_ENTRY)
DDK提供了两种链表的数据结构,双向链表和单向链表,其定义如下:
typedef struct _LIST_ENTRY
{
struct _LIST_ENTRY *Flink;
struct _LIST_ENTRY *Blink;
} LIST_ENTRY,*PLIST_ENTRY;
typedef struct _SINGLE_LIST_ENTRY {
struct _SINGLE_LIST_ENTRY *Next;
} SINGLE_LIST_ENTRY, *PSINGLE_LIST_ENTRY;
一.双向链表LIST_ENTRY
这个结构不能直接存进我们要的数据,如果要把我们的数据存进链表的结构里,需要重新定义一个结构体,结构体里必须要包括一个LIST_ENTRY类型的成员,这个成员可以放在结构体里的任何位置,如:
typedef struct _list
{
LIST_ENTRY List;
ULONG data;
} Node,*PNode;
或者:
typedef struct _list
{
ULONG data;
LIST_ENTRY List;
} Node,*PNode;
在使用链表时要定义一个链表头并初始化,其类型为LIST_ENTRY,
1.初始化链表函数为InitializeListHead(PLIST_ENTRY pListHeader);
2.插入链表函数
InsertHeadList(
PLIST_ENTRY pListHeader, //链头
PLIST_ENTRY MyListEntry); //结构体中的LIST_ENTRY类型的成员变量地址
这个函数是在链表的开头插入一个结点,第一个参数是链头,第二个参数也是一个PLIST_ENTRY类型,是我们自己定义的结构体中的LIST_ENTRY类型的成员变量地址。类似的还有从尾部插入链表函数InsertTailList,参数与InsertHeadList一致。
3.从链表删除结点
函数RemoveTailList(PLIST_ENTRY pListHeader)把链表的最后的结点删除,返回删除的结点的指针。
函数RemoveHeadList(PLIST_ENTRY pListHeader)把链表的第一个结点删除,返回删除的结点的指针。
一.单向链表SINGLE_LIST_ENTRY
1.初始化链表函数为InitializeListHead(PLIST_ENTRY pListHeader),与双向链表相同。
2.插入链表函数
FORCEINLINE
VOID
PushEntryList( //从头部插入,成为第一个结点
_Inout_ PSINGLE_LIST_ENTRY ListHead, //链头
_Inout_ __drv_aliasesMem PSINGLE_LIST_ENTRY Entry //结构体中的LIST_ENTRY类型的成员变量地址
)
{
Entry->Next = ListHead->Next;
ListHead->Next = Entry;
return;
}
3.从链表删除结点
FORCEINLINE
PSINGLE_LIST_ENTRY
PopEntryList( //从链表头下一个删除节点,删除第一个结点
_Inout_ PSINGLE_LIST_ENTRY ListHead //链头
)
{
PSINGLE_LIST_ENTRY FirstEntry;
FirstEntry = ListHead->Next;
if (FirstEntry != NULL) {
ListHead->Next = FirstEntry->Next;
}
return FirstEntry;
}
//bp ListEntry!DriverEntry NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
{
NTSTATUS Status = STATUS_SUCCESS;
PDEVICE_OBJECT DeviceObject = NULL;
DriverObject->DriverUnload = DriverUnload; SeListEntry();
SeSingleListEntry();
return Status;
}
VOID SeListEntry()
{
LIST_ENTRY ListHead;
PITEM Item = NULL;
ULONG i = 0;
//初始化链表
InitializeListHead(&ListHead);
for (i = 0; i < 10; i++)
{
Item = (PITEM)
ExAllocatePool(PagedPool, sizeof(ITEM));
Item->ItemData = i;
InsertHeadList(&ListHead, &Item->u.ListEntry);
}
while (!IsListEmpty(&ListHead))
{
PLIST_ENTRY ListEntry = RemoveTailList(&ListHead); KdPrint(("%d\n", ((PITEM)ListEntry)->ItemData));
ExFreePool((PITEM)ListEntry);
}
}
VOID SeSingleListEntry()
{
SINGLE_LIST_ENTRY ListHead;
PITEM Item = NULL;
ULONG i = 0;
//初始化链表
InitializeListHead(&ListHead);
for (i = 0; i < 10; i++)
{
Item = (PITEM)
ExAllocatePool(PagedPool, sizeof(ITEM));
Item->ItemData = i;
PushEntryList(&ListHead, &Item->u.SingleListEntry);
}
while (!IsListEmpty(&ListHead))
{
PSINGLE_LIST_ENTRY ListEntry = PopEntryList(&ListHead); KdPrint(("%d\n", ((PITEM)ListEntry)->ItemData));
ExFreePool((PITEM)ListEntry);
}
} VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
DbgPrint("DriverUnload()\r\n");
}
驱动链表(LIST_ENTRY)的更多相关文章
- [内核驱动] 链表LIST_ENTRY的操作(转)
转载:https://www.cnblogs.com/forlina/archive/2011/08/11/2134610.html 转载:http://www.xuebuyuan.com/15443 ...
- 梦织未来Windows驱动编程 第05课 小结(读取另一驱动,遍历所有驱动)
读取另一驱动 驱动通过"\\Driver\\XueTr"获取到了XueTr工具的驱动,并Hook了XueTr驱动的分发函数. 具体的驱动代码如下: //FilterDriver.c ...
- 驱动开发:内核枚举进程与线程ObCall回调
在笔者上一篇文章<驱动开发:内核枚举Registry注册表回调>中我们通过特征码定位实现了对注册表回调的枚举,本篇文章LyShark将教大家如何枚举系统中的ProcessObCall进程回 ...
- usb驱动开发22之驱动生命线
我们总是很喜欢高潮,不是吗?那就好好对待她哦.我们来看一下linux中的高潮部分设备是怎么从Address进入Configured的. usb_set_configuration函数的代码就不贴了,可 ...
- usb驱动开发18之设备生命线
现在已经使用GET_DESCRIPTOR请求取到了包含一个配置里所有相关描述符内容的一堆数据,这些数据是raw的,即原始的,所有数据不管是配置描述符.接口描述符还是端点描述符都挤在一起,所以得想办法将 ...
- usb驱动开发16之设备生命线
回到struct usb_hcd,继续努力的往下看. kref,usb主机控制器的引用计数.struct usb_hcd也有自己专用的引用计数函数,看hcd.c文件. static void hcd_ ...
- usb驱动开发10之usb_device_match
在第五节我们说过会专门分析函数usb_device_match,以体现模型的重要性.同时,我们还是要守信用的. 再贴一遍代码,看代码就要不厌其烦. static int usb_device_matc ...
- usb驱动开发4之总线设备驱动模型
在上文说usb_init函数,却给我们留下了很多岔路口.这次就来好好聊聊关于总线设备驱动模型.这节只讲理论,不讲其中的函数方法,关于函数方法使用参考其他资料. 总线.设备.驱动对应内核结构体分别为bu ...
- linux设备驱动模型
尽管LDD3中说对多数程序员掌握设备驱动模型不是必要的,但对于嵌入式Linux的底层程序员而言,对设备驱动模型的学习非常重要. Linux设备模型的目的:为内核建立一个统一的设备模型,从而又一个对系统 ...
随机推荐
- Spring Boot 之注解@Component @ConfigurationProperties(prefix = "sms") 使用@ConfigurationProperties读取yml配置
从spring-boot开始,已经支持yml文件形式的配置,@ConfigurationProperties的大致作用就是通过它可以把properties或者yml配置直接转成对象 @Componen ...
- p1468 Party Lamps
就是模拟.同一个开关按2下相当于没按,那么,如果一共按0下,就是没按,按1下就是4个开关的1个,按2下可能相当于实际按了0下或按2下,按3下实际按了1下或3下,之后如果是奇数,相当于按1或3下,偶数相 ...
- webpack添加热更新
之前的wbepack一直没有加上热更新,这是一种遗憾,今天终于加上去了,看不懂我博客的可以看这篇文章:http://blog.csdn.net/hyy1115/article/details/5302 ...
- 51Nod 1810 连续区间
https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1810 题目给出一个1~n的排列,问有多少连续区间.连续区间的定义为区间 ...
- 架构探险笔记3-搭建轻量级Java web框架
MVC(Model-View-Controller,模型-视图-控制器)是一种常见的设计模式,可以使用这个模式将应用程序进行解耦. 上一章我们使用Servlet来充当MVC模式中的Controller ...
- CF数据结构练习
1. CF 438D The Child and Sequence 大意: n元素序列, m个操作: 1,询问区间和. 2,区间对m取模. 3,单点修改 维护最大值, 取模时暴力对所有>m的数取 ...
- Leetcode 869. 重新排序得到 2 的幂
869. 重新排序得到 2 的幂 显示英文描述 我的提交返回竞赛 用户通过次数102 用户尝试次数134 通过次数103 提交次数296 题目难度Medium 从正整数 N 开始,我们按任何顺序 ...
- 创建型模式篇(单例模式Single Pattern)
一.单例模式(Singleton Pattern) 单例模式要求一个类只能有一个实例,并且提供了一个全局的访问点. 比如说,中国主席的职位是Singleton,法律规定主席选举,任何时间只能有一个主席 ...
- linux上udev的配置(转载)
udev配置文件主要的udev配置文件是/etc/udev/udev.conf.这个文件通常很短,他可能只是包含几行#开头的注释,然后有几行选项:udev_rules=”/etc/udev/rules ...
- [LeetCode] 94. Binary Tree Inorder Traversal(二叉树的中序遍历) ☆☆☆
二叉树遍历(前序.中序.后序.层次.深度优先.广度优先遍历) 描述 解析 递归方案 很简单,先左孩子,输出根,再右孩子. 非递归方案 因为访问左孩子后要访问右孩子,所以需要栈这样的数据结构. 1.指针 ...