3.1 内核模式下的字符串操作

来源:互联网 发布:怎么删除淘宝已有地址 编辑:程序博客网 时间:2024/04/29 11:40
三、
编写驱动程序的基础知识
3.1 内核模式下的字符串操作
内核模式与用户模式一样都是有ANSI和UNICODE两种字符串,但可以这么说,Windows内核是使用Unicode编码的,ANSI只在很少的特殊场合才会使用,而这种场合往往是非常罕见的(摘自楚狂人的驱动教程),因此我们就不考虑ANSI字符串了,这里只介绍Unicode字符串的用法。
Unicode字符串有一个结构体定义如下:
typedefstruct_UNICODE_STRING{
USHORTLength; // 字符串的长度(字节数)
Windows 下设备驱动程序的开发方法 2120080411 计算机应用 赖锡盛
7
USHORTMaximumLength; // 字符串缓冲区的长度(字节数)
PWSTR Buffer; // 字符串缓冲区
}UNICODE_STRING,*PUNICODE_STRING;
需要注意的是,当我们定义了一个UNICODE_STRING变量之后,它的Buffer域还没有分配空间,因此我们不能直接赋值,好的做法是使用微软提供的Rtl系列函数。
UNICODE_STRINGstr;
RtlInitUnicodeString(&str,L"myfirststring!");
或者如下所示:
#include<ntdef.h>
UNICODE_STRINGstr=RTL_CONSTANT_STRING(L"myfirststring!");
看了上面的代码之后我们回顾一下第二章讲解创建设备对象和符号链接的代码,是不是就用RtlInitUnicode函数来初始化的。
还有一个需要注意的地方是,与ring3不同,我们的UNICODE字符串并不是以“\0”来表示字符串结束的,而是依靠UNICODE_STRING的Length域来确定。
字符串的很多操作都有相应的函数,例如字符串的复制可以使用RtlCopyUnicodeString函数,字符串的比较可以使用RtlCompareUnicodeString函数,字符串转换成大写可以使用RtlUpcaseUnicodeString函数(没有转换成小写的),字符串与整数数字互相转换分别可以使用RtlUnicodeStringToInteger和RtlIntegerToUnicodeString函数。
下面我们来着重说明一下字符串的打印方法。比如在输出日志记录的时候,我们往往同时涉及数字、字符等信息,在C语言中我们可以使用sprintf和swprintf函数来完成任务,这两个函数在驱动中仍然可以使用,但很不安全,因为有许多C语言的运行时函数都是基于Win32API的,在驱动中绝对不能使用,如果我们不清楚哪些可以使用哪些不能使用,就都不要使用,而使用微软推荐的Rtl系列函数。对应sprintf的功能函数是RtlStringCbPrintfW,它需要包含头文件“ntstrsafe.h”和静态连接库“ntsafestr.lib”。相关代码如下所示:
#include<ntstrsafe.h>
// 任何时候,假设文件路径的长度为有限的都是不对的。应该动态的分配内存。
Windows 下设备驱动程序的开发方法 2120080411 计算机应用 赖锡盛
8
但动态分配内存的
// 方法还没有讲述,所以这里再次把内存空间定义在局部变量中,也就是所谓的“在栈中”
WCHARbuf[512]={0};
UNICODE_STRINGdst;
NTSTATUSstatus;
……
// 字符串初始化为空串。缓冲区长度为512*sizeof(WCHAR)
RtlInitEmptyString(dst,dst_buf,512*sizeof(WCHAR));
// 调用RtlStringCbPrintfW来进行打印
status=RtlStringCbPrintfW(
dst->Buffer,L”filepath=%wZfilesize =%d\r\n”,
&file_path,file_size);
// 这里调用wcslen没问题,这是因为RtlStringCbPrintfW打印的字符串是以空结束的。
dst->Length=wcslen(dst->Buffer)*sizeof(WCHAR);
RtlStringCbPrintfW在目标缓冲区内存不足的时候依然可以打印,但是多余的部分被截去了。返回的status值为STATUS_BUFFER_OVERFLOW。调用这个函数之前很难知道究竟需要多长的缓冲区。一般都采取倍增尝试。每次都传入一个为前次尝试长度为2倍长度的新缓冲区,直到这个函数返回STATUS_SUCCESS为止。
值得注意的是UNICODE_STRING类型的指针,通常用%wZ可以打印出字符串。在不能保证字符串为空结束的时候,必须避免使用%ws或者%s。其他的打印格式字符串与传统C语言中的printf函数完全相同。可以尽情使用。
原创粉丝点击