c++ 使用Windows API读写Windows注册表

edqdpe6u  于 2023-01-28  发布在  Windows
关注(0)|答案(1)|浏览(355)

我正在尝试写入和读取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);

阅读:

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);

写入似乎工作正常,至少在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

但这没有用

    • 更新**

首先,谢谢你的回答,我现在对这件事有了一点了解。不幸的是,我仍然无法成功地读取字符串。
下面是根据以下答案组合的测试示例:

HKEY registry_key;
LPCTSTR sk = "SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting";

// open registry key
auto openRes = RegOpenKey(HKEY_CURRENT_USER, sk, &registry_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);
}

再次写入可以正常工作(在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);
}

我发现调用RegGetValueA时应该使用

RRF_NOEXPAND | RRF_RT_REG_EXPAND_SZ

flag,看起来很奇怪,但是在定义它的头文件中有描述,所以我猜它是正确的。

RRF_RT_REG_EXPAND_SZ

发生错误87错误无效参数。

c90pui9n

c90pui9n1#

在写作方面:
std::string使用char元素,但TCHARMap到charwchar_t,具体取决于您的代码是否使用定义的UNICODE进行编译。
TEXT()宏只能用于 * 编译时文本 *,不能用于 * 运行时数据 *。TEXT(path.c_str())是无效的类型转换,即使启用UNICODE也无法编译。
显然,您正在处理char数据,因此应该使用基于char的API函数,而不是基于TCHAR的函数。
您也没有遵守RegSetValueEx()最重要的规则之一:
对于基于字符串的类型(如REG_SZ),字符串必须以null结尾。对于REG_MULTI_SZ数据类型,字符串必须以两个null字符结尾... lpData参数所指向的信息的大小(以字节为单位)。如果数据类型为REG_SZ、REG_EXPAND_SZ或REG_MULTI_SZ,则cbData必须包括终止null字符的大小
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);

在阅读方面:
您收到错误是因为您没有告诉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);

或者:

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);
}
    • UPDATE**:您的新代码失败,因为您引入了新的错误。

您正在使用适用于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);
}
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);
}

另一方面,当您必须进行多个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);
}

相关问题