WDM drivers can work with string data in any of four formats:
The UNICODE_STRING and ANSI_STRING data structures both have the layout depicted in Figure 3-14. The Buffer field of either structure points to a data area elsewhere in memory that contains the string data. MaximumLength gives the length of the buffer area, and Length provides the (current) length of the string without regard to any null terminator that might be present. Both length fields are in bytes, even for the UNICODE_STRING structure.
Figure 3-14. The UNICODE_STRING and ANSI_STRING structures.
Table 3-7 lists the service functions that you can use for working with Unicode and ANSI strings. I've listed them side by side because there's a fair amount of duplication. I've also listed some functions from the standard C run-time library that are available in kernel mode for manipulating regular C-style strings. The standard DDK headers include declarations of these functions, and the libraries with which you link drivers contain them, so there's no particular reason not to use them even though they've never been documented in the DDK as being available.
Table 3-7. Functions for string manipulation.
|Operation||ANSI String Function||Unicode String Function|
||wcscat, wcsncat, RtlAppendUnicodeStringToString, RtlAppendUnicodeToString|
||wcscpy, wcsncpy, RtlCopyUnicodeString|
||wcscmp, wcsncmp, _wcsicmp, _wcsnicmp, RtlCompareUnicodeString, RtlEqualUnicodeString, RtlPrefixUnicodeString|
|Initialize||_strset, _strnset, RtlInitAnsiString, RtlInitString||_wcsnset, RtlInitUnicodeString|
||wcschr, wcsrchr, wcsspn, wcsstr|
|Upper/lowercase||_strlwr, _strupr, RtlUpperString||_wcslwr, _wcsupr, RtlUpcaseUnicodeString|
||towlower, towupper, RtlUpcaseUnicodeChar|
|Format||sprintf, vsprintf, _snprintf, _vsnprintf||swprintf, _snwprintf|
|String conversion||atoi, atol, _itoa||_itow, RtlIntegerToUnicodeString, RtlUnicodeStringToInteger|
|Type conversion||RtlAnsiStringToUnicodeSize, RtlAnsiStringToUnicodeString||RtlUnicodeStringToAnsiString|
functions are exported by the system DLLs, but I've listed the ones for which the DDK header files (and the SDK headers they include) define
I'm not going to describe the string manipulation functions in detail because the DDK documentation does this
You often define UNICODE_STRING (or ANSI_STRING) structures as automatic
UNICODE_STRINGfoo; if(bArriving) RtlInitUnicodeString(&foo,L"Hello,world!"); else RtlAnsiStringToUnicodeString(&foo,"Goodbye,cruelworld!",TRUE); ... RtlFreeUnicodeString(&foo);// don'tdothis!
In one case, we initialize foo.Length , foo.MaximumLength , and foo.Buffer to describe a wide character string constant in our driver. In another case, we ask the system (by means of the TRUE third argument to RtlAnsiStringToUnicodeString ) to allocate memory for the Unicode translation of an ANSI string. In the first case, it's a mistake to call RtlFreeUnicodeString because it will unconditionally try to release a memory block that's part of our code or data. In the second case, it's mandatory to call RtlFreeUnicodeString eventually if we want to avoid a memory leak.
I've borrowed the
Table 3-8. Service functions for working with blobs of data.
|Service Function or Macro||Description|
||Find a byte in a blob|
||Copy bytes when there might be an overlap|
||Fill blob with given value|
||Compare one blob to another|
|memset, RtlZeroBytes, RtlZeroMemory||Zero-fill a blob|
The Windows 2000 Device Driver Book: A Guide for Programmers (2nd Edition)
Windows System Programming (4th Edition) (Addison-Wesley Microsoft Technology Series)
Developing Drivers with the Windows Driver Foundation (Pro Developer)
Windowsu00ae Internals: Including Windows Server 2008 and Windows Vista, Fifth Edition (Pro Developer)