内核编程笔记(一、内核字符串处理)

原文:http://hi.baidu.com/hack_oldwolf/blog/item/03c2dba88fad05bcca130c47.html

 

1、使用字符串结构

=================================================================
UNICODE_STRING
UNICODE_STRING结构体是用来定义UNICODE字符串的。

typedef struct _UNICODE_STRING {
  USHORT    Length;
  USHORT    MaximumLength;
   PWSTR   Buffer;
} UNICODE_STRING * PUNICODE_STRING;

结构体变量说明:
Length
存储在缓冲器中字符串的长度。
MaximumLength
缓冲器的最大长度。
Buffer
指向一个包含宽字符字符串的缓冲区。
=================================================================
由于UNICODE_STRING中Buffer不一定是以空终止符结尾的。所以下面的方法都是错误的:

UNICODE_STRING str;
len = wcslen( str.Buffer);        //试图求长度
DbgPrint( "%ws" , str.Buffer);     //试图调试输出str.Buffer中的内容

出错的原因也很简单,wcslen和DbgPrint都认为'/0' 是字符串结束符
=================================================================
2 、字符串的初始化

错误的初始化方法:
UNICODE_STRING str;
wcscpy( str.Buffer, L"my first string!" );     //错误:Buffer是一个未初始化的指针
str.Length = str.MaximumLength = wcslen( L"my first string!" ) * sizeof ( WCHAR);

正确的初始化方式是:
UNICODE_STRING str;
str.Buffer = L"my first string!" ;
str.Length = str.MaximumLength = wcslen( L"my first string!" ) * sizeof ( WCHAR);

上面初始化字符串的方法相对比较繁琐,在头文件ntdef.h中有一个宏,可简单初始化子符串。
#include < ntdef.h>
UNICODE_STRING str = RTL_CONSTANT_STRING( L"my first string!" );

但是RTL_CONSTANT_STRING这个宏只能在定义的时候使用,为了随时初始化字符串,我们使用RtlInitUnicodeString.定义方法如下:
UNICODE_STRING str;
RtlInitUnicodeString(& str, L"my first string!" );

或者使用RtlInitEmptyString:
UNICODE_STRING str;
WCHAR wchStr[ 256 ];
RtlInitEmptyString(& str, wchStr, sizeof ( WCHAR) * 256 );

3 、字符串拷贝

在内核编程中,普通的wcscpy函数已经不行了。我们用RtlCopyUnicodeString函数来拷贝。拷贝的时候要注意目的字符串的Buffer必须要有足够的空间,否则会丢失数据,但系统不会崩溃。
例子:
UNICODE_STRING dst;
WCHAR dst_buf[ 256 ];
UNICODE_STRING src = RTL_CONSTANT_STRING( L"my first string!" );
RtlInitEmptyString(& dst, dst_buf, sizeof ( WCHAR) * 256 );
RtlCopyUnicodeString(& dst, & src);

4 、字符串的连接

内核中的Unicode字符串连接不难,重要的是保证目标字符串的空间大小。
实例:
NTSTATUS status
UNICODE_STRING dst;
WCHAR dst_buf[ 256 ];
UNICODE_STRING src = RTL_CONSTANT_STRING( L"my first string!" );
RtlInitEmptyString(& dst, dst_buf, sizeof ( WCHAR) * 256 );
RtlCopyUnicodeString(& dst, & src);
status = RtlAppendUnicodeToString(& dst, L"my second string!" );
if ( status == STATUS_SUCCESS)
{
     ……
}

这里在介绍个连接字符串的函数:
NTSTATUS
   RtlAppendUnicodeStringToString(
     IN OUT PUNICODE_STRING   Destination,     //指向目的字符串的缓冲区
     IN PUNICODE_STRING   Source              //指向源字符串的缓冲区
    );

NTSTATUS是一个返回值类型,如果成功就返回STATUS_SUCCESS,否则返回一个错误码。如果目标字符串的空间不足,则返回一个STATUS_BUFFER_TOO_SAMLL。


5 、字符串的打印

NTSTATUS
   RtlStringCbPrintfW(
     OUT LPWSTR   pszDest,     //指向目的Unicode字符串
     IN size_t   cbDest,       //目的缓冲区的大小,Unicode的*sizeof(WCHAR)。
     IN LPCWSTR   pszFormat,
     ...
    );

使用该函数的时候要包含ntstrsate.h和ntstrsate.lib。
实例:
int const arraysize = 30 ;
WCHAR pszDest[ arraysize];
size_t cbDest = arraysize * sizeof ( WCHAR);

LPCWSTR pszFormat = L"%wZ %d + %d + %d." ;
WCHAR * pszTxt = L"my first string!" ;

NTSTATUS status = RtlStringCBPrintfW( pszDest, cdDest, pszFormat, pszTxt, 1 , 2 , 3 );
RtlStringCBPrintfW在目标缓冲区内存不足的时候依然可以打印,但是多余的部分被借去了,此时的status的返回值为STATUS_BUFFRT_OVERFLOW。
打印UNICODE_STRING类型的指针时,在不确定字符串是以空终止符结尾的情况下,最好用% wZ, 否则也可以使用% ws和% s。
驱动中还可以调用DbgPrint() 函数来打印调试信息。
但是DbgPrint() 不管在发行版还是调试版本中都会有效,一般我们都使用宏KdPrint() 来输出调试字符串。
使用KdPrint() 函数的时候要使用双括号来包含参数。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值