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)的更多相关文章

  1. [内核驱动] 链表LIST_ENTRY的操作(转)

    转载:https://www.cnblogs.com/forlina/archive/2011/08/11/2134610.html 转载:http://www.xuebuyuan.com/15443 ...

  2. 梦织未来Windows驱动编程 第05课 小结(读取另一驱动,遍历所有驱动)

    读取另一驱动 驱动通过"\\Driver\\XueTr"获取到了XueTr工具的驱动,并Hook了XueTr驱动的分发函数. 具体的驱动代码如下: //FilterDriver.c ...

  3. 驱动开发:内核枚举进程与线程ObCall回调

    在笔者上一篇文章<驱动开发:内核枚举Registry注册表回调>中我们通过特征码定位实现了对注册表回调的枚举,本篇文章LyShark将教大家如何枚举系统中的ProcessObCall进程回 ...

  4. usb驱动开发22之驱动生命线

    我们总是很喜欢高潮,不是吗?那就好好对待她哦.我们来看一下linux中的高潮部分设备是怎么从Address进入Configured的. usb_set_configuration函数的代码就不贴了,可 ...

  5. usb驱动开发18之设备生命线

    现在已经使用GET_DESCRIPTOR请求取到了包含一个配置里所有相关描述符内容的一堆数据,这些数据是raw的,即原始的,所有数据不管是配置描述符.接口描述符还是端点描述符都挤在一起,所以得想办法将 ...

  6. usb驱动开发16之设备生命线

    回到struct usb_hcd,继续努力的往下看. kref,usb主机控制器的引用计数.struct usb_hcd也有自己专用的引用计数函数,看hcd.c文件. static void hcd_ ...

  7. usb驱动开发10之usb_device_match

    在第五节我们说过会专门分析函数usb_device_match,以体现模型的重要性.同时,我们还是要守信用的. 再贴一遍代码,看代码就要不厌其烦. static int usb_device_matc ...

  8. usb驱动开发4之总线设备驱动模型

    在上文说usb_init函数,却给我们留下了很多岔路口.这次就来好好聊聊关于总线设备驱动模型.这节只讲理论,不讲其中的函数方法,关于函数方法使用参考其他资料. 总线.设备.驱动对应内核结构体分别为bu ...

  9. linux设备驱动模型

    尽管LDD3中说对多数程序员掌握设备驱动模型不是必要的,但对于嵌入式Linux的底层程序员而言,对设备驱动模型的学习非常重要. Linux设备模型的目的:为内核建立一个统一的设备模型,从而又一个对系统 ...

随机推荐

  1. Java Config for WebProject

    1.Java EE vs Java SE They are just official SDK,when using IDE,it's ok to just install jdk/jre. &quo ...

  2. Hypergeometric distribution

    How TermFinder calculates P-values Readme: MGI GO Term Finder The GoTermFinder attempts to determine ...

  3. Linux上配置bond

    http://blog.csdn.net/wuweilong/article/details/39720571 一,配置设定文件[root@woo ~]# vi /etc/sysconfig/netw ...

  4. windows如何简单安装mongodb

    windows如何安装mongodb 步骤: 1.下载地址 2.选择zip(解压版本) 3.压缩文件解压到  /D:盘 4.在 D:盘  下建一个 data文件夹,data下建 db文件夹:   D: ...

  5. linux中用户和用户组

    一.用户和组原理 一个用户可以属于多个组,一个组有多个用户 在Linux中操作系统必须依赖组和用户进行管理 二.与用户和组相关的配置文件 1.组相关配置文件 1)/etc/group :管理用户组信息 ...

  6. Composer 的学习

    一.Composer简介 Composer 是PHP用来管理依赖关系的工具. 使用 composer 的必要前提有: 1.PHP版本要高于PHP5.3.2 2.PHP支持OpenSSL扩展 3.安装有 ...

  7. MySQL事务(三)

    一.事务(Innodb锁)的隔离级别概述 并发事务带来的问题: 更新丢失(lost update):当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会 ...

  8. 『PyTorch』第二弹_张量

    参考:http://www.jianshu.com/p/5ae644748f21# 几个数学概念: 标量(Scalar)是只有大小,没有方向的量,如1,2,3等 向量(Vector)是有大小和方向的量 ...

  9. Spring boot(六)优雅使用mybatis

    orm框架的本质是简化编程中操作数据库的编码,发展到现在基本上就剩两家了,一个是宣称可以不用写一句SQL的hibernate,一个是可以灵活调试动态sql的mybatis,两者各有特点,在企业级系统开 ...

  10. leetcode-algorithms-30 Substring with Concatenation of All Words

    leetcode-algorithms-30 Substring with Concatenation of All Words You are given a string, s, and a li ...