RegGetValueW 返回字符串数据大小不一致
Windows API RegGetValueW 函数的原型如下:
c++LSTATUS RegGetValueW(
[in] HKEY hkey,
[in, optional] LPCWSTR lpSubKey,
[in, optional] LPCWSTR lpValue,
[in, optional] DWORD dwFlags,
[out, optional] LPDWORD pdwType,
[out, optional] PVOID pvData,
[in, out, optional] LPDWORD pcbData
);使用该 API 获取字符串值时,是否传递 pvData 参数会影响 pcbData 输出的值大小。
在注册表 HKEY_CURRENT_USER 下创建一个名为 Test 的字符串值,内容为 abcde。使用如下代码,分别获取字符串的字节数:
c++#include <iostream>
#include <windows.h>
int main()
{
wchar_t data[100];
DWORD cbData = 0;
// pvData 参数为 NULL
if (ERROR_SUCCESS != RegGetValueW(HKEY_CURRENT_USER,
nullptr,
L"Test",
RRF_RT_REG_SZ,
nullptr,
nullptr,
&cbData)) {
throw std::runtime_error("RegGetValueW failed");
}
std::cout << "Value size: " << cbData << " bytes\n";
// pvData 参数不为 NULL
if (ERROR_SUCCESS != RegGetValueW(HKEY_CURRENT_USER,
nullptr,
L"Test",
RRF_RT_REG_SZ,
nullptr,
data,
&cbData)) {
throw std::runtime_error("RegGetValueW failed");
}
std::cout << "Value size: " << cbData << " bytes\n";
}输出结果为:
Value size: 14 bytes
Value size: 12 bytes当 pvData 参数为 NULL 时,获得的字符串数据大小是 14 字节,当 pvData 参数不为 NULL 时,获得的字符串数据大小是 12 字节——前者比后者多了 2 个字节,也就是一个宽字符长度。通读了一遍微软的官方文档,对此现象并没有特别说明,而各个 AI 对此的解释也是不知所云。
一种合理的推测如下:首先,注册表保存了每个字符串值占用的字节长度(含末尾 NULL 字符),但并不保证实际存储的字符串数据必然是 NULL 结尾的;其次,使用 RegGetValueW 获取字符串值类型的数据必须保证是 NULL 结尾的。当 pvData 参数为 NULL 时,RegGetValueW 不会扫描整个字符串,所以不确定注册表保存的字符串数据末尾是否包含 NULL 字符。为了保证 Buffer 大小能足够容纳包含结尾的 NULL,就在输出 pcbData 时,在保存的数据值字节长度上加上一个宽字符的长度,也就是多出来的 2 个字节。当 pvData 参数不为 NULL 时,RegGetValueW 会在复制字符串值的时候检测末尾是否为 NULL,因此得到是真实长度。
| Value | Type | Size (bytes) | Data | |||||
| Test | REG_SZ | 12 | a | b | c | d | e | \0 |
为了证实猜想,用以下代码构造一个末尾不包含 NULL 字符的注册表字符串值:
#include <iostream>
#include <windows.h>
int main()
{
wchar_t testData[] = L"abcdefghijk";
int cutOffLen = 5;
if (ERROR_SUCCESS != RegSetValueExW(HKEY_CURRENT_USER,
L"Test",
0,
REG_SZ,
(BYTE*)testData,
cutOffLen * sizeof(wchar_t))) {
throw std::runtime_error("RegSetValueExW failed");
}
}| Value | Type | Size (bytes) | Data | ||||
| Test | REG_SZ | 10 | a | b | c | d | e |
重新运行上一段代码,输出结果是:
Value size: 12 bytes
Value size: 12 bytes两次输出字节长度一致。Q.E.D.