写作&使用 Windows API 读取 Windows 注册表 [英] Writing & reading to windows registry with windows API

查看:32
本文介绍了写作&使用 Windows API 读取 Windows 注册表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从 Windows 寄存器中写入和读取:

I am trying to write&read from the windows register:

写作:

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 中看起来不错.

Writing appears to work fine, at least it looks fine in regedit.exe.

读取失败,ERROR_INVALID_PARAMETER = 87.如果我将 RF_RT_REG_EXPAND_SZ 更改为 RRF_RT_ANY,它可以在调试模式下工作,但在发布时仍然失败,错误代码为 ERROR_MORE_DATA = 234.我试过:

Reading fails with ERROR_INVALID_PARAMETER = 87. If I change RF_RT_REG_EXPAND_SZ to RRF_RT_ANY, it works in debug mode, but still fails in release with error code ERROR_MORE_DATA = 234. I tried:

std::string path = "c:\\";
path = path + "\0"  (it should be null terminated anyway

但是没用

更新

首先,感谢您的回答,我现在对这件事有了一些了解.不幸的是,我仍然无法成功读取字符串.

First of all, thanks for answers, I understand the thing a little better now. Unfortunately, I am still unable to read the string successfully.

这是结合以下答案的测试示例:

Here is the test example combined from the answer below:

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.

Writing again works fine (checked in regedit, and the return error code). On the other hand, reading the size of string register sets the size to 0 and returns error code 87 = ERROR_INVALID_PARAMETER.

显然,我仍然缺少一些东西.(项目设置为多字节字符集)

Apparently, I am still missing something. (the project is set to multy-byte character set)

解决方案

修复以下答案提出的问题后,以下代码对我有用:

After fixing things proposed by the answers below, the following code worked for me:

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

我发现,应该使用

RRF_NOEXPAND | RRF_RT_REG_EXPAND_SZ 

标志,看起来很奇怪,但在定义它的标题中进行了描述,所以我猜它是正确的.如果只使用

flag, which appears strange, but is described in header where it is defined, so I guess it is correct. If using only

RRF_RT_REG_EXPAND_SZ

发生错误 87 ERROR_INVALID_PARAMETER.

error 87 occurs ERROR_INVALID_PARAMETER.

推荐答案

在写作方面:

std::string 使用 char 元素,但 TCHAR 映射到 charwchar_t 取决于您的代码是否使用定义的 UNICODE 编译.

std::string uses char elements, but TCHAR maps to either char or wchar_t depending on whether your code is compiled with UNICODE defined or not.

TEXT() 宏仅适用于编译时文字,不能与运行时数据一起使用.TEXT(path.c_str()) 是一个无效的类型转换,如果启用 UNICODE 甚至不会编译.

The TEXT() macro only works with compile-time literals, you can't use it with runtime data. TEXT(path.c_str()) is an invalid type-cast, and won't even compile if UNICODE is enabled.

您显然正在使用 char 数据,因此您应该使用基于 char 的 API 函数而不是基于 TCHAR 的函数.

You are clearly working with char data, so you should be using the char-based API functions instead of the TCHAR-based functions.

您也没有遵循 RegSetValueEx() 最重要的规则之一:

You are also not following one of the most important rules of RegSetValueEx():

对于基于字符串的类型,例如 REG_SZ,字符串必须以空字符结尾.对于 REG_MULTI_SZ 数据类型,字符串必须以两个空字符结尾... lpData 参数指向的信息的大小,以字节为单位.如果数据类型为 REG_SZ、REG_EXPAND_SZ 或 REG_MULTI_SZ,则 cbData 必须包含一个或多个终止空字符的大小.

For string-based types, such as REG_SZ, the string must be null-terminated. With the REG_MULTI_SZ data type, the string must be terminated with two null characters... The size of the information pointed to by the lpData parameter, in bytes. If the data is of type REG_SZ, REG_EXPAND_SZ, or REG_MULTI_SZ, cbData must include the size of the terminating null character or characters.

std::string::c_str() 返回一个指向空终止数据的指针,但在报告写入注册表的数据大小时不包括空终止符.RegGetValue() 知道如何处理这个错误,但 RegGetValueEx() 不知道.您可能不是唯一读取过该值的人,因此请确保正确包含空终止符.

std::string::c_str() returns a pointer to null-terminated data, but you are not including the null terminator when reporting the size of the data you are writing to the Registry. RegGetValue() knows how to deal with that mistake, but RegGetValueEx() does not. You might not be the only person to ever read the value, so make sure you include the null terminator properly.

试试这个:

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 的大小(以字节为单位).

You are getting errors because you are not telling RegGetValue() how large your str_data buffer is. You have to set your size variable to the size of str_data, in bytes, before you pass it in.

试试这个:

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:您的新代码失败,因为您引入了新的错误.

UPDATE: your new code fails because you have introduced new bugs.

您正在使用适用于 16 位应用程序的旧注册表功能.您需要使用RegOpenKeyEx/RegCreateKeyEx 而不是RegOpenKey/RegCreateKey,然后您可以只指定特定的访问权限您实际需要的权限(创建子项、设置值、读取值等).更好的是,RegCreateKeyEx() 会为您创建缺失的密钥,因此您无需单独手动打开父密钥来创建新的子密钥.

You are using legacy Registry functions that are meant for 16bit apps. You need to use RegOpenKeyEx/RegCreateKeyEx instead of RegOpenKey/RegCreateKey, and then you can specify only the specific access rights that you actually need (create subkeys, set values, read values, etc). Even better, RegCreateKeyEx() creates missing keys for you, so you don't need to manually open a parent key separately just to create a new subkey.

此外,您将 HKEY_LOCAL_MACHINE 更改为 HKEY_CURRENT_USER,但不一致.您的某些步骤使用一个根,其他步骤使用另一个根.您无法读回您正在写入的值,因为您读取的不是您写入的同一个键.

Also, you changed HKEY_LOCAL_MACHINE to HKEY_CURRENT_USER, but not consistently. Some of your steps use one root, other steps use the other root. You are not able to read back the value you are writing because you are not reading from the same key you wrote to.

试试这个:

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 调用来读取一个值(即查询大小,然后查询数据)时,你应该先显式地打开父键:

On the other hand, when you have to make multiple API calls to read a value (ie, to query the size, then query the data), you should explicitly open the parent key first:

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

这篇关于写作&amp;使用 Windows API 读取 Windows 注册表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆