RegQueryValueEx每次都返回不同的值
RegQueryValueEx returning a different value every time
我正在尝试读取注册表项值并显示它。我为自己创建了当前要读取的注册表项,并使用regedit:将其值设置为"foo">
HKEY hkey;
DWORD dwret = RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\Classes\foo", NULL, KEY_QUERY_VALUE, &hkey);
if (dwret == ERROR_SUCCESS)
{
TCHAR value[1024] = _T("");
DWORD dwvalue = 1024;
DWORD type = REG_SZ;
RegQueryValueEx(HKEY_CURRENT_USER, L"Software\Classes\test", NULL,&type , (LPBYTE)&value, &dwvalue);
cout << value;
RegCloseKey(hkey);
hkey = NULL;
}
问题是,如果我多次运行代码,我总是会得到不同的输出,下面是摘录:
00CFF5D0
001CF2D8
005EF5B8
0053F5A4
我误解什么了吗?RegQueryValueEx不是应该将键值存储到我的value
中吗?如果是,为什么每次都得到不同的输出?
您的代码显然是为Unicode编译的,因此TCHAR
映射到wchar_t
,RegQueryValueEx()
映射到RegQueryValueExW()
。
但是std::cout
没有用于wchar_t*
指针的operator<<
作为输入,但是它具有用于void*
指针的operator<<
,其打印出指针中包含的存储器地址。
ANY指针可以隐式转换为void*
,所以这就是您实际调用的overator<<
重载,这就是为什么您在输出中看到十六进制数字的原因。
每次运行代码时都会得到不同的值,因为value[]
缓冲区每次都位于不同的内存地址。
为此,您需要:
-
在定义
UNICODE
时使用std::wcout
而不是std::cout
:#ifdef UNICODE wcout << value; #else cout << value; #endif
或者:
#ifdef UNICODE wostream &tcout = wcout; #else ostream &tcout = cout; #endif tcout << value;
-
将
value
缓冲区从wchar_t
转换为char
,例如使用WideCharToMultiByte()
或等效缓冲区,然后使用std::cout
:输出#ifdef UNICODE char temp[1024]; int len = WideCharToMultiByte(CP_ACP, 0, value, -1, temp, sizeof(temp)-1, NULL, NULL); temp[len] = 0; cout << temp; #else cout << value; #endif
-
将
RegQueryValueExA()
与char[]
缓冲器一起使用,而不是将RegQueryValueEx()
与TCHAR[]
缓冲器一起使用。让操作系统为您处理到char[]
的转换:char value[1024]; ... RegQueryValueExA(..., (LPBYTE)&value, ...); ... cout << value;
也就是说,您的代码还有其他几个问题。
-
您使用的是基于
TCHAR
的API,但使用的是硬编码的宽字符串文字。只有当您将项目设置为使用Unicode进行编译(您应该使用Unicode(时,这才会起作用。但是,为了在政治上正确,在TCHAR
API中使用字符串文字时,应该使用TEXT()
宏。TEXT("Software\Classes\foo") TEXT("test") ...
但是,您真的不应该再使用
TCHAR
API了。它们早在早期就被引入,当时Windows还是一个基于ANSI的操作系统,正在迁移到Unicode。TCHAR
帮助开发人员同时支持ANSI和Unicode版本的操作系统。但是那些日子已经一去不复返了。只使用Unicode API,除非您绝对需要ANSI API。忘记TCHAR
的存在吧。 -
你打给
RegQueryValueEx()
的电话全错了。-
在使用
value
缓冲区之前,您没有进行任何错误检查以确保RegQueryValueEx()
确实成功。dwret = RegQueryValueEx(...); if (dwret == ERROR_SUCCESS) ... else ...
-
不能在其
lpValueName
参数中传递密钥路径,只能传递值名称。假设您的foo
密钥具有test
值,则需要传入打开的hkey
,并仅指定"test"
作为值名称:DWORD dwret = RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\Classes\foo"), NULL, KEY_QUERY_VALUE, &hkey); if (dwret == ERROR_SUCCESS) { ... dwret = RegQueryValueEx(hkey, TEXT("test"), ...); ... }
-
您为
lpcbData
参数传入了错误的大小值。该参数以字节表示,但传入的大小以字符表示。由于您的代码是为Unicode编译的,其中sizeof(TCHAR)
是2,这意味着RegQueryValueEx()
只能写入一半的缓冲区。使用sizeof()
获取完整字节大小:DWORD dwvalue = sizeof(value);
-
即使
RegQueryValueEx()
成功,您也没有考虑到返回的字符串可能不会以null终止。对于使用小型手动字符串的简单测试,它可能会以null终止,但在生产代码中,您需要处理null终止符可能不总是存在的可能性。否则,请改用RegGetValue()
,这样可以确保输出中始终存在空终止符,即使它不存在于源数据中。
-
-
无论
RegQueryValueEx()
成功还是失败,您都会将value
缓冲区传递给std::cout
。如果RegQueryValueEx()
失败,缓冲区的内容将是不确定的,并且不能保证是null终止的,所以根本不要使用缓冲区。
试试类似的东西:
HKEY hkey = NULL;
LONG lret = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\Classes\foo", NULL, KEY_QUERY_VALUE, &hkey);
if (lret == ERROR_SUCCESS)
{
WCHAR value[1024] = {};
DWORD dwvalue = sizeof(value);
DWORD type = REG_SZ;
lret = RegQueryValueExW(hkey, L"test", NULL, &type, (LPBYTE)&value, &dwvalue);
if (lret == ERROR_SUCCESS)
{
int len = (dwvalue / sizeof(WCHAR));
if ((len > 0) && (value[len-1] == 0))
--len;
wcout.write(value, len);
/* alternatively:
char temp[1024];
len = WideCharToMultiByte(CP_ACP, 0, value, len, temp, sizeof(temp), NULL, NULL);
cout.write(temp, len);
*/
}
RegCloseKey(hkey);
hkey = NULL;
}
或者:
HKEY hkey = NULL;
LONG lret = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\Classes\foo", NULL, KEY_QUERY_VALUE, &hkey);
if (lret == ERROR_SUCCESS)
{
CHAR value[1024] = {};
DWORD dwvalue = sizeof(value);
DWORD type = REG_SZ;
lret = RegQueryValueExA(hkey, "test", NULL, &type, (LPBYTE)&value, &dwvalue);
if (lret == ERROR_SUCCESS)
{
if ((dwvalue > 0) && (value[dwvalue-1] == 0))
--dwvalue;
cout.write(value, dwvalue);
}
RegCloseKey(hkey);
hkey = NULL;
}
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- 什么时候在C++中返回常量引用是个好主意
- 你能重载对象变量名本身返回的内容吗
- 为什么 Serial.println(<char[]>);返回随机字符?
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 如何获取std::result_of函数的返回类型
- QueryWorkingSet总是返回false
- (C++)分析树以计算返回错误值的简单算术表达式
- 访问者访问变体并返回不同类型时出错
- 如何返回一个类的两个对象相加的结果
- OpenInventor从9.8升级到10.4.2后,GLSL纹理返回零
- lower_bound()返回最后一个元素
- "throw expression code" 1e7 >返回 d 是什么?投掷标准::overflow_error( "too big" ) : d;意味 着?
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- 如何取消对nullptr的屏蔽,返回正确的对象
- 奇怪的结构&GCC&clang(void*返回类型)
- 架构决策:返回std::future还是提供回调
- 从python中调用C++函数并获取返回值
- 矩阵向量乘法(cublasDgemv)返回零
- 为什么模板类中的对象不能返回值