在 Windows 内核开发中,字符串并非像 C 中使用的是一个 \0 结尾的字符数组,取而代之的是一个结构体,该结构体储存了指向字符的指针和字符的长度。因为没有了 \0,很多 C 语言库函数也无法使用了,但不用担心,Windows 提供了很多操作这种字符串的函数。见如下示例:

初始化、拷贝、拼接字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{
// 使用字符串常量初始化字符串
UNICODE_STRING src;
RtlInitUnicodeString(&src, L "Hello My First Driver..\r\n");

// 用一个缓冲区初始化字符串
UNICODE_STRING dst;
WCHAR dst_buf[256];
RtlInitEmptyUnicodeString(&dst, dst_buf, 256 * sizeof( WCHAR));

// Copy 字符串
RtlCopyUnicodeString(&dst, &src);
DbgPrint("src = %wZ\r\ndst = %wZ\r\n", &src, &dst);

// Append 字符串
RtlAppendUnicodeToString(&dst, L "Yes I'm Fine...\r\n");
DbgPrint("Append String dst = %wZ\r\n", &dst);

driver->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}

实现类 C 语言函数 sprintf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{
WCHAR dst_buf[512] = { 0 };
UNICODE_STRING dst;
NTSTATUS status;
UNICODE_STRING file_path =
RTL_CONSTANT_STRING(L "\\??\\c:\\winddk\\7600.16385.1\\inc\\cifs.h" );
USHORT file_size = 1024;

RtlInitEmptyUnicodeString(&dst, dst_buf, 512 * sizeof( WCHAR));

// 实现类 sprintf 的功能
status = RtlStringCbPrintfW(
dst. Buffer,
512 * sizeof( WCHAR),
L "file path = %wZ file size = %d \r\n",
&file_path, file_size);
dst.Length = wcslen(dst.Buffer) * sizeof(WCHAR);

DbgPrint("dst = %wZ\r\n", &dst);

driver->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}

动态分配内存储存字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{
NTSTATUS status;
UNICODE_STRING dst = { 0 };
UNICODE_STRING src = RTL_CONSTANT_STRING(L "Hello My First Driver...\r\n");

// 根据 src 长度给 dst 分配内存
dst.Buffer = (PWCHAR)ExAllocatePoolWithTag(NonPagedPool, src.Length, MEM_TAG);
if (NULL == dst.Buffer)
{
status = STATUS_INSUFFICIENT_RESOURCES;
}

// 指定 dst 字符串的长度
dst.Length = dst.MaximumLength = src.Length;
// 拷贝字符串
RtlCopyUnicodeString(&dst, &src);

// 包装一层 DbgPrint,让其只在 Debug 模式下打印
KdPrint(("ExAllocatePoolWithTag: dst = %wZ\r\n", &dst));

// 释放内存并将字符串指向 NULL,长度置为 0
ExFreePool(dst.Buffer);
dst.Buffer = NULL;
dst.Length = dst.MaximumLength = 0;

driver->DriverUnload = DriverUnload;
return status;
}