2 《Undocumented Windows 2000 Secrets》翻译 --- 第二章( 四 )


USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING,*PUNICODE_STRING;
typedef struct _STRING
{
USHORT Length;
USHORT MaximumLength;
PCHAR Buffer;
} STRING, *PSTRING;
typedef STRING ANSI_STRING, *PANSI_STRING;
typedef STRING OEM_STRING, *POEM_STRING;
列表 2-4. 字符串类型
Length 成员给出了当前字符串的字节数(注意,不是字符个数),MaximumLength 成员指出 Buffer 所指向内存块的大小,实际的字符串数据将保存在该内存块中 。注意,MaximumLength 也是字节数 。由于 Unicode 字符宽度为 16 位,所有其长度总是字符个数的两倍 。通常,Buffer 指向的字符串都是以零结尾的 。然而,有些内核模块可能仅依赖字符串的长度值,而不考虑结尾的 0 字符,这种情况下要小心处理 。
Windows 2000 的 ANSI 字符串叫做 STRING ,如 列表 2-4 中所示 。为了方便,nedef.h 分别定义了 ANSI_STRING 和 OEM_STRING 来代表使用不同代码页的 8 位字符串( ANSI 默认代码页为 1252 ; OEM 默认代码页为 437 ) 。不过,Windows 2000 内核使用的主要字符串类型还是 UNICODE_STRING。你可能偶尔会碰到 8 位字符串 。
在 图 2-3 中,我给出了两个典型的 UNICODE_STRING 示例 。左面的那个包含两个独立的内存块:一个 UNICODE_STRING 结构和一个 16 位 PWCHAR 类型的 Unicode 字符数组 。这或许是在 Windows 2000 数据类型中最常见的字符串类型 。右边的是一种频繁出现的特殊类型,在此种类型中,UNICODE_STRING 和 PWCHAR 数组位于同一个内存块中 。有些内核函数,包括 Native API 内部使用的一些函数,都在连续的内存块中保存其返回的结构化的系统信息 。如果数据中包含字符串,它们通常都存储在嵌入式的 UNICODE_STRING 中,如 图 2-3 右面所示 。例如,NtQuerySystemInformation() 函数就频繁使用了这种特殊的字符串类型 。
这些字符串结构不许要手工维护,ntdll.dll 和 ntoskrnl.exe 导出了一组丰富的运行时 API 函数,如 RtlCreateUnicodeString() 、 RtlInitUnicodeString() 、 RtlCopyUnicodeString() 等 。通常,STRING 和 ANSI_STRING 也有对应的等价函数 。这些函数中的大多数在 DDK 中都有文档记录,但其中有些没有 。不过,很容易猜出这些未文档化的字符串函数的功能及其需要的参数 。使用 UNICODE_STRING 、 STRING 的好处是,可以隐示的指定 Buffer 可容纳的字符串的大小 。如果你给一个函数传递了一个 UNICODE_STRING 类型的字符串,而该函数需要适当改变该字符串的值,而这可能会增加该字符串的长度,那这个函数只需要简单的检查 MaximumLength 成员就可确定是否有足够的空间来存放结果 。
结构体
个别的几个内核 API 函数期望其处理的对象有一个合适的 OBJECT_ATTRIBUTES 结构,列表 2-5 给出了该结构的定义 。例如,NtOpenFile() 函数没有 PWSTR 或 PUNICODE_STRING 参数用来指定要打开的文件的路径 。替代的,OBJECT_ATTRIBUTES 结构中的 ObjectName 成员给出了该路径 。通常,设置该结构很容易 。除 ObjectName 外,还需要设置 Length 和 Attributes 成员 。Length 必须设置为: sizeof(OBJECT_ATTRIBUTES) ,Attributes 是一组来自 ntdef.h 的 OBJ_* 常量 。例如,如果你对象名称不区分大小写的话,Attributes 应设置为 OBJ_CASE_INSENSITIVE。当然,ObjectName 成员是一个 UNICODE_STRING 指针,并不是通常的 PWSTR。剩余的成员只要不使用,都可设置为 NULL。
typedef struct _OBJECT_ATTRIBUTES
{
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
列表 2-5. OBJECT_ATTRIBUTES 结构
OBJECT_ATTRIBUTES 结构仅描述函数使用的数据的细节,列表 2-6 给出的 IO_STATUS_BLOCK 结构则用于记录对用户所提交的操作的处理结果 。该结构很简单 ---Staus 成员存放一个 NTSTATUS 类型的代码,其值可能是 STATUS_SUCCESS 或定义于 ntstatus.h 中的所有可能的错误代码 。Information 成员在操作成功的情况下,提供与操作相关的附加数据 。比如,如果函数返回一个数据块,该成员将被设置为该数据块的大小 。

推荐阅读