Cách đọc giá trị từ sổ đăng ký Windows


89

Đã cung cấp khóa cho một số giá trị đăng ký (ví dụ: HKEY_LOCAL_MACHINE \ blah \ blah \ blah \ foo) làm cách nào để tôi:

  1. Xác định một cách an toàn rằng một khóa như vậy tồn tại.
  2. Theo chương trình (tức là với mã) nhận giá trị của nó.

Tôi hoàn toàn không có ý định viết lại bất cứ điều gì cho cơ quan đăng ký (trong suốt thời gian sự nghiệp của tôi nếu tôi có thể giúp nó). Vì vậy, chúng tôi có thể bỏ qua bài giảng về mọi phân tử trong cơ thể tôi phát nổ với tốc độ ánh sáng nếu tôi viết sai cho cơ quan đăng ký.

Thích câu trả lời bằng C ++, nhưng chủ yếu chỉ cần biết câu thần chú đặc biệt của Windows API để nhận được giá trị là gì.

Câu trả lời:


74

Đây là một số mã giả để truy xuất những thứ sau:

  1. Nếu một khóa đăng ký tồn tại
  2. Giá trị mặc định cho khóa đăng ký đó là gì
  3. Giá trị chuỗi là gì
  4. Giá trị DWORD là gì

Mã ví dụ:

Bao gồm phụ thuộc thư viện: Advapi32.lib

HKEY hKey;
LONG lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Perl", 0, KEY_READ, &hKey);
bool bExistsAndSuccess (lRes == ERROR_SUCCESS);
bool bDoesNotExistsSpecifically (lRes == ERROR_FILE_NOT_FOUND);
std::wstring strValueOfBinDir;
std::wstring strKeyDefaultValue;
GetStringRegKey(hKey, L"BinDir", strValueOfBinDir, L"bad");
GetStringRegKey(hKey, L"", strKeyDefaultValue, L"bad");

LONG GetDWORDRegKey(HKEY hKey, const std::wstring &strValueName, DWORD &nValue, DWORD nDefaultValue)
{
    nValue = nDefaultValue;
    DWORD dwBufferSize(sizeof(DWORD));
    DWORD nResult(0);
    LONG nError = ::RegQueryValueExW(hKey,
        strValueName.c_str(),
        0,
        NULL,
        reinterpret_cast<LPBYTE>(&nResult),
        &dwBufferSize);
    if (ERROR_SUCCESS == nError)
    {
        nValue = nResult;
    }
    return nError;
}


LONG GetBoolRegKey(HKEY hKey, const std::wstring &strValueName, bool &bValue, bool bDefaultValue)
{
    DWORD nDefValue((bDefaultValue) ? 1 : 0);
    DWORD nResult(nDefValue);
    LONG nError = GetDWORDRegKey(hKey, strValueName.c_str(), nResult, nDefValue);
    if (ERROR_SUCCESS == nError)
    {
        bValue = (nResult != 0) ? true : false;
    }
    return nError;
}


LONG GetStringRegKey(HKEY hKey, const std::wstring &strValueName, std::wstring &strValue, const std::wstring &strDefaultValue)
{
    strValue = strDefaultValue;
    WCHAR szBuffer[512];
    DWORD dwBufferSize = sizeof(szBuffer);
    ULONG nError;
    nError = RegQueryValueExW(hKey, strValueName.c_str(), 0, NULL, (LPBYTE)szBuffer, &dwBufferSize);
    if (ERROR_SUCCESS == nError)
    {
        strValue = szBuffer;
    }
    return nError;
}

11
Nếu vì một số lý do không thể giải thích được mà điều này dường như không bao giờ tìm thấy khóa thì đó có thể là sự cố 32-bit / 64-bit. Xem stackoverflow.com/q/15084380/482758
mkjeldsen

4
Có thể hữu ích khi đề cập rằng mã của bạn được sử dụng với cái mà Windows gọi là bộ ký tự Unicode. Tôi sẽ thay đổi các cuộc gọi chức năng RegOpenKeyExWRegQueryValueExWđể "bộ ký tự" của họ thuyết bất khả tri tương đương RegOpenKeyExRegQueryValueEx
Hamster

Unicode là mặc định, nó sẽ chỉ thất bại nếu một số một cách rõ ràng thay đổi dự án để đa byte mà không có lý do để làm
paulm

8
Đây là một nhận xét rất muộn, nhưng tôi muốn nhắc tất cả rằng bạn nên đóng khóa đăng ký khi bạn hoàn tất bằng cách gọi RegCloseKey.
Có thể Bud

3
Điều này trông giống như một API C và chúng tôi có 2016. Gói API Win32 phù hợp vào C ++ và khai thác RAII cho các tài nguyên như HKEY.

9
const CString REG_SW_GROUP_I_WANT = _T("SOFTWARE\\My Corporation\\My Package\\Group I want");
const CString REG_KEY_I_WANT= _T("Key Name");

CRegKey regKey;
DWORD   dwValue = 0;

if(ERROR_SUCCESS != regKey.Open(HKEY_LOCAL_MACHINE, REG_SW_GROUP_I_WANT))
{
  m_pobLogger->LogError(_T("CRegKey::Open failed in Method"));
  regKey.Close();
  goto Function_Exit;
}
if( ERROR_SUCCESS != regKey.QueryValue( dwValue, REG_KEY_I_WANT))
{
  m_pobLogger->LogError(_T("CRegKey::QueryValue Failed in Method"));
  regKey.Close();
  goto Function_Exit;
}

// dwValue has the stuff now - use for further processing

1
đi đến? Việc sử dụng hàm tạo CRegKey mà không có đối số là gì? Không cần đại diện cho một khóa đăng ký chưa được khởi tạo. Đây là những gì boost :: tùy chọn dành cho.

1
Bạn cần bao gồm thư viện nào?
Donald Duck

CRegKeyâm thanh như ATL hoặc MFC quốc gia.
kayleeFrye_onDeck 29/10/18

6

Kể từ Windows> = Vista / Server 2008, RegGetValue có sẵn, đây là một chức năng an toàn hơn RegQueryValueEx . Không cần RegOpenKeyEx, RegCloseKeyhoặc NULkiểm tra chấm dứt chuỗi giá trị ( REG_SZ, REG_MULTI_SZ,REG_EXPAND_SZ ).

#include <iostream>
#include <string>
#include <exception>
#include <windows.h>

/*! \brief                          Returns a value from HKLM as string.
    \exception  std::runtime_error  Replace with your error handling.
*/
std::wstring GetStringValueFromHKLM(const std::wstring& regSubKey, const std::wstring& regValue)
{
    size_t bufferSize = 0xFFF; // If too small, will be resized down below.
    std::wstring valueBuf; // Contiguous buffer since C++11.
    valueBuf.resize(bufferSize);
    auto cbData = static_cast<DWORD>(bufferSize * sizeof(wchar_t));
    auto rc = RegGetValueW(
        HKEY_LOCAL_MACHINE,
        regSubKey.c_str(),
        regValue.c_str(),
        RRF_RT_REG_SZ,
        nullptr,
        static_cast<void*>(valueBuf.data()),
        &cbData
    );
    while (rc == ERROR_MORE_DATA)
    {
        // Get a buffer that is big enough.
        cbData /= sizeof(wchar_t);
        if (cbData > static_cast<DWORD>(bufferSize))
        {
            bufferSize = static_cast<size_t>(cbData);
        }
        else
        {
            bufferSize *= 2;
            cbData = static_cast<DWORD>(bufferSize * sizeof(wchar_t));
        }
        valueBuf.resize(bufferSize);
        rc = RegGetValueW(
            HKEY_LOCAL_MACHINE,
            regSubKey.c_str(),
            regValue.c_str(),
            RRF_RT_REG_SZ,
            nullptr,
            static_cast<void*>(valueBuf.data()),
            &cbData
        );
    }
    if (rc == ERROR_SUCCESS)
    {
        cbData /= sizeof(wchar_t);
        valueBuf.resize(static_cast<size_t>(cbData - 1)); // remove end null character
        return valueBuf;
    }
    else
    {
        throw std::runtime_error("Windows system error code: " + std::to_string(rc));
    }
}

int main()
{
    std::wstring regSubKey;
#ifdef _WIN64 // Manually switching between 32bit/64bit for the example. Use dwFlags instead.
    regSubKey = L"SOFTWARE\\WOW6432Node\\Company Name\\Application Name\\";
#else
    regSubKey = L"SOFTWARE\\Company Name\\Application Name\\";
#endif
    std::wstring regValue(L"MyValue");
    std::wstring valueFromRegistry;
    try
    {
        valueFromRegistry = GetStringValueFromHKLM(regSubKey, regValue);
    }
    catch (std::exception& e)
    {
        std::cerr << e.what();
    }
    std::wcout << valueFromRegistry;
}

Tham số của nó dwFlagshỗ trợ cờ để hạn chế kiểu, lấp đầy bộ đệm giá trị bằng các số không khi bị lỗi ( RRF_ZEROONFAILURE) và truy cập đăng ký 32 / 64bit ( RRF_SUBKEY_WOW6464KEY, RRF_SUBKEY_WOW6432KEY) cho các chương trình 64bit.



4

RegQueryValueEx

Điều này cung cấp giá trị nếu nó tồn tại và trả về mã lỗi ERROR_FILE_NOT_FOUND nếu khóa không tồn tại.

(Tôi không thể biết liên kết của mình có hoạt động hay không, nhưng nếu bạn chỉ cần google cho "RegQueryValueEx" thì lần truy cập đầu tiên là tài liệu msdn.)


0

Ứng dụng bảng điều khiển này sẽ liệt kê tất cả các giá trị và dữ liệu của chúng từ khóa đăng ký cho hầu hết các giá trị đăng ký tiềm năng. Có một số cái kỳ lạ không thường được sử dụng. Nếu bạn cần hỗ trợ tất cả chúng, hãy mở rộng từ ví dụ này trong khi tham khảo tài liệu Loại giá trị đăng ký này .

Hãy để đây là nội dung khóa đăng ký bạn có thể nhập từ .reg định dạng tệp:

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\added\subkey]
"String_Value"="hello, world!"
"Binary_Value"=hex:01,01,01,01
"Dword value"=dword:00001224
"QWord val"=hex(b):24,22,12,00,00,00,00,00
"multi-line val"=hex(7):4c,00,69,00,6e,00,65,00,20,00,30,00,00,00,4c,00,69,00,\
  6e,00,65,00,20,00,31,00,00,00,4c,00,69,00,6e,00,65,00,20,00,32,00,00,00,00,\
  00
"expanded_val"=hex(2):25,00,55,00,53,00,45,00,52,00,50,00,52,00,4f,00,46,00,49,\
  00,4c,00,45,00,25,00,5c,00,6e,00,65,00,77,00,5f,00,73,00,74,00,75,00,66,00,\
  66,00,00,00

Bản thân ứng dụng bảng điều khiển:

#include <Windows.h>
#include <iostream>
#include <string>
#include <locale>
#include <vector>
#include <iomanip>

int wmain()
{
    const auto hKey = HKEY_CURRENT_USER;
    constexpr auto lpSubKey = TEXT("added\\subkey");
    auto openedKey = HKEY();
    auto status = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_READ, &openedKey);

    if (status == ERROR_SUCCESS) {
        auto valueCount = static_cast<DWORD>(0);
        auto maxNameLength = static_cast<DWORD>(0);
        auto maxValueLength = static_cast<DWORD>(0);
        status = RegQueryInfoKey(openedKey, NULL, NULL, NULL, NULL, NULL, NULL,
            &valueCount, &maxNameLength, &maxValueLength, NULL, NULL);

        if (status == ERROR_SUCCESS) {
            DWORD type = 0;
            DWORD index = 0;
            std::vector<wchar_t> valueName = std::vector<wchar_t>(maxNameLength + 1);
            std::vector<BYTE> dataBuffer = std::vector<BYTE>(maxValueLength);

            for (DWORD index = 0; index < valueCount; index++) {
                DWORD charCountValueName = static_cast<DWORD>(valueName.size());
                DWORD charBytesData = static_cast<DWORD>(dataBuffer.size());
                status = RegEnumValue(openedKey, index, valueName.data(), &charCountValueName,
                    NULL, &type, dataBuffer.data(), &charBytesData);

                if (type == REG_SZ) {
                    const auto reg_string = reinterpret_cast<wchar_t*>(dataBuffer.data());
                    std::wcout << L"Type: REG_SZ" << std::endl;
                    std::wcout << L"\tName: " << valueName.data() << std::endl;
                    std::wcout << L"\tData : " << reg_string << std::endl;
                }
                else if (type == REG_EXPAND_SZ) {
                    const auto casted = reinterpret_cast<wchar_t*>(dataBuffer.data());
                    TCHAR buffer[32000];
                    ExpandEnvironmentStrings(casted, buffer, 32000);
                    std::wcout << L"Type: REG_EXPAND_SZ" << std::endl;
                    std::wcout << L"\tName: " << valueName.data() << std::endl;
                    std::wcout << L"\tData: " << buffer << std::endl;
                }
                else if (type == REG_MULTI_SZ) {
                    std::vector<std::wstring> lines;
                    const auto str = reinterpret_cast<wchar_t*>(dataBuffer.data());
                    auto line = str;
                    lines.emplace_back(line);
                    for (auto i = 0; i < charBytesData / sizeof(wchar_t) - 1; i++) {
                        const auto c = str[i];
                        if (c == 0) {
                            line = str + i + 1;
                            const auto new_line = reinterpret_cast<wchar_t*>(line);
                            if (wcsnlen_s(new_line, 1024) > 0)
                                lines.emplace_back(new_line);
                        }
                    }
                    std::wcout << L"Type: REG_MULTI_SZ" << std::endl;
                    std::wcout << L"\tName: " << valueName.data() << std::endl;
                    std::wcout << L"\tData: " << std::endl;
                    for (size_t i = 0; i < lines.size(); i++) {
                        std::wcout << L"\t\tLine[" << i + 1 << L"]: " << lines[i] << std::endl;
                    }
                }
                if (type == REG_DWORD) {
                    const auto dword_value = reinterpret_cast<unsigned long*>(dataBuffer.data());
                    std::wcout << L"Type: REG_DWORD" << std::endl;
                    std::wcout << L"\tName: " << valueName.data() << std::endl;
                    std::wcout << L"\tData : " << std::to_wstring(*dword_value) << std::endl;
                }
                else if (type == REG_QWORD) {
                    const auto qword_value = reinterpret_cast<unsigned long long*>(dataBuffer.data());
                    std::wcout << L"Type: REG_DWORD" << std::endl;
                    std::wcout << L"\tName: " << valueName.data() << std::endl;
                    std::wcout << L"\tData : " << std::to_wstring(*qword_value) << std::endl;
                }
                else if (type == REG_BINARY) {
                    std::vector<uint16_t> bins;
                    for (auto i = 0; i < charBytesData; i++) {
                        bins.push_back(static_cast<uint16_t>(dataBuffer[i]));
                    }
                    std::wcout << L"Type: REG_BINARY" << std::endl;
                    std::wcout << L"\tName: " << valueName.data() << std::endl;
                    std::wcout << L"\tData:";
                    for (size_t i = 0; i < bins.size(); i++) {
                        std::wcout << L" " << std::uppercase << std::hex << \
                            std::setw(2) << std::setfill(L'0') << std::to_wstring(bins[i]);
                    }
                    std::wcout << std::endl;
                }
            }
        }
    }

    RegCloseKey(openedKey);
    return 0;
}

Đầu ra bảng điều khiển mong đợi:

Type: REG_SZ
        Name: String_Value
        Data : hello, world!
Type: REG_BINARY
        Name: Binary_Value
        Data: 01 01 01 01
Type: REG_DWORD
        Name: Dword value
        Data : 4644
Type: REG_DWORD
        Name: QWord val
        Data : 1188388
Type: REG_MULTI_SZ
        Name: multi-line val
        Data:
                Line[1]: Line 0
                Line[2]: Line 1
                Line[3]: Line 2
Type: REG_EXPAND_SZ
        Name: expanded_val
        Data: C:\Users\user name\new_stuff

0

Thông thường, khóa thanh ghi và giá trị là hằng số trong chương trình. Nếu vậy, đây là ví dụ về cách đọc giá trị đăng ký DWORD Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem\LongPathsEnabled:

#include <windows.h>

DWORD val;
DWORD dataSize = sizeof(val);
if (ERROR_SUCCESS == RegGetValueA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\FileSystem", "LongPathsEnabled", RRF_RT_DWORD, nullptr /*type not required*/, &val, &dataSize)) {
  printf("Value is %i\n", val);
  // no CloseKey needed because it is a predefined registry key
}
else {
  printf("Error reading.\n");
}

Để thích ứng với các loại giá trị khác, hãy xem https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-reggetvaluea để biết thông số kỹ thuật đầy đủ.


0
#include <windows.h>
#include <map>
#include <string>
#include <stdio.h>
#include <string.h>
#include <tr1/stdint.h>

using namespace std;

void printerr(DWORD dwerror) {
    LPVOID lpMsgBuf;
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dwerror,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
        (LPTSTR) &lpMsgBuf,
        0,
        NULL
    );
    // Process any inserts in lpMsgBuf.
    // ...
    // Display the string.
    if (isOut) {
        fprintf(fout, "%s\n", lpMsgBuf);
    } else {
        printf("%s\n", lpMsgBuf);
    }
    // Free the buffer.
    LocalFree(lpMsgBuf);
}



bool regreadSZ(string& hkey, string& subkey, string& value, string& returnvalue, string& regValueType) {
    char s[128000];
    map<string,HKEY> keys;
    keys["HKEY_CLASSES_ROOT"]=HKEY_CLASSES_ROOT;
    keys["HKEY_CURRENT_CONFIG"]=HKEY_CURRENT_CONFIG; //DID NOT SURVIVE?
    keys["HKEY_CURRENT_USER"]=HKEY_CURRENT_USER;
    keys["HKEY_LOCAL_MACHINE"]=HKEY_LOCAL_MACHINE;
    keys["HKEY_USERS"]=HKEY_USERS;
    HKEY mykey;

    map<string,DWORD> valuetypes;
    valuetypes["REG_SZ"]=REG_SZ;
    valuetypes["REG_EXPAND_SZ"]=REG_EXPAND_SZ;
    valuetypes["REG_MULTI_SZ"]=REG_MULTI_SZ; //probably can't use this.

    LONG retval=RegOpenKeyEx(
        keys[hkey],         // handle to open key
        subkey.c_str(),  // subkey name
        0,   // reserved
        KEY_READ, // security access mask
        &mykey    // handle to open key
    );
    if (ERROR_SUCCESS != retval) {printerr(retval); return false;}
    DWORD slen=128000;
    DWORD valuetype = valuetypes[regValueType];
    retval=RegQueryValueEx(
      mykey,            // handle to key
      value.c_str(),  // value name
      NULL,   // reserved
      (LPDWORD) &valuetype,       // type buffer
      (LPBYTE)s,        // data buffer
      (LPDWORD) &slen      // size of data buffer
    );
    switch(retval) {
        case ERROR_SUCCESS:
            //if (isOut) {
            //    fprintf(fout,"RegQueryValueEx():ERROR_SUCCESS:succeeded.\n");
            //} else {
            //    printf("RegQueryValueEx():ERROR_SUCCESS:succeeded.\n");
            //}
            break;
        case ERROR_MORE_DATA:
            //what do I do now?  data buffer is too small.
            if (isOut) {
                fprintf(fout,"RegQueryValueEx():ERROR_MORE_DATA: need bigger buffer.\n");
            } else {
                printf("RegQueryValueEx():ERROR_MORE_DATA: need bigger buffer.\n");
            }
            return false;
        case ERROR_FILE_NOT_FOUND:
            if (isOut) {
                fprintf(fout,"RegQueryValueEx():ERROR_FILE_NOT_FOUND: registry value does not exist.\n");
            } else {
                printf("RegQueryValueEx():ERROR_FILE_NOT_FOUND: registry value does not exist.\n");
            }
            return false;
        default:
            if (isOut) {
                fprintf(fout,"RegQueryValueEx():unknown error type 0x%lx.\n", retval);
            } else {
                printf("RegQueryValueEx():unknown error type 0x%lx.\n", retval);
            }
            return false;

    }
    retval=RegCloseKey(mykey);
    if (ERROR_SUCCESS != retval) {printerr(retval); return false;}

    returnvalue = s;
    return true;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.