ntstrsafe.h now contains safe functions for UNICODE_STRING too!

I don’t think this is a well publicized feature, but the Server 2003 SP1 DDK contains a new version of ntstrsafe.h that now supports UNICODE_STRING.  I pushed for this new functionality because nearly all ntoskrnl.exe exports which deal with a name expect a UNICODE_STRING, not a PWSTR.  Furthermore, all of the KMDF DDIs which accept a raw string expect a UNICODE_STRING pointer, not a PWSTR.

It used to be that you have code like this

ULONG count = 0;

do {
    UNICODE_STRING string;
    WCHAR buffer[80];
    NTSTATUS status;

    status = RtlStringCbPrintfW(buffer, sizeof(buffer), “\\Device\\Foo%d”, count++);
    if (!NT_SUCCESS(status)) {
        return status;

    RtlInitUnicodeString(&string, buffer);

    status = IoCreateDevice(DriverObject,

while the formatting can now be

WCHAR buffer[80];

string.Buffer = buffer;
string.Length = 0;
string.MaximumLength = sizeof(buffer);

do {
    status = RtlUnicodeStringPrintf(string, “\Device\Foo%d”, count++);
    if (!NT_SUCCESS(status)) {
        return status;

The naming convention for the UNICODE_STRING versions is

  • There are no A or W versions, there are just W versions.  As such, there is no A or W designation, e.g. RtlUnicodeStringPrintf vs RtlStringCbPrintfW.
  • Since the UNICODE_STRING contains its length, there are no Cb and Cch versions.  As such, there is no Cch or Cb designation. 
  • The source string can be either a PCWSTR or another PCUNICODE_STRING.  A function which takes the PCUNICODE_STRING is RtlUnicodeStringXxx, where Xxx is the action (Cat, Copy, etc), e.g. NTSTATUS RtlUnicodeStringCat(PUNICODE_STRING Dest, PCUNICODE_STRING Src).  A function which takes the PWSTR is RtlUnicodeStringXxxString, e.g. NTSTATUS RtlUnicodeStringCatString(PUNICODE_STRING Dest, PCWSTR Src).

I would suggest that you update your source as applicable to use the new UNICODE_STRING safe functions.  I have found that in KMDF it makes for simpler and more readable code.  Since the implemenation is contained within the header itself (or in the supplied lib), you can use these functions all the way back to Windows 2000.


Comments (2)

  1. One of the goals of KMDF was to use clear and concise types in our parameters and structures so that