分享
 
 
 

《Undocumented Windows 2000 Secrets》翻译 --- 第七章(1)

王朝system·作者佚名  2006-01-31
窄屏简体版  字體: |||超大  

第七章 Windows 2000的对象管理

翻译:Kendiv( fcczj@263.net )

更新:Thursday, May 19, 2005

声明:转载请注明出处,并保证文章的完整性,本人保留译文的所有权利。

在Windows 2000内部几乎没有什么比它的对象还有趣。如果可以像观看行星表面一样查看操作系统的内存空间,那么对象看起来就像活在行星上的生物。存在着多种类型的对象,有大有小,有复杂的也有简单的,它们通过多种方式互相影响。一个巧妙的、结构化的对象管理机制是Windows 2000的一大特色,不过这一机制几乎没有文档记载。本章将试图带你深入这个庞大而复杂的世界里。很不幸的是,Windows 2000的这一部分是微软保护最好的秘密,许多问题在这里仍然没有答案。不过,我希望本章能成为一个起点,以帮助我们探索“在此之前,还没有人去过的地方”。

Windows 2000对象的结构

本书光盘上有一个很大的头文件名为:w2k_def.h,它位于\src\common\include目录下,它为Windows 2000系统编程者那颗痛苦跳动着的心带来了一丝喜悦。该文件包含多年来深入研究Windows NT/200所获取的常量和类型定义。w2k_def.h可以用于Win32应用程序也可用于内核模式的驱动程序中,它使用条件编译选项来区分不同的构建环境。例如,Win32应用程序无法使用ntdef.h和ntddk.h,因为这俩个文件包含很多内核数据类型的定义。因此,w2k_def.h包含了所有可以在DDK头文件中找到的#define和typedef定义,未文档化的内容需要这些定义。为了在构建内核模式的驱动程序时,出现避免重定义错误,这些定义被放入了#ifdef _USER_MODE_子句中,因此,如果没有定义_USER_MDE_没有定义,编译器将忽略它们。这意味着你必须在包含w2k_def.h的源代码中放入#define _USER_MODE_,这一语句必须位于#include “w2k_def.h”之前,这样才能允许预处理器在Win32应用程序或DLL中处理DDK中的定义。#ifdef _USER_MODE_的#else子句包含少量Windows 2000 DDK头文件中缺失的定义,如SECURITY_DESCRIPTOR和SECURITY_DESCRIPTOR_CONTROL类型。

对象的基本分类

尽管对象是Windows 2000送给我们的一个大礼,但在DDK中你很难发现有关它们的内部结构的有用信息。由ntoskrnl.exe导出的21个用于对象管理的Ob*()函数,仅有6个出现在DDK文档中。这些函数接受一个指向对象的指针作为参数,该指针参数的类型通常为PVOID。如果你在DDK的主要头文件ntdef.h和ntddk.h中查找与对象相关的类型定义,你会发现几乎没有什么有用的信息。有些重要的对象数据类型仅被定义为一个占位符(placeholder)。例如,OBJECT_TYPE结构出现方式为:typedef struct _OBJECT_TYPE *POBJECT_TYPE;这样做只是为了让编译器高兴而以,没有透露出任何有关该对象内部的信息。

无论你在何时遇到对象指针,你都会发现从其线形地址来看,它将常驻内存的结构体划分为两部分:一个对象头和一个对象体。对象指针并没有指向对象自身的基地址,而是指向了对象体,由于紧接着对象头的就是对象体,所以可以给对象指针加上一个负的偏移量来访问对象头。对象体的内部结构完全依赖于对象的类型,对于不同的类型其差别很大。最简单的对象是Event对象,该对象只有一个16字节的对象体。最复杂对象的代表就是进程和线程对象,这俩个对象的大小达到了几百字节。基本上,可以将对象体的类型划分为如下三个主要类别:

1. Dispatcher对象 此类对象位于系统的最底层,在它们的对象体的开始处都有一个共享的公共数据结构----DISPATCHER_HEADER(参见列表7-1)。在它们的对象头中包含一个对象类型ID和对象体的长度(保存在32位的DWORD变量中)。所有Dispatcher对象结构体的名字都以字母K开始,这表示它们是内核(Kernel)对象。DISPATCHER_HEADER结构的存在使得对象是“可等待的(waitable)”。这意味着,此种类型的对象可以被传递给同步函数KeWaitForSingleObject()和KeWaitForMultipleObjects(),Win32函数WaitForSingleObject()和WaitForMultipleObjects()就构建于它们之上。

typedef struct _DISPATCHER_HEADER

{

/*000*/ BYTE Type; // DISP_TYPE_*

/*001*/ BYTE Absolute;

/*002*/ BYTE Size; // number of DWORDs

/*003*/ BYTE Inserted;

/*004*/ LONG SignalState;

/*008*/ LIST_ENTRY WaitListHead;

/*010*/ }

DISPATCHER_HEADER,

* PDISPATCHER_HEADER,

**PPDISPATCHER_HEADER;

#define DISPATCHER_HEADER_ sizeof (DISPATCHER_HEADER)

列表7-1. DISPATCHER_HEADER结构的定义

译注:

可以在本书CD的\src\common目录下的w2k_def.h中找到该结构的定义。

2. I/O系统数据结构(I/O对象) 这类对象是最高层的对象,其对象体的开始位置是一个SHORT类型的成员,该成员用来标识该对象的ID。通常,此ID之后还有一个SHORT或WORD类型的成员用来记录对象体的大小。不过,此类对象并不都遵守这一规则。

3. 其他对象 不属于上述两种对象的对象。

从现在起就要注意Dispatcher对象和I/O对象的类型ID,因为这些ID都是单独维护的,所以有些ID可能会发生重复。表7-1给出了我所知道的Dispatcher对象的类型。出现在表7-1的“C结构”一栏的某些结构体在DDK头文件ntddk.h中有相应的定义。但很不幸的是,很多非常重要的结构,如KPROCESS和KTHREAD都没有官方给出的定义(译注:可以理解,这些结构在未来的版本中可能会发生变化)。不过无需担心,稍后我们将详细讨论这些特殊对象类型的细节。在w2k_def.h中你可以找到所有未文档化的结构体(当然这仅限于我了解得那些)的定义,附录C也会列出这些结构体的定义。

表7-1. Dispatcher对象汇总

ID

类 型

C结构

定 义

0

DISP_TYPE_NOTIFICATION_EVENT

KEVENT

ntddk.h

1

DISP_TYPE_SYNCHRONIZATION_EVENT

KEVENT

ntddk.h

2

DISP_TYPE_MUTANT

KMUTANT,KMUTEX

ntddk.h

3

DISP_TYPE_PROCESS

KPROCESS

w2k_def.h

4

DISP_TYPE_QUEUE

KQUEUE

w2k_def.h

5

DISP_TYPE_SEMAPHORE

KSEMAPHORE

ntddk.h

6

DISP_TYPE_THREAD

KTHREAD

w2k_def.h

8

DISP_TYPE_NOTIFICATION_TIMER

KTIMER

ntddk.h

9

DISP_TYPE_SYNCHRONIZATION_TIMER

KTIMER

ntddk.h

表7-2列出了到目前为止所有我知道的I/O对象。仅有前13个可以在ntddk.h中找到它们的定义,

表7-2. I/O对象汇总

ID

类 型

C结构

定 义

1

IO_TYPE_AD_APTER

ADAPTER_OBJECT

2

IO_TYPE_CONTROLLER

CONTROLLER_OBJECT

ntddk.h

3

IO_TYPE_DEVICE

DEVICE_OBJECT

ntddk.h

4

IO_TYPE_DRIVER

DRIVER_OBJECT

ntddk.h

5

IO_TYPE_FILE

FILE_OBJECT

ntddk.h

6

IO_TYPE_IRP

IRP

ntddk.h

7

IO_TYPE_MASTER_ADAPTER

8

IO_TYPE_OPEN_PACKET

9

IO_TYPE_TIMER

IO_TIMER

w2k_def.h

10

IO_TYPE_VPB

VPB

ntddk.h

11

IO_TYPE_ERROR_LOG

IO_ERROR_LOG_ENTRY

w2k_def.h

12

IO_TYPE_ERROR_MESSAGE

IO_ERROR_LOG_MESSAGE

ntddk.h

13

IO_TYPE_DEVICE_OBJECT_EXTENSION

DEVOBJ_EXTENSION

ntddk.h

18

IO_TYPE_APC

KAPC

ntddk.h

19

IO_TYPE_DPC

KDPC

ntddk.h

20

IO_TYPE_DEVICE_QUEUE

KDEVICE_QUEUE

ntddk.h

21

IO_TYPE_EVENT_PAIR

KEVENT_PAIR

w2k_def.h

22

IO_TYPE_INTERRUPT

KINTERRUPT

23

IO_TYPE_PROFILE

KPROFILE

对象的表头(header)

Windows 2000对于对象体的大小和结构没有任何限制。与此相反的是,对象的表头则几乎没有什么自由可言。图7-1给出了一个对象实例的内存布局,该实例拥有完整的对象特性,并且其拥有最多的表头字段(header fields)。每一种对象特性都至少拥有一个基本的OBJECT_HEADER结构,紧随该结构之后就是对象体,在对象体之前最多可有四个可选的结构,这些结构用于提供了有关对象的附加信息。前面已经提到过,一个对象指针总是指向对象体,而不是对象的表头,因此需要在对象指针上增加一个负的偏移量才能访问表头字段。基本的表头包含有关可选表头字段的位置及其是否存在的信息,这些可选字段都位于OBJECT_HEADER结构之上,其顺序如图7-1所示。不过,这种顺序并不是强制的,你的应用程序不应该依赖这一顺序。OBJECT_HEADER结构中的信息足够定位所有的表头字段(唯一不能确定的就是它们的顺序)。唯一列外的是:如果OBJECT_CREATOR_INFO结构存在的话,那么它将总是出现在OBJECT_HEADER结构之前。

图7-1. 对象的内存布局

#define OB_FLAG_CREATE_INFO 0x01 // has OBJECT_CREATE_INFO

#define OB_FLAG_KERNEL_MODE 0x02 // created by kernel

#define OB_FLAG_CREATOR_INFO 0x04 // has OBJECT_CREATOR_INFO

#define OB_FLAG_EXCLUSIVE 0x08 // OBJ_EXCLUSIVE

#define OB_FLAG_PERMANENT 0x10 // OBJ_PERMANENT

#define OB_FLAG_SECURITY 0x20 // has security descriptor

#define OB_FLAG_SINGLE_PROCESS 0x40 // no HandleDBList

typedef struct _OBJECT_HEADER

{

/*000*/ DWORD PointerCount; // number of references

/*004*/ DWORD HandleCount; // number of open handles

/*008*/ POBJECT_TYPE ObjectType;

/*00C*/ BYTE NameOffset; // -> OBJECT_NAME

/*00D*/ BYTE HandleDBOffset; // -> OBJECT_HANDLE_DB

/*00E*/ BYTE QuotaChargesOffset; // -> OBJECT_QUOTA_CHARGES

/*00F*/ BYTE ObjectFlags; // OB_FLAG_*

/*010*/ union

{ // OB_FLAG_CREATE_INFO ? ObjectCreateInfo : QuotaBlock

/*010*/ PQUOTA_BLOCK QuotaBlock;

/*010*/ POBJECT_CREATE_INFO ObjectCreateInfo;

/*014*/ };

/*014*/ PSECURITY_DESCRIPTOR SecurityDescriptor;

/*018*/ }

OBJECT_HEADER,

* POBJECT_HEADER,

**PPOBJECT_HEADER;

#define OBJECT_HEADER_ sizeof (OBJECT_HEADER)

列表7-2. OBJECT_HEADER结构定义

列表7-2给出了OBJECT_HEADER结构的定义,该结构中的各个成员分别用于如下目的:

l PonterCount成员用于记录当前有多少指针指向此对象。这与COM中的引用计数非常类似。ntoskrnl.exe中的ObReferenceObject()、ObReferenceObjectByHandle()、ObReferenceObjectByName()和ObReferenceObjectByPointer()函数用于增加PointerCount,而ObfDereferenceObject()和ObDereferenceObject()则用于减少PointerCount。

l HandleCount成员用来记录当前有多少个打开的句柄引用了此对象。

l ObjectType成员指向一个OBJECT_TYPE结构(稍后将讨论),该结构用来代表一个类型对象,在对象的创建中将使用该结构。

l NameOffset成员给出了对象表头中的OBJECT_NAME结构的地址(用OBJECT_HEADER结构的地址减去NameOffset就可得到),如果为0,则表示对象表头中不存在OBJECT_NAME结构。

l HandleDBOffset成员给出了对象表头中的OBJECT_HANDLE_DB结构的地址(用OBJECT_HEADER结构的地址减去HandleDBOffset就可得到),如果为0,则表示对象表头中不存在OBJECT_HANDLE_DB结构。

l QuotachargesOffset成员给出了对象表头中的OBJECT_QUOTA_CHARGES结构的地址(用OBJECT_HEADER结构的地址减去QuotachargesOffset就可得到),如果为0,则表示对象表头中不存在OBJECT_QUOTA_CHARGES结构。

l ObjectFlags指出了对象的多个属性(每个属性占用一个二进制位),列表7-2的顶部列出了这些属性。如果OB_FLAG_CREATOR_INFO位被设置了,那么就意味着在对象表头中存在一个OBJECT_CREATOR_INFO结构,该结构紧挨着OBJECT_HEADER,并位于OBJECT_HEADER之前。在《Windows NT/2000 Native API Reference》中,Gray Nebbett在介绍ZwQuerySystemInformation()函数所使用的SystemObjectInformation标志时提到过对象属性,不过他的描述与本书给出的略有不同。表7-3给出了它们之间的区别。

l QuotaBlock和ObjectCreateInfo成员是互斥的(它们两个构成了一个union)。如果ObjectFlags成员的OB_FLAG_CREATE_INFO标志被设置,那么该成员(此时为ObjectCreateInfo)将包含一个指向OBJECT_CREATE_INFO结构(稍后介绍)的指针。否则,该成员(此时为QuotaBlock)将指向一个QUOTA_BLOCK结构,该结构提供了Paged和NonPaged内存池的使用量的相关信息。很多对象都将它们的QuotaBlock指针指向系统内部的PspDefaultQuotaBlock结构。该union可以为NULL。

l SecurityDescriptor成员 如果ObjectFlags成员的OB_FLAG_SECURITY位被设置的话,那么该成员将指向一个SECURITY_DESCRIPTOR结构,否则该成员为NULL。

上面的列表中提及到多个结构现在还没有介绍,接下来我们将开始介绍它们,首先要介绍的是图7-1中的四个可选表头字段。

表7-3. ObjectFlags描述对比

本书的描述

《Windows NT/2000 Native API Reference》

OB_FLAG_CREATE_INFO

0x01

N/A

OB_FLAG_KERNEL_MODE

0x02

KERNEL_MODE

OB_FLAG_CREATOR_INFO

0x04

CREATOR_INFO

OB_FLAG_EXCLUSIVE

0x08

EXCLUSIVE

OB_FLAG_PERMANENT

0x10

PERMANENT

OB_FLAG_SECURITY

0x20

DEFAULT_SECURITY_QUOTA

OB_FLAG_SINGLE_PROCESS

0x40

SINGLE_HANDLE_ENTRY

对象创建者的相关信息

如果ObjectFlags成员的OB_FLAG_CREATOR_INFO位被设置,那么对象的OBJECT_HEADER将紧随OBJECT_CREATOR_INFO结构之后。列表7-3给出了该可选结构的定义。OBJECT_CREATOR_INFO结构中的ObjectList成员是一个双向链表(参见第二章的列表2-7)中的一个节点。该双向链表由类型相同的对象构成。默认情况下,仅有Port和WaitablePort对象在它们的对象表头中包含OBJECT_CREATOR_INFO结构。使用SystemObjectInformation标志的ZwQuerySystemInformation()函数就是使用ObjectList来返回当前已分配对象的完整列表,这些对象将按照对象类型进行分类。在《Windows NT/2000 Native API Reference》中,Gray Nebbett指出“[….]仅在系统启动时,使用NtGlobalFlags()设置了FLG_MAINTAIN_OBJECT_TYPELIST,该信息标志才有效”(Nebbett 2000, p.25)

typedef struct _OBJECT_CREATOR_INFO

{

/*000*/ LIST_ENTRY ObjectList; // OBJECT_CREATOR_INFO

/*008*/ HANDLE UniqueProcessId;

/*00C*/ WORD Reserved1;

/*00E*/ WORD Reserved2;

/*010*/ }

OBJECT_CREATOR_INFO,

* POBJECT_CREATOR_INFO,

**PPOBJECT_CREATOR_INFO;

#define OBJECT_CREATOR_INFO_ sizeof (OBJECT_CREATOR_INFO)

列表7-3. OBJECT_CREATOR_INFO结构的定义

OBJECT_CREATOR_INFO 结构中的UniqueProcessId成员是一个从0开始的数字,它实际上是创建对象的进程的ID。尽管该成员被定义为一个句柄,但实际上它并不是一个句柄。它将被解释为一个不透明的32位无符号整数。Win32函数GetCurrentProcessId()返回的数据类型实际为DWORD。

OBJECT_NAME结构

如果OBJECT_HEADER结构中的NameOffset成员是一个非零值,那么就意味着存在着OBJECT_NAME结构,NameOffset的值就是该结构相对于OBJECT_HEADER的基地址的负偏移量。该负偏移量通常是0x10或0x20,这依赖于是否存在OBJECT_CREATOR_INFO结构。列表7-4给出了OBJECT_NAME结构的定义。OBJECT_NAME结构的Name成员是一个UNICODE_STRING结构,该结构的Buffer成员指向实际的名称字符串,该字符串占用的内存并不包含在对象中。并不是所有的命名对象都使用一个OBJECT_NAME结构来存储自己的名称。例如,有些对象使用QueryNameProcedure()来获取一个名字。QueryNameProcedure()会根据与这些对象相关联的OBJECT_TYPE来产生这一名字。

OBJECT_NAME结构的Directory成员不为NULL,那么它将指向一个目录对象(OBJECT_DIRECTORY),该对象用于记录该对象在系统的对象层次结构中位于哪一层。类似于文件位于文件系统中,Windows 2000的对象也保存在由目录对象和叶子对象(leaf object)构成的层次化的树型结构中。稍后我们将详细介绍OBJECT_DIRECTORY结构。

typedef struct _OBJECT_NAME

{

/*000*/ POBJECT_DIRECTORY Directory;

/*004*/ UNICODE_STRING Name;

/*00C*/ DWORD Reserved;

/*010*/ }

OBJECT_NAME,

* POBJECT_NAME,

**PPOBJECT_NAME;

#define OBJECT_NAME_ sizeof (OBJECT_NAME)

列表7-4. OBJECT_NAME结构

OBJECT_HANDLE_DATABASE结构

某些对象所维护的进程相关的句柄计数保存在一个称为“句柄数据库”的结构中。在这种情况下,OBJECT_HEADER结构的HandleDBOffset成员将包含一个非零值。和前面讨论的NameOffset类似,这一偏移量也是相对于OBJECT_HEADER基地址的负偏移量。列表7-5给出了OBJECT_HANDLE_DB结构的定义。如果ObjectFlags的OB_FLAG_SINGLE_PROCESS标志被设置,那么OBJECT_HANDLE_DB结构中的Process成员(位于该结构的一个union子结构中)将指向一个进程对象。如果一个以上的进程持有该对象的句柄,那么OB_FLAG_SINGLE_PROCESS标志将被清除,此时HandleDBList成员(该成员与前面的Process成员一起构成了OBJECT_HANDLE_DB结构中的一个union子结构)将指向一个OBJECT_HANDLE_DB_LIST结构,该结构包含一个OBJECT_HANDLE_DB结构数组。

typedef struct _OBJECT_HANDLE_DB

{

/*000*/ union

{

/*000*/ struct _EPROCESS *Process;

/*000*/ struct _OBJECT_HANDLE_DB_LIST *HandleDBList;

/*004*/ };

/*004*/ DWORD HandleCount;

/*008*/ }

OBJECT_HANDLE_DB,

* POBJECT_HANDLE_DB,

**PPOBJECT_HANDLE_DB;

#define OBJECT_HANDLE_DB_ sizeof (OBJECT_HANDLE_DB)

// -----------------------------------------------------------------

typedef struct _OBJECT_HANDLE_DB_LIST

{

/*000*/ DWORD Count;

/*004*/ OBJECT_HANDLE_DB Entries [];

/*???*/ }

OBJECT_HANDLE_DB_LIST,

* POBJECT_HANDLE_DB_LIST,

**PPOBJECT_HANDLE_DB_LIST;

#define OBJECT_HANDLE_DB_LIST_ sizeof (OBJECT_HANDLE_DB_LIST)

列表7-5. OBJECT_HANDLE_DB结构

资源使用费用(Charges)和使用限额(Quota)

如果一个进程打开一个对象的句柄,那么该进程必须为该操作所使用的系统资源“付费”。我们把应付款称为费用,进程可以使用的资源上限称为限额。在DDK文档的术语表中,微软以如下的方式定义了“限额”:

限额(Quota):

针对每个进程可使用的系统资源的限制。

针对每个进程,Windows NT/Windows 2000对某些系统资源设置了限制,这些资源是进程的线程需要使用的,这包括针对Paging-file、 Paged-pool和Nonpaged-pool的使用限额等等。例如,内存管理器使用限额来限制线程对page-file、paged-pool或nonpaged-pool内存的使用;当线程释放占用的内存后,管理器会更新配这些值。(Windows 2000 DDK\Kernel-Mode Drivers\Design Guide\Kernel-Mode Glossary\Q\Quota)

默认情况下,对象的OBJECT_TYPE用来确定paged/nonpaged poll的使用费用以及因为安全而产生的相关费用。不过,通过向对象中增加一个OBJECT_QUOTA_CHARGES结构可以改变这种默认设置。该结构相对于OBJECT_HEADER的偏移量由OBJECT_HEADER的QuotaChargesOffset成员给出,该偏移量是一个负偏移量。列表7-6给出了OBJECT_QUOTA_CHARGES结构的定义。Paged和Nonpaged Pool的使用量是独立统计的。如果对象要求使用安全特性,那么附加的SecurityCharge将被增加到paged-pool的使用量上。默认的安全开销是0x800。

如果ObjectFlags成员(属于OBJECT_HEADER结构)的OB_FLAG_CREATE_INFO标志位被设为0,那么QuotaBlock成员将指向一个QUOTA_BLOCK结构(见列表7-7),该结构包含有关对象的资源使用量的统计信息。

#define OB_SECURITY_CHARGE 0x00000800

typedef struct _OBJECT_QUOTA_CHARGES

{

/*000*/ DWORD PagedPoolCharge;

/*004*/ DWORD NonPagedPoolCharge;

/*008*/ DWORD SecurityCharge;

/*00C*/ DWORD Reserved;

/*010*/ }

OBJECT_QUOTA_CHARGES,

* POBJECT_QUOTA_CHARGES,

**PPOBJECT_QUOTA_CHARGES;

#define OBJECT_QUOTA_CHARGES_ sizeof (OBJECT_QUOTA_CHARGES)

typedef struct _QUOTA_BLOCK

{

/*000*/ DWORD Flags;

/*004*/ DWORD ChargeCount;

/*008*/ DWORD PeakPoolUsage [2]; // NonPagedPool, PagedPool

/*010*/ DWORD PoolUsage [2]; // NonPagedPool, PagedPool

/*018*/ DWORD PoolQuota [2]; // NonPagedPool, PagedPool

/*020*/ }

QUOTA_BLOCK,

* PQUOTA_BLOCK,

**PPQUOTA_BLOCK;

#define QUOTA_BLOCK_ sizeof (QUOTA_BLOCK)

列表7-7. QUOTA_BLOCK结构

对象目录

在讨论OBJECT_HEADER表头时我们已经提到过对象目录对象,Windows 2000对象管理器将独立的对象保存在一个树型的OBJECT_DIRECTORY结构中,该结构一般称为“目录对象”。一个OBJECT_DIRECTORY结构是另一个较复杂的对象类型,和OBJECT_HEADER对象类似,它也是一个实际的对象所必需的。Windows 2000管理对象目录的方式非常巧妙。如列表7-8所示,OBJECT_DIRECTORY本质上是一个Hash表,该表最多可容纳37个表项。之所以选择这37或许是因为这是一个质数吧J。每个表项可存放一个指向OBJECT_DIRECTORY_ENTRY结构的指针,OBJECT_DIRECTORY_ENTRY结构的Object成员是一个指向实际对象的指针。当一个对象被创建时,对象管理器根据对象的名字来计算该对象的Hash值(该值范围为0---36)并为该对象创建一个OBJECT_DIRECTORY_ENTRY。如果Hash表中的目标表项为空,那么前面创建的OBJECT_DIRECTORY_ENTRY结构的指针将被保存在该表项中。如果目标表项已经被使用了,那么新的OBJECT_DIRECTORY_ENTRY结构将被插入一个单向链表中,该链表的表头就位于该表项中。OBJECT_DIRECTORY_ENTRY结构中的NextEntry成员就是用来构建此单向链表的。为了表现出对象之间的层次关系,对象目录可以是嵌套的:通过增加一个新的OBJECT_DIRECTORY_ENTRY结构,并将该结构的Object成员指向其下属目录对象。

为了优化对频繁使用的对象的访问,对象管理器采用了简单的最近最多使用算法(most recently used,MRU)。只要可以成功的访问某个对象,那么该对象将被移动到它所在的单向链表的前端(译注:这里的对象目录对象构成的结构很像数据结构中的邻接表与Hash表的结合,采用单向链表来组织Hash值相同的目录对象,是Hash技术中最常用的处理冲突的方法)。更新后的链表指针保存在OBJECT_DIRECTORY结构中的CurrentEntry成员中。CurrentEntryValid标志用来表示CurrentEntry是否有效。通过使用一个称为ObpRootDirectoryMutex的资源锁可实现同步访问系统全局对象目录。这个锁既没有文档记录也没有导出。

typedef struct _OBJECT_DIRECTORY_ENTRY

{

/*000*/ struct _OBJECT_DIRECTORY_ENTRY *NextEntry;

/*004*/ POBJECT Object;

/*008*/ }

OBJECT_DIRECTORY_ENTRY,

* POBJECT_DIRECTORY_ENTRY,

**PPOBJECT_DIRECTORY_ENTRY;

#define OBJECT_DIRECTORY_ENTRY_ sizeof (OBJECT_DIRECTORY_ENTRY)

// -----------------------------------------------------------------

#define OBJECT_HASH_TABLE_SIZE 37

typedef struct _OBJECT_DIRECTORY

{

/*000*/ POBJECT_DIRECTORY_ENTRY HashTable [OBJECT_HASH_TABLE_SIZE];

/*094*/ POBJECT_DIRECTORY_ENTRY CurrentEntry;

/*098*/ BOOLEAN CurrentEntryValid;

/*099*/ BYTE Reserved1;

/*09A*/ WORD Reserved2;

/*09C*/ DWORD Reserved3;

/*0A0*/ }

OBJECT_DIRECTORY,

* POBJECT_DIRECTORY,

**PPOBJECT_DIRECTORY;

#define OBJECT_DIRECTORY_ sizeof (OBJECT_DIRECTORY)

列表7-8. OBJECT_DIRECTORY和OBJECT_DIRECTORY_ENTRY结构

..……..待续……….

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有