UNICODE_STRING详解及注意事项

 

  • UNICODE_STRING的结构
typedef struct _UNICODE_STRING {
	USHORT Length;   //有效字符串的长度(字节数)
	USHORT MaximumLength; //字符串的最大长度(字节数)
	PWSTR Buffer; //指向字符串的指针
}UNICODE_STRING,*PUNICODE_STRING;

注意事项:

1.Buffer指向的字符串不以'\0'为结束符,其长度大小仅取决于Length的大小(Length<=MaximumLength)。

2.不建议使用wcscp、wcscmp等函数对Buffer进行操作,因为这些函数默认处理以'\0'结尾的字符串,可能缺漏。

3.因为Length和MaximumLength均为USHORT,占2个字节,所以MaximumLength和Length的范围是[0,65535]。

4.MaximumLength和Length表示的是字节数,是字符数的2倍。

5.Buffer指针必须指向有效内存!

 

  • 初始化UNICODE_STRING

1.

UNICODE_STRING test={0};//填0初始化
WCHAR* buf=L"I am buf";//定义宽字节字符串
RtlInitUnicodeString(&test,buf);//初始化

首先所有成员均被置0。接着RtlInitUnicodeString做了3件事:

1.将Buffer指针指向静态常量区的字符串"I am buf"(更改指针,非深拷贝,指向常量区所以不能使用

RtlCopyUnicodeString、RtlAppendUnicodeToString等函数直接对其操作,否则可能引发蓝屏)。

2.修改Length为wcslen(buf)*sizeof(WCHAR)。

3.修改MaximumLength为(wcslen(buf)+1)*sizeof(WCHAR)。

2.

UNICODE_STRING test;
DECLARE_CONST_UNICODE_STRING(test,L"I am buf");
UNICODE_STRING test=RL_CONSTANT_STRING(L"first:Hello ,my salary!");

将buffer指针指向宽字符串常量,具体操作和上面描述的一致。同样需要注意指向的字符串位于常量区。

3.

UNICODE_STRING test={0};//填0初始化
WCHAR buf[9]=L"I am buf";//定义宽字节字符串
test.Buffer=buf;
test.Length=sizeof(buf);
test.MaximumLength=sizeof(buf);//wcslen(L"I am buf")*sizeof(WCHAR);

通过栈上字符串初始化UNICODE_STRING,这种情况下Length和MaximumLength的大小需要自己设置,否则容易出错。

4.

UNICODE_STRING test = {0};
ULONG Length = (wcslen(L"I am Buf") + 1)*sizeof(WCHAR);
test.Buffer = ExAllocatePoolWithTag(PagedPool, 64*sizeof(WCHAR), 'ALAL');//注意这里不是双引号
if (ustrTest.Buffer == NULL)
{
	return;
}
RtlZeroMemory(test.Buffer, 64*sizeof(WCHAR));
wcscpy(test.Buffer, L"I am Buf");//拷贝
test.Length = Length;
test.MaximumLength = 64*sizeof(WCHAR);
ExFreePool(test.Buffer);//释放内存

通过堆区申请内存并拷贝字符串至Buffer来初始化。代码中的ExAllocatePoolWithTag可用ExAllocatePool函数代替但不推荐这样做,因为在WDM.H(NTDDK.H)中声明了内存分配函数无条件受预处理宏POOL_TAGGING控制(POOL_TAGGING被无条件的定义)。因此,即便是调用的ExAllocatePool函数,实际执行的却是:ExAllocatePoolWithTag,其加入的标签为"mdW",指明是WDM的内存块。若强行关闭POOL_TAGGING宏再去调用ExAllocatePool,实际执行的依然是ExAllocatePoolWithTag,带标签"enoN"。因此,建议在分配内存时,直接调用ExAllocatePoolWithTag并加上一个自定义的标签,同时也方便调试时辨认并定位。

 

  • 拼接UNICODE_STRING
RtlAppenUnicodeToString(&uStr,str);//将str拼接至uStr

1.要保证uStr的Buffer长度充足。

2.str是WCHAR*类型,字符串以'\0'结尾。

RtlAppendUnicodeStringToString(&uStr1,&uStr2);//uStr2拼接至uStr1尾部

这种拼接的2个参数uStr1和uStr2均为UNICODE_STRING类型。

 

  • 拷贝UNICODE_STRING
//初始化 UnicodeString1
UNICODE_STRING UnicodeString1;
RtlInitUnicodeString(&UnicodeString1, L"Hello World");
//初始化 UnicodeString2
UNICODE_STRING UnicodeString2 = { 0 };
UnicodeString2.Buffer = (PWSTR)ExAllocatePool(PagedPool, BUFFER_SIZE);
UnicodeString2.MaximumLength = BUFFER_SIZE;
//将初始化 UnicodeString2 拷贝到 UnicodeString1
RtlCopyUnicodeString(&UnicodeString2, &UnicodeString1);
//分别显示 UnicodeString1 和 UnicodeString2
DbgPrint("UnicodeString1:%wZ\n", &UnicodeString1);
DbgPrint("UnicodeString2:%wZ\n", &UnicodeString2);
//销毁 UnicodeString2
//注意!!UnicodeString1 不用销毁
RtlFreeUnicodeString(&UnicodeString2);

                                                                                -----来自张帆<<Windows驱动开发技术详解>>

  • 比较UNICODE_STRING
//初始化 UnicodeString1
UNICODE_STRING UnicodeString1;
RtlInitUnicodeString(&UnicodeString1, L"Hello World");
//初始化 UnicodeString2
UNICODE_STRING UnicodeString2;
RtlInitUnicodeString(&UnicodeString1, L"Hello");
if (RtlEqualUnicodeString(&UnicodeString1, &UnicodeString2, TRUE))//最后一个参数含义为是否无视大小写
DbgPrint("UnicodeString1 and UnicodeString2 are equal\n");
else
DbgPrint("UnicodeString1 and UnicodeString2 are NOT equal\n");
}

                                                                                -----来自张帆<<Windows驱动开发技术详解>>
 

  • ANSI_STRING、UNICODE_STRING、CHAR*、WCHAR*相互转换
//ANSI_STRING 字符串与 UNICODE_STRING 字符串相互转换
VOID StringConverTest()
{
	//(1)将 UNICODE_STRING 字符串转换成 ANSI_STRING 字符串
	//初始化 UnicodeString1
	UNICODE_STRING UnicodeString1;
	RtlInitUnicodeString(&UnicodeString1,L"Hello World");
	ANSI_STRING AnsiString1;
	NTSTATUS nStatus = RtlUnicodeStringToAnsiString(&AnsiString1,&UnicodeString1,TRUE);
	if ( NT_SUCCESS(nStatus))
	{
		KdPrint(("Conver succussfully!\n"));
		KdPrint(("Result:%Z\n",&AnsiString1));
	}
	else


	{
			KdPrint(("Conver unsuccessfully!\n"));
	}
	//销毁 AnsiString1
	RtlFreeAnsiString(&AnsiString1);
	//(2)将 ANSI_STRING 字符串转换成 UNICODE_STRING 字符串
	//初始化 AnsiString2
	ANSI_STRING AnsiString2;
	RtlInitString(&AnsiString2,"Hello World");
	UNICODE_STRING UnicodeString2;
	nStatus = RtlAnsiStringToUnicodeString(&UnicodeString2,&AnsiString2,TRUE);
	if ( NT_SUCCESS(nStatus))
	{
		KdPrint(("Conver succussfully!\n"));
		KdPrint(("Result:%wZ\n",&UnicodeString2));
	}
	else
	{
		KdPrint(("Conver unsuccessfully!\n"));
	}
	//销毁 UnicodeString2
	RtlFreeUnicodeString(&UnicodeString2);
}

 

//UNICODE_STRINGz 转换为 CHAR*
//输入 UNICODE_STRING 的指针,输出窄字符串,BUFFER 需要已经分配好空间
VOID UnicodeToChar(PUNICODE_STRING dst, char *src)
{
	ANSI_STRING string;
	RtlUnicodeStringToAnsiString(&string,dst, TRUE);
	strcpy(src,string.Buffer);
	RtlFreeAnsiString(&string);
}
//WCHAR*转换为 CHAR*
//输入宽字符串首地址,输出窄字符串,BUFFER 需要已经分配好空间
VOID WcharToChar(PWCHAR src, PCHAR dst)
{
	UNICODE_STRING uString;
	ANSI_STRING aString;
	RtlInitUnicodeString(&uString,src);
	RtlUnicodeStringToAnsiString(&aString,&uString,TRUE);
	strcpy(dst,aString.Buffer);
	RtlFreeAnsiString(&aString);
}
//CHAR*转UNICODE_STRING
VOID CharToUnicode(PCHAR src,PUNICODE_STRING dst)
{
	ANSI_STRING aString;
	RtlInitAnsiString(&aString,src);
	RtlAnsiStringToUnicodeString(dst,&aString,FALSE);
}

//CHAR*转 WCHAR*
//输入窄字符串首地址,输出宽字符串,BUFFER 需要已经分配好空间
VOID CharToWchar(PCHAR src, PWCHAR dst)
{
	UNICODE_STRING uString;
	ANSI_STRING aString;
	RtlInitAnsiString(&aString,src);
	RtlAnsiStringToUnicodeString(&uString,&aString,TRUE);
	wcscpy(dst,uString.Buffer);
	RtlFreeUnicodeString(&uString);
}

                                                                               -----来自张帆<<Windows驱动开发技术详解>>
 

 

 

 

 

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值