驱动开发之字符串操作

WDM驱动程序可以使用下面4种格式的字符串:

  • Unicode串,由UNICODE_STRING结构描述,包含16位字符。Unicode有足够的代码空间编码地球上所有语言的字型。
  • ANSI串,由ANSI_STRING结构描述,包含8位字符。另一种OEM_STRING串与其相似,也是用8位字符描述串。两者的不同是,OEM串中的字符字型由当前代码页决定,而ANSI串的字符字型不依赖任何代码页。WDM驱动程序不必处理OEM串,因为它们只能来自用户模式,在驱动程序看到这些串之前,它们已经被某些内核模式部件转换成Unicode串。
  • 空结尾的字符串。你可以用普通的C语法表达串常量,例如,"Hello, world!",该串使用了类型为CHAR的8位字符,这些字符被假定属于ANSI字符集。串常量中的字符来自你创建源程序所用的编辑器。如果你的编辑器需要依赖当前代码页才能显示编辑窗口中的字符字型,那么应该注意,这些字符在Windows ANSI字符集中可能会有不同的含义。
  • 空结尾的宽字符(WCHAR类型)串,用C语法也可以表达宽串常量,例如,L"Goodbye, cruel world!",该串看起来象Unicode串常量,但是,最后从文本编辑器出来的串实际仅使用了Windows ANSI字符集中ASCII和Latin1区(0020-007F和00A0-00FF)中的字符。

UNICODE_STRING和ANSI_STRING有相同的数据结构。Buffer域指向包含串数据的缓冲区。MaximumLength给出了缓冲区的长度,Length提供串的当前长度,它不考虑任何可能存在的空结束符。length域的单位是字节,对于UNICODE_STRING结构也是这样。

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

typedef struct _STRING {
  USHORT  Length;
  USHORT  MaximumLength;
  PCHAR  Buffer;
} ANSI_STRING, *PANSI_STRING;

表3-7列出了用于处理Unicode和ANSI字符串的服务函数。我还对应列出了一些标准C运行时间库函数,这些函数在内核模式中也存在,它们可以处理常规的C样式串。虽然它们从来没有在DDK文档中公开过,但标准DDK头中有这些函数的声明,而且连接库中也包含了它们,所以没有理由不使用它们。

表3-7. 串处理函数

操作ANSI串函数Unicode串函数
Lengthstrlenwcslen
Concatenatestrcat, strncatwcscat, wcsncat, RtlAppendUnicodeStringToString, RtlAppendUnicodeToString
Copystrcpy, strncpy, RtlCopyStringwcscpy, wcsncpy, RtlCopyUnicodeString
Reverse_strrev_wcsrev
Comparestrcmp, strncmp, _stricmp, _strnicmp, RtlCompareString, RtlEqualStringwcscmp, wcsncmp, _wcsicmp, _wcsnicmp, RtlCompareUnicodeString, RtlEqualUnicodeString, RtlPrefixUnicodeString
Initialize_strset, _strnset, RtlInitAnsiString, RtlInitString_wcsnset, RtlInitUnicodeString
Searchstrchr, strrchr, strspn, strstrwcschr, wcsrchr, wcsspn, wcsstr
Upper/lowercase_strlwr, _strupr, RtlUpperString_wcslwr, _wcsupr, RtlUpcaseUnicodeString
Characterisdigit, islower, isprint, isspace, isupper, isxdigit, tolower, toupper, RtlUpperChartowlower, towupper, RtlUpcaseUnicodeChar
Formatsprintf, vsprintf, _snprintf, _vsnprintfswprintf, _snwprintf
String conversionatoi, atol, _itoa_itow, RtlIntegerToUnicodeString, RtlUnicodeStringToInteger
Type conversionRtlAnsiStringToUnicodeSize, RtlAnsiStringToUnicodeStringRtlUnicodeStringToAnsiString
Memory releaseRtlFreeAnsiStringRtlFreeUnicodeString

系统DLL还输出了许多RtlXxx函数,但我仅列出了在DDK头文件中定义了原型的函数,在驱动程序中我们仅应使用这些函数。

分配和释放串缓冲区

我不将详细描述这些串处理函数,DDK中的描述已经十分详细。你可以根据你的串使用经验使用它们。但这里有一个问题我要提一下。

你可能经常把UNICODE_STRING或ANSI_STRING类型的串定义成自动变量,或者定义成设备扩展的一部分。而串的数据缓冲区通常是动态分配的内存。但有时候你希望使用串常量,记录谁拥有某个串缓冲区可能是一个问题。考虑下面函数片段:

UNICODE_STRING foo;
if (bArriving)
  RtlInitUnicodeString(&foo, L"Hello, world!");
else
{
  ANSI_STRING bar;
  RtlInitAnsiString(&bar, "Goodbye, cruel world!");
  RtlAnsiStringToUnicodeString(&foo, &bar, TRUE);
}
...
RtlFreeUnicodeString(&foo); 				//  <--don't do this!

在第一种情况下,我们为驱动程序中的宽字符串常量初始化foo.Lengthfoo.MaximumLength,和foo.Buffer。在另一种情况下,我们要求系统(使用第三个参数为TRUE的RtlAnsiStringToUnicodeString调用)为转化ANSI串分配内存。在第一种情况下,调用RtlFreeUnicodeString就是一个错误,因为它将无条件地释放常量串“Hello, world!”占用的内存,由于foo串的Buffer成员指向一个常量串,不是动态分配的内存,所以根本不能释放。在另一种情况下,由于我们指定了TRUE参数,系统为表达转换结果动态地分配了Unicode串缓冲区,所以我们必须调用RtlFreeUnicodeString释放该缓冲区,以避免内存泄漏。

Blob数据(大块数据)

我从数据库技术中借来术语“blob”来描述一块无结构定义的字节组合。表3-8列出了处理这种数据的函数(包括一些来自标准运行时间库中的函数),你可以在内核模式中调用它们。我假设你能从它们的名字上看出它们的用法。然而,我需要指出一些不明显的事实:

  • 内存的“copy”和“move”操作之间的区别在于可否容忍源和目的相重叠。move操作不管源和目的是否重叠。而copy操作在源和目的有任何重叠时不工作。
  • “byte”操作和“memory”操作的区别是操作的间隔尺寸。byte操作保证按字节为单位执行。而memory操作可以在内部使用更大的块,所有这些块的和等于指定的字节数。这个区别会根据平台的不同而改变,在32位Intel计算机上,byte操作实际上是对应memory操作的宏。但在Alpha平台上,RtlCopyBytesRtlCopyMemory是完全不同的函数。

表3-8. 处理blob数据的服务函数

服务函数或宏描述
memchr在blob中寻找一个字节
memcpy, RtlCopyBytes, RtlCopyMemory复制字节,不允许重叠
memmove, RtlMoveMemory复制字节,允许重叠
memset, RtlFillBytes, RtlFillMemory用给定的值填充blob
memcmp, RtlCompareMemory, RtlEqualMemory比较两个blob
memset, RtlZeroBytes, RtlZeroMemoryblob清零
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值