UNICODE_STRING 到 wchar_t* 空终止
UNICODE_STRING to wchar_t* null terminated
我想使用来自 UNICODE_STRING
的缓冲区,但似乎我不能通过复制引用直接使用它,因为有时我可以看到字符串中间有空字节, Length
比我在调试器中看到的要大。所以如果我这样做
UNICODE_STRING testStr;
//after being used by some function it has data like this 'bad丣[=12=]more_stuff[=12=]'
wchar_t * wStr = testStr.Buffer;
我会得到 wStr = "bad丣";
有没有办法将其转换为以 null 结尾的有效 wchar_t*
?
A UNICODE_STRING 是一个结构,它存储字符数据及其长度。因此,它允许嵌入 NUL 字符,例如 std::wstring
。
另一方面,C 风格的字符串(例如 wchar_t*
)不存储明确的字符串长度。按照惯例,它以 NUL 字符结尾。它的长度是隐含的。一个推论是,它不能包含嵌入的 NUL 字符。
这意味着您无法在不丢失长度信息的情况下从 UNICODE_STRING
转换为 wchar_t*
。您必须明确地存储长度,连同 wchar_t*
指针,或者建立解释规则,允许重新计算长度(例如,通过将字符序列解释为双空终止字符串)1).
附加信息:
- What is the format of a double-null-terminated string with no strings?
- Why double-null-terminated strings instead of an array of pointers to strings?
1) 调试器会将 wchar_t*
解释为以零结尾的字符串。如果要查看整个序列,则需要使用 format specifier. 显式提供数组大小
A wchar_t*
只是一个指针。除非您告诉调试器(或您将 wchar_t*
传递给的任何函数)实际指向了多少 wchar_t
字符,否则它必须在某处停止,因此它会在遇到的第一个空字符处停止.
UNICODE_STRING::Buffer
不保证以空值终止,但它可以包含嵌入的空值。您必须使用 UNICODE_STRING::Length
字段来了解 Buffer
中有多少 WCHAR
元素,包括嵌入的空值,但不计算结尾的空终止符(如果存在的话)。如果您需要空终止符,请将 Buffer
数据复制到您自己的缓冲区并附加一个终止符。
最简单的方法是使用 std::wstring
,例如:
#include <string>
UNICODE_STRING testStr;
// fill testStr as needed...
std::wstring wStrBuf(testStr.Buffer, testStr.Length / sizeof(WCHAR));
const wchar_t *wStr = wStrBuf.c_str();
嵌入的空值仍将存在,但 c_str()
将为您附加尾随的空值终止符。 调试器 仍将仅显示第一个空值之前的数据,除非您告诉调试器数据中 WCHAR
元素的实际数量。
或者,如果您知道 Buffer
数据包含多个由空值分隔的子字符串,您可以选择将 Buffer
数据拆分为一个字符串数组,例如:
#include <string>
#include <vector>
UNICODE_STRING testStr;
// fill testStr as needed...
std::vector<std::wstring> wStrArr;
std::wstring wStr(testStr.Buffer, testStr.Length / sizeof(WCHAR));
std::wstring::size_type startidx = 0;
do
{
std::wstring::size_type idx = wStr.find(L'[=11=]', startidx);
if (idx == std::wstring::npos)
{
if (startidx < wStr.size())
{
if (startidx > 0)
wStrArr.push_back(wStr.substr(startidx));
else
wStrArr.push_back(wStr);
}
break;
}
wStrArr.push_back(wStr.substr(startidx, idx-startidx));
startidx = idx + 1;
}
while (true);
// use wStrArr as needed...
或者:
#include <vector>
#include <algorithm>
UNICODE_STRING testStr;
// fill testStr as needed...
std::vector<std::wstring> wStrArr;
WCHAR *pStart = testStr.Buffer;
WCHAR *pEnd = pStart + (testStr.Length / sizeof(WCHAR));
do
{
WCHAR *pFound = std::find(pStart, pEnd, L'[=12=]');
if (pFound == pEnd)
{
if (pStart < pEnd)
wStrArr.push_back(std::wstring(pStart, pEnd-pStart));
break;
}
wStrArr.push_back(std::wstring(pStart, pFound-pStart));
pStart = pFound + 1;
}
while (true);
// use wStrArr as needed...
我想使用来自 UNICODE_STRING
的缓冲区,但似乎我不能通过复制引用直接使用它,因为有时我可以看到字符串中间有空字节, Length
比我在调试器中看到的要大。所以如果我这样做
UNICODE_STRING testStr;
//after being used by some function it has data like this 'bad丣[=12=]more_stuff[=12=]'
wchar_t * wStr = testStr.Buffer;
我会得到 wStr = "bad丣";
有没有办法将其转换为以 null 结尾的有效 wchar_t*
?
A UNICODE_STRING 是一个结构,它存储字符数据及其长度。因此,它允许嵌入 NUL 字符,例如 std::wstring
。
另一方面,C 风格的字符串(例如 wchar_t*
)不存储明确的字符串长度。按照惯例,它以 NUL 字符结尾。它的长度是隐含的。一个推论是,它不能包含嵌入的 NUL 字符。
这意味着您无法在不丢失长度信息的情况下从 UNICODE_STRING
转换为 wchar_t*
。您必须明确地存储长度,连同 wchar_t*
指针,或者建立解释规则,允许重新计算长度(例如,通过将字符序列解释为双空终止字符串)1).
附加信息:
- What is the format of a double-null-terminated string with no strings?
- Why double-null-terminated strings instead of an array of pointers to strings?
1) 调试器会将
wchar_t*
解释为以零结尾的字符串。如果要查看整个序列,则需要使用 format specifier. 显式提供数组大小
A wchar_t*
只是一个指针。除非您告诉调试器(或您将 wchar_t*
传递给的任何函数)实际指向了多少 wchar_t
字符,否则它必须在某处停止,因此它会在遇到的第一个空字符处停止.
UNICODE_STRING::Buffer
不保证以空值终止,但它可以包含嵌入的空值。您必须使用 UNICODE_STRING::Length
字段来了解 Buffer
中有多少 WCHAR
元素,包括嵌入的空值,但不计算结尾的空终止符(如果存在的话)。如果您需要空终止符,请将 Buffer
数据复制到您自己的缓冲区并附加一个终止符。
最简单的方法是使用 std::wstring
,例如:
#include <string>
UNICODE_STRING testStr;
// fill testStr as needed...
std::wstring wStrBuf(testStr.Buffer, testStr.Length / sizeof(WCHAR));
const wchar_t *wStr = wStrBuf.c_str();
嵌入的空值仍将存在,但 c_str()
将为您附加尾随的空值终止符。 调试器 仍将仅显示第一个空值之前的数据,除非您告诉调试器数据中 WCHAR
元素的实际数量。
或者,如果您知道 Buffer
数据包含多个由空值分隔的子字符串,您可以选择将 Buffer
数据拆分为一个字符串数组,例如:
#include <string>
#include <vector>
UNICODE_STRING testStr;
// fill testStr as needed...
std::vector<std::wstring> wStrArr;
std::wstring wStr(testStr.Buffer, testStr.Length / sizeof(WCHAR));
std::wstring::size_type startidx = 0;
do
{
std::wstring::size_type idx = wStr.find(L'[=11=]', startidx);
if (idx == std::wstring::npos)
{
if (startidx < wStr.size())
{
if (startidx > 0)
wStrArr.push_back(wStr.substr(startidx));
else
wStrArr.push_back(wStr);
}
break;
}
wStrArr.push_back(wStr.substr(startidx, idx-startidx));
startidx = idx + 1;
}
while (true);
// use wStrArr as needed...
或者:
#include <vector>
#include <algorithm>
UNICODE_STRING testStr;
// fill testStr as needed...
std::vector<std::wstring> wStrArr;
WCHAR *pStart = testStr.Buffer;
WCHAR *pEnd = pStart + (testStr.Length / sizeof(WCHAR));
do
{
WCHAR *pFound = std::find(pStart, pEnd, L'[=12=]');
if (pFound == pEnd)
{
if (pStart < pEnd)
wStrArr.push_back(std::wstring(pStart, pEnd-pStart));
break;
}
wStrArr.push_back(std::wstring(pStart, pFound-pStart));
pStart = pFound + 1;
}
while (true);
// use wStrArr as needed...