UNICODE_STRING的初始化

UNICODE_STRING结构体的三个成员可以看到,其包含的是字符串的指针,字符串的实际长度和字符串指针的内存空间长。
学过C语言的我们都知道,要对一个指针的内存进行赋值,就必须确定这个指针指向的内存空间可用,否则会导致内存使用异常。在应用层中会导致应用程序异常,而在驱动中会导致蓝屏。
我们们这里使用以下的代码是完全错误的,内核会立刻崩溃:

    #define MYSTRING L"www.bytekits.com"
    UNICODE_STRING str;
    wcscpy(str.Buffer,MYSTRING);
    str.Length = str.MaximumLength = wcslen(MYSTRING) * sizeof(WCHAR);

上面的这段代码相当于定义了一个指针,但并没有对这个指针进行初所以系统会使用默认的值进行填充。str.Buffer只是一个未初始化的指针。它并没有指向有意义的空间。

Rlease/Free编译环境下为NULL,所以wcscpy其实是对NULL地址复制数据。

其相当于我们在应用层如下的代码:

#define MYSTRING L"www.bytekits.com"
char * pBuffer;
wcscpy(str.Buffer,MYSTRING);

pBuffer并未始始化,所以对其指向的内存赋值会引起内存写异常。

手动初始化UNICODE_STRING

以下的方法是正确初始化UNICODE_STRING:

#define MYSTRING L"www.bytekits.com"
    // 先定义后,再定义空间
UNICODE_STRING str;
str.Buffer = MYSTRING;
str.Length = str.MaximumLength = wcslen(MYSTRING) * sizeof(WCHAR);

在上面的代码中,指针Buffer进行了初始化赋值,这个指针指向的全局常量地址空间,所以这一段地址空间只能读,不可写。
如果我们强行对其地址修改,会触发系统的异常,导致蓝屏。

下在我们来使用另一种方式来初始化UNICODE_STRING。

UNICODE_STRING str = { 
    sizeof(L"www.bytekits.com") – sizeof((L"www.bytekits.com")[0]),
    sizeof(L"www.bytekits.com"),
    L"www.bytekits.com"};

上面一段代码相当于分别对结构体的三个变量进行初始化:
对于UNICODE_STRING的Length,相当于

str.Length = sizeof(L"www.bytekits.com") – sizeof((L"www.bytekits.com")[0]);
  • sizeof(L”www.bytekits.com”) 计算该字符串所占的内存空间,这里包括L’\0’。
  • sizeof((L”www.bytekits.com”)[0])相当于取的是这个字符串的第一个字符长度,这里因为宽字节,所以是2,两者相减,就计算出了字符串的长度。这里看到确实是以字节为单位计算的,而不是以宽字节的长度为单位的。

而对于UNIOCDE_STRING的MaximumLength成同,则直接使用sizeof计算其所占内存空间。所以这里也就包括了L’\0’2个字节的长度。

对于UNIOCDE_STRING的Buffer成员,直接使用常量地址空间的地址赋值。


使用RtlInitUnicodeString和RTL_CONSTANT_STRING初始化字符串

通过上面的代码看到,要初始化一个UNICODE_STRING,简直不要太复杂,而且很容易由于书写错误引起错误而导致蓝屏。
这里就不得不说一下微软简易太贴心了,它把以上的代码封装成了一个宏RTL_CONSTANT_STRING,我们可以直接使用这个宏来初始化常量字符串。

#define RTL_CONSTANT_STRING(s) \
{ \
    sizeof( s ) - sizeof( (s)[0] ), \
    sizeof( s ) / sizeof(_RTL_CONSTANT_STRING_type_check(s)), \
    _RTL_CONSTANT_STRING_remove_const_macro(s) \
}

所以上面的代码可以简化为:

#include <ntdef.h>
UNICODE_STRING str = RTL_CONSTANT_STRING(L"www.bytekits.com");

要使用宏RTL_CONSTANT_STRING,必须包括头文件ntdef.h,因为这个宏是在ntdef.h头文件中定义的。

这里我们再介绍一个函数可以使用RtlInitUnicodeString函数,这个函数可以随时初始化一个字符串。

这只能在定义这个字符串的时候使用。为了随时初始化一个字符串,可以使用RtlInitUnicodeString。示例如下:

UNICODE_STRING str;
RtlInitUnicodeString(&str,L"www.bytekits.com");
...
//可以再次初始化
RtlInitUnicodeString(&str,L"tool.bytekits.com");

关于ANSI_STRING

ANSI_STRING字符串也有相对应的宏和初始函数,分别为RTL_CONSTANT_STRING和RtlInitString。

    ANSI_STRING str = RTL_CONSTANT_STRING("www.bytekits.com");
    RtlInitAnsiString(&str, "www.bytekits.com");

用本小节的方法初始化的字符串,不用担心内存释放方面的问题。因为我们并没有分配任何内存,因为这些内存都是使用的是常量地址空间。

取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

Powered by bytekits.com,汇天下文字,成非凡梦想!!!