GpG*_*GpG 1 c++ winapi visual-studio-2017
我正在尝试从 Windows 寄存器中写入和读取:
写作:
std::string path = "c:\\"
LPCTSTR str_data = TEXT(path.c_str());
auto size = static_cast<DWORD>(strlen(str_data));
LONG setRes = RegSetValueEx(*key, TEXT("DumpFolder"), 0, REG_EXPAND_SZ, (LPBYTE)str_data, size);
Run Code Online (Sandbox Code Playgroud)
读:
char str_data[1028];
DWORD keyType;
DWORD size;
auto sk = TEXT("SOFTWARE\\Microsoft\\Windows\\Windows Error reporting\\LocalDumps");
auto status = RegGetValue(HKEY_LOCAL_MACHINE, sk, TEXT("DumpFolder"), RF_RT_REG_EXPAND_SZ, &keyType, str_data, &size);
Run Code Online (Sandbox Code Playgroud)
写入似乎工作正常,至少它在 regedit.exe 中看起来不错。
读取失败,ERROR_INVALID_PARAMETER = 87。如果我将 RF_RT_REG_EXPAND_SZ 更改为 RRF_RT_ANY,它可以在调试模式下工作,但在发布时仍然失败,错误代码为 ERROR_MORE_DATA = 234。我尝试过:
std::string path = "c:\\";
path = path + "\0" (it should be null terminated anyway
Run Code Online (Sandbox Code Playgroud)
但它没有帮助
更新
首先,感谢您的回答,我现在对这件事有了更好的了解。不幸的是,我仍然无法成功读取字符串。
以下是结合以下答案的测试示例:
HKEY registry_key;
LPCTSTR sk = "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting";
// open registry key
auto openRes = RegOpenKey(HKEY_CURRENT_USER, sk, ®istry_key);
// set default dump options
HKEY default_key;
auto createRes = RegCreateKey(registry_key, "LocalDumps", &default_key);
if (createRes != ERROR_SUCCESS) {
auto b = createRes;
}
std::string path = "c:\\";
LONG setRes = RegSetValueExA(default_key, "DumpFolder", 0, REG_EXPAND_SZ, (LPCBYTE)path.c_str(), path.size() + 1);
std::string str_data;
DWORD size = 0;
const char *sak = "SOFTWARE\\Microsoft\\Windows\\Windows Error reporting\\LocalDumps";
auto status = RegGetValueA(HKEY_CURRENT_USER, sak, "DumpFolder", RRF_RT_REG_EXPAND_SZ, NULL, NULL, &size);
if ((status == ERROR_SUCCESS) && (size > 1)) {
str_data.resize(size - 1);
status = RegGetValueA(HKEY_CURRENT_USER, sk, "DumpFolder", RRF_RT_REG_EXPAND_SZ, NULL, &str_data[0], &size);
}
Run Code Online (Sandbox Code Playgroud)
再次写入工作正常(在 regedit 中检查,并返回错误代码)。另一方面,读取字符串寄存器的大小会将大小设置为 0 并返回错误代码 87 = ERROR_INVALID_PARAMETER。
显然,我仍然缺少一些东西。(项目设置为多字节字符集)
解决方案
在修复以下答案提出的问题后,以下代码对我有用:
#include <Windows.h>
#include <string>
#include <iostream>
#define reg_type HKEY_LOCAL_MACHINE
void main() {
const std::string reg_path = "Software\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps";
const std::string dump_folder = "DumpFolder";
const std::string path = "c:\\";
// WRITING
HKEY default_key;
auto status = RegCreateKeyExA(reg_type, reg_path.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_QUERY_VALUE, NULL, &default_key, NULL);
if (status != ERROR_SUCCESS) {
std::cout << "Creating key failed.";
return;
}
status = RegSetValueExA(default_key, dump_folder.c_str(), 0, REG_EXPAND_SZ, (LPCBYTE)path.c_str(), path.size() + 1);
if (status != ERROR_SUCCESS) {
std::cout << "Setting key value failed.";
return;
}
// READING
std::string str_data;
DWORD size = 0;
status = RegGetValueA(default_key, "", dump_folder.c_str(), RRF_NOEXPAND | RRF_RT_REG_EXPAND_SZ, NULL, NULL, &size);
if ((status == ERROR_SUCCESS) && (size > 1)){
str_data.resize(size - 1);
status = RegGetValueA(default_key, "", dump_folder.c_str(), RRF_NOEXPAND | RRF_RT_REG_EXPAND_SZ, NULL, &str_data[0], &size);
std::cout << "Successfully read key value: " << str_data;
} else {
std::cout << "Unable to retrive value. Error: " << status;
}
RegCloseKey(default_key);
}
Run Code Online (Sandbox Code Playgroud)
我发现,应该用一个调用 RegGetValueA
RRF_NOEXPAND | RRF_RT_REG_EXPAND_SZ
Run Code Online (Sandbox Code Playgroud)
标志,这看起来很奇怪,但在定义它的标题中进行了描述,所以我猜它是正确的。如果只使用
RRF_RT_REG_EXPAND_SZ
Run Code Online (Sandbox Code Playgroud)
错误 87 发生 ERROR_INVALID_PARAMETER。
在写作方面:
std::string使用char元素,但TCHAR映射到char或wchar_t取决于您的代码是否使用UNICODE定义编译。
该TEXT()宏仅适用于编译时文字,不能与运行时数据一起使用。 TEXT(path.c_str())是一个无效的类型转换,如果UNICODE启用甚至不会编译。
您显然是在处理char数据,因此您应该使用char-based API 函数而不是TCHAR-based 函数。
您也没有遵循以下最重要的规则之一RegSetValueEx():
对于基于字符串的类型,例如 REG_SZ,该字符串必须以 null 结尾。对于 REG_MULTI_SZ 数据类型,字符串必须以两个空字符结尾... lpData 参数指向的信息的大小,以字节为单位。如果数据是 REG_SZ、REG_EXPAND_SZ 或 REG_MULTI_SZ 类型,则 cbData 必须包括终止空字符的大小。
std::string::c_str()返回一个指向空终止数据的指针,但在报告写入注册表的数据大小时不包括空终止符。 RegGetValue()知道如何处理这个错误,但RegGetValueEx()不知道。您可能不是唯一读取过该值的人,因此请确保正确包含空终止符。
试试这个:
std::string path = "c:\\";
LONG setRes = RegSetValueExA(*key, "DumpFolder", 0, REG_EXPAND_SZ, (LPCBYTE)path.c_str(), path.size()+1);
Run Code Online (Sandbox Code Playgroud)
在阅读方面:
您收到错误是因为您没有告诉RegGetValue()您的str_data缓冲区有多大。在传入之前,您必须将size变量设置为str_data, 以字节为单位的大小。
试试这个:
char str_data[1028];
DWORD size = sizeof(str_data);
DWORD dwFlags = RRF_RT_REG_EXPAND_SZ;
// NOTE: when using RRF_RT_REG_EXPAND_SZ, RRF_NOEXPAND is *required* prior to Windows 8.1!
auto status = RegGetValueA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\Windows Error reporting\\LocalDumps", "DumpFolder", RRF_RT_REG_EXPAND_SZ | RRF_NOEXPAND, NULL, str_data, &size);
Run Code Online (Sandbox Code Playgroud)
或者:
std:string str_data;
DWORD size = 0;
const char *sk = "SOFTWARE\\Microsoft\\Windows\\Windows Error reporting\\LocalDumps";
// NOTE: when using RRF_RT_REG_EXPAND_SZ, RRF_NOEXPAND is *required* prior to Windows 8.1!
const DWORD dwFlags = RRF_RT_REG_EXPAND_SZ | RRF_NOEXPAND;
auto status = RegGetValueA(HKEY_LOCAL_MACHINE, sk, "DumpFolder", dwFlags, NULL, NULL, &size);
if ((status == ERROR_SUCCESS) && (size > 1))
{
str_data.resize(size-1);
status = RegGetValueA(HKEY_LOCAL_MACHINE, sk, "DumpFolder", dwFlags, NULL, &str_data[0], &size);
}
Run Code Online (Sandbox Code Playgroud)
更新:您的新代码失败,因为您引入了新错误。
您正在使用适用于 16 位应用程序的旧注册表功能。您需要使用RegOpenKeyEx/RegCreateKeyEx而不是RegOpenKey/ RegCreateKey,然后您可以仅指定您实际需要的特定访问权限(创建子项、设置值、读取值等)。更好的是,RegCreateKeyEx()为您创建丢失的密钥,因此您无需单独手动打开父密钥来创建新的子密钥。
此外,您更改HKEY_LOCAL_MACHINE为HKEY_CURRENT_USER,但不一致。您的某些步骤使用一个根,其他步骤使用另一个根。您无法读回正在写入的值,因为您读取的不是与写入的键相同。
试试这个:
LPCSTR sk = "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps";
HKEY default_key;
auto status = RegCreateKeyExA(HKEY_LOCAL_MACHINE, sk, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &default_key, NULL);
if (status == ERROR_SUCCESS)
{
std::string path = "c:\\";
status = RegSetValueExA(default_key, "DumpFolder", 0, REG_EXPAND_SZ, (LPCBYTE)path.c_str(), path.size() + 1);
RegCloseKey(default_key);
}
Run Code Online (Sandbox Code Playgroud)
LPCSTR sk = "SOFTWARE\\Microsoft\\Windows\\Windows Error reporting\\LocalDumps";
std::string str_data;
DWORD size = 0;
// NOTE: when using RRF_RT_REG_EXPAND_SZ, RRF_NOEXPAND is *required* prior to Windows 8.1!
const DWORD dwFlags = RRF_RT_REG_EXPAND_SZ | RRF_NOEXPAND;
auto status = RegGetValueA(HKEY_LOCAL_MACHINE, sk, "DumpFolder", dwFlags, NULL, NULL, &size);
if ((status == ERROR_SUCCESS) && (size > 1))
{
str_data.resize(size - 1);
status = RegGetValueA(HKEY_LOCAL_MACHINE, sk, "DumpFolder", dwFlags, NULL, &str_data[0], &size);
}
Run Code Online (Sandbox Code Playgroud)
另一方面,当你必须通过多次 API 调用来读取一个值(即查询大小,然后查询数据)时,你应该先显式打开父键:
const char *sk = "SOFTWARE\\Microsoft\\Windows\\Windows Error reporting\\LocalDumps";
std:string str_data;
HKEY default_key;
auto status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, sk, 0, KEY_QUERY_VALUE, &dumps_key);
if (status == ERROR_SUCCESS)
{
DWORD size = 0;
// NOTE: when using RRF_RT_REG_EXPAND_SZ, RRF_NOEXPAND is *required* prior to Windows 8.1!
const DWORD dwFlags = RRF_RT_REG_EXPAND_SZ | RRF_NOEXPAND;
status = RegGetValueA(default_key, "", "DumpFolder", dwFlags, NULL, NULL, &size);
if ((status == ERROR_SUCCESS) && (size > 1))
{
str_data.resize(size-1);
status = RegGetValueA(default_key, "", "DumpFolder", dwFlags, NULL, &str_data[0], &size);
}
RegCloseKey(default_key);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3048 次 |
| 最近记录: |