前记:最近驱动也差不多弄完了,在过一段时间差不多该上了,回头看看,这半年来也就折腾了这个象样点,自然也要留点啥的,供后面回忆回忆。
言归正传,首先看UNICODE_STRING的结构定义:
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING *PUNICODE_STRING;
包括三个域,其中:
Length:表示Buffer的长度;
MaximumLength:表示Buffer的最大长度,一般不常用,和系统有关系;
Buffer:表示字符串指针地址;
UNICODE_STRING在驱动应用比较多,其操作大致有如下几个:
(1)初始化,常见的初始化有两种方式:
1.调用RtlInitUnicodeString,该函数原型如下:
VOID RtlInitUnicodeString(
IN OUT PUNICODE_STRING DestinationString,
IN PCWSTR SourceString
);
该方法的实际原理是:将SourceString的宽字符串指针赋值给UNICODE_STRING的Buffer值,同时SourceString的长度值填入结构的Length域,默认的MaximumLength = Length + 2;
如:RtlInitUnicodeString(&ustrRegString,L"Hello");
2.采用动态分配内存的方式初始化,其调用方式如下:
UNICODE_STRING ustr;
ustr.Length= 0;
ustr.MaximumLength = 256;
ustr.Buffer = (PWCHAR)ExAllocatePoolWithTag(NonPagedPool,256,MEM_TAG); //MEM_TAG为自定义
这样就动态分配了一个存储空间给ustr。
(2)字符串连接
连接常见的就是将两个UNICODE_STRING或者将WCHAR_T的字符串连接起来
首先,将两个UNICODE_STRING连接起来,调用RtlAppendUnicodeStringToString函数实现,其原型如下:
NTSTATUS RtlAppendUnicodeStringToString(
IN OUT PUNICODE_STRING Destination,
IN PUNICODE_STRING Source
);
调用该函数的原理是将两者的字符串Buffer拼接起来,同时,更新对应的Length和MaxLength域。在调用的
过程中要注意Destination的MaxLength域,若MaxLength小于Destination和Source的Length域的和的时候,该函数调用不成功,返回0xC0000023,即缓冲区溢出错误。所以在调用该函数的时候,一定要确定Destination的MaxLength域。
若将WCHAR_T字符串串接到UNICODE_STRING之后,则需要调用RtlAppendUnicodeToString,函数原型如下:
NTSTATUS RtlAppendUnicodeToString(
IN OUT PUNICODE_STRING Destination,
IN PCWSTR Source
);
该函数和上面函数并没有特别多的不一致,但该函数较上一个函数不同的地方就是不会出现缓冲区溢出的错误,也就是即使Destination的MaxLength域为0,也可以执行RtlAppendUnicodeToString的操作。
还有另外一个需要注明的地方,如果UNICODE_STRING是通过RtlInitUnicodeString初始化,那么不管调用什么函数,修改UNICODE_STRING值的时候,初始化使用的PCWSTR数组的值也会发生改变,因为他们指向的是同一个Buffer。
注上一例,备后用:
UNICODE_STRING ustrStr,ustrName;
ustrStr.Length = wcslen(strKey) * 2;
RtlAppendUnicodeToString(&ustrStr,strKey);
ustrStr.MaximumLength = 256;
RtlAppendUnicodeToString(&ustrStr,L"");
RtlAppendUnicodeStringToString(&ustrStr,&ustrName);
(3)字符串转换
转换目的可能涉及到中文显示的问题,如果简单的UNICODE_STRING转换为wchar_t或者char的形式,采用RtlCopyMemory的方式,因为UNICODE_STRING字符串并不一定以\0作为结束符,所以需要使用RtlCopyMemory,拷贝定长的字符串。
对于中文显示的问题,采用ANSI_STRING的方式进行输出。从UNICODE_STRING到ANSI_STRING转换,可以通过RtlUnicodeStringToAnsiString实现,其原型如下:
NTSTATUS RtlUnicodeStringToAnsiString(
IN OUT PANSI_STRING DestinationString,
IN PUNICODE_STRING SourceString,
IN BOOLEAN AllocateDestinationString
);
典型例子如下:
UNICODE_STRING src;
ANSI_STRING dst;
RtlInitUnicodeString(&src,L”打印汉字”);
RtlUnicodeStringToAnsiString(&dst,&src,TRUE);
DbgPrint(“%Z”,&dst);
RtlFreeAnsiString(&dst);