Windows内核编程基础之使用LIST_ENTRY

拼搏现实的明天。 2022-08-04 12:45 378阅读 0赞

LIST_ENTRY 是一个双向链表结构。它总是在使用的时候被插入到已有的数据结构中。Windows内核中使用LIST_ENTRY作为i链表,这个结构随处可见。

看看下面的代码,构建了一个链表,每个节点是又一个文件名和一个文件大小两个数据成员组成的结构。此外有一个FILE_OBJECT指针对象,在驱动中代表一个文件对象。该链表的作用是保存了文件的文件长度和文件名。

  1. typedef struct{
  2. LIST_ENTRY list_Entry,
  3. PFILE_OBJECT file_Object,
  4. UNICODE_STRING file_Name,
  5. LARGE_INTEGER file_Length
  6. }MY_FILE_INFO, *PMY_FILE_INFO;

请注意:这个结构体中多了一个 LIST_ENTRY list_Entry,这样做是为了保证节点插入的位置无所谓。可以将待插入的节点放在任何位置。

LIST_ENTRY 如果是作为链表的头,在使用之前,必须调用InitializeListHead 来初始化。比如像下面这样:

  1. ///----链表头
  2. LIST_ENTRY my_List_Head;
  3. ///---链表头初始化,一般地应该在程序入口处调用一下
  4. void MyFileInfoInit()
  5. {
  6. InitializeListHead(&my_List_Head);
  7. }
  8. ///---节点:文件长度和文件名
  9. typedef struct{
  10. LIST_ENTRY list_Entry,
  11. PFILE_OBJECT file_Object,
  12. UNICODE_STRING file_Name,
  13. LARGE_INTEGER file_Length
  14. }MY_FILE_INFO, *PMY_FILE_INFO;
  15. ///---追加一条信息。也就是增加一个链表节点,请注意file_name是外面分配的
  16. ///---内存由使用者管理,该链表不用管理它
  17. NTSTATUS MyFileInfoAppendNode(
  18. PFILE_OBJECT file_Object,
  19. PUNICODE_STRING file_Name,
  20. PLARGE_INTEGER file_Length )
  21. {
  22. PMY_FILE_INFO my_File_Info = (PMY_FILE_INFO)ExAllocatePoolWithTag(
  23. PagePool, sizeof(MY_FILE_INFO), MEM_TAG);
  24. if (NULL == my_File_Info)
  25. {
  26. return STATUS_INSUFFICIENT_RESOURES;
  27. }
  28. ///----填写数据成员
  29. my_File_Info->file_Object = file_Object;
  30. my_File_Info->file_Name = file_Name;
  31. my_File_Info->file_Length = file_Length;
  32. ///---插入到链表尾,请注意这里没有使用任何锁,所以这个函数不是多线程安全的,
  33. InsertHeadList(&my_List_Head, (PLIST_ENTRY)&my_File_Info);
  34. return STATUS_SUCCESS;
  35. }

上面的代码实现了插入。

下面是的代码,是关于计算LIST_ENTRY结构体的所在节点的地址的一个示例。

  1. for (p = my_List_Head.Flink; p != &my_List_Head.Flink; p = p->Flink)
  2. {
  3. PMY_FILE_INFO elem = CONTAINTING_RECORD(p, MY_FILE_INFO, list_Entry);
  4. }

CONTAINTING_RECORED是一个 WDK中已经定义的宏,作用是通过一个 LIST_ENTRY结构的指针找到这个结构体所在的节点的指针,定义如下:

  1. PCHAR CONTAINING_RECORD(
  2. [in] PCHAR Address,
  3. [in] TYPE Type,
  4. [in] PCHAR Field
  5. );

-————————————————————————————————————-

LIST_ENTRY中的数据成员Flink指向下一个LIST_ENTRY。整个链表的最后一个LIST_ENTRY的Flink不是空, 而是指向头节点(我下面使用红色标记出来啦):

for (p = my_List_Head.Flink; p != &my_List_Head.Flink;p = p->Flink)

///——do something

得到LIST_ENTRY之后,要用CONTAINTING_RECORD来得到链表节点中的数据。

-——-摘自<[天书夜读-从汇编到Windows内核编程]>

也加入了自己对这个概念的理解。

-——————————————-接着秀 一张 模板—————————————————

Center

发表评论

表情:
评论列表 (有 0 条评论,378人围观)

还没有评论,来说两句吧...

相关阅读