Недопустимое значение DWORD в реестре после записи DWORD как REG_DWORD?

#c

#c

Вопрос:

Я почти уверен RegSetSetValueExA , что мои данные, которые я пишу, работают нормально (CONST BYTE*)amp;setValue . Мой setvalue — это a DWORD , и я уже написал в реестр с этим with RegOpenKeyExA , и он работает нормально. Я думаю, что проблема возникает из RegCreateKeyExA -за того, что я создаю свой новый ключ из этого.

Кроме того, REG_DWORD по какой-то причине my требует от меня записи в двоичном формате

https://gyazo.com/e418587d579a3e540656f06a2524901f

Я пробовал смотреть на другие потоки, но проблема каждого, похоже, отличается от моей, потому что они используют RegOpenKeyExA .

 #include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <Windows.h>
#include <cstdio>
#include "Strsafe.h"

// Stolen microsoft error code credits:msdn

void ErrorExit(LPTSTR lpszFunction)
{
    // Retrieve the system error message for the last-error code

    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError();

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)amp;lpMsgBuf,
        0, NULL);

    // Display the error message and exit the process

    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
        (lstrlen((LPCTSTR)lpMsgBuf)   lstrlen((LPCTSTR)lpszFunction)   40) * sizeof(TCHAR));
    StringCchPrintf((LPTSTR)lpDisplayBuf,
        LocalSize(lpDisplayBuf) / sizeof(TCHAR),
        TEXT("%s failed with error %d: %s"),
        lpszFunction, dw, lpMsgBuf);
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);

    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
    ExitProcess(dw);
}

// end of stolen code
int main()
{
    DWORD Disposition = REG_CREATED_NEW_KEY;
    BYTE lpData[32];
    DWORD setValue = 2;
    PHKEY throwAwayKey = 0;
    DWORD lpType = { REG_DWORD };
    DWORD lpcbData = { sizeof(lpData) };
    HKEY hKey = 0;
    char regPath[64] = "Software\Policies\Microsoft\Windows\System";
    char lpValueName[32] = "DisableCMD";

    long RegCKExA = RegCreateKeyExA(HKEY_CURRENT_USER, regPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, amp;hKey, amp;Disposition);
    if (RegCKExA == ERROR_SUCCESS)
    {
        std::cout << "Successfully executed RegCreatKeyExAn";
    }
    else
    {
        std::cout << "An error has occurred while executing RRegCreateKeyExA. Error code: ";
        ErrorExit((LPTSTR)TEXT("RegCreateKeyExA"));
        getchar();
        return EXIT_FAILURE;
    }

    long regQVExA = RegQueryValueExA(hKey, lpValueName, NULL, amp;lpType, (LPBYTE)lpData, amp;lpcbData);

    if (regQVExA == ERROR_SUCCESS)
    {
        std::cout << "Successfully executed RegQueryValueExA and DisableCMD is already on this computer. Press ENTER to continuten";
        getchar();
        return ERROR_SUCCESS; // Difference is it returns here if DisableCMD exists
    }
    else
        std::cout << "DisableCMD not found. Starting creation of DisableCMD registry value. Press ENTER to continue";
    getchar();

    auto regSVExA = RegSetValueExA(hKey, lpValueName, 0, REG_DWORD, (CONST BYTE*)amp;setValue, lpcbData);

    if (regSVExA == ERROR_SUCCESS)
    {
        std::cout << "Successfully executed RegSetValueExAn";
        getchar();
    }
    else
    {
        std::cout << "An error has occurred while executing RegSetValueExA. Error code: ";
        getchar();
        return EXIT_FAILURE;
    }

    RegCloseKey(hKey);

    return  0;
}
  

Комментарии:

1. Прежде чем задавать вопрос здесь, вы должны проверить результат RegSetValueExA вызова.

2. Это приводит к ERROR_SUCCESS?, я собираюсь опубликовать полный код.

3. Это не приводит к ERROR_SUCCESS . Когда я отлаживал ваш код, возвращаемое значение из RegCreateKey 5 равно Access Denied

4. При вызове RegQueryValueExA() , lpcbData возможно, было изменено, но, что более важно, вы не устанавливаете lpcbData значение sizeof(setvalue) при вызове RegSetValueEx() . Кроме того, функции реестра возвращают коды ошибок напрямую, они не сообщают коды ошибок через GetLastError() , поэтому вам нужно изменить ErrorExit() , чтобы использовать код ошибки в качестве входного параметра, а затем передать возвращаемое значение сбойных функций реестра в этот параметр.

5. Изменение его на setValue сработало, спасибо. Я должен был полностью понять параметры. Спасибо, я наконец-то могу заснуть. Раньше это работало, потому что я уже скопировал данные setValue в lpData, поэтому я фактически вычислял setValue.

Ответ №1:

Я переработал ваши функции как WriteDWORD и ReadDWORD . Обратите внимание, что код на самом деле ОЧЕНЬ ПОХОЖ на ваш код. Так почему я беспокоился? Ну, есть одно тонкое отличие в том, что я сделал DWORD типом ввода / вывода вместо массива БАЙТОВ, который у вас был.

 LSTATUS WriteDWORD(LPCSTR lpPath, LPCSTR lpValueName, DWORD dwData)
{
    LSTATUS status = ERROR_SUCCESS;
    HKEY hKey = NULL;
    DWORD dwDisposition = 0;
    status = RegCreateKeyExA(HKEY_CURRENT_USER, lpPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, amp;hKey, amp;dwDisposition);
    if (status != ERROR_SUCCESS)
    {
        return status;
    }

    status = RegSetValueExA(hKey, lpValueName, 0, REG_DWORD, (CONST BYTE*) amp;dwData, sizeof(DWORD));
    RegCloseKey(hKey);
    return status;
}

LSTATUS ReadDWORD(LPCSTR lpPath, LPCSTR lpValueName, DWORD* pdwData)
{
    LSTATUS status = ERROR_SUCCESS;
    HKEY hKey = NULL;
    DWORD dwDisposition = 0;
    status = RegCreateKeyExA(HKEY_CURRENT_USER, lpPath, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, amp;hKey, amp;dwDisposition);
    if (status != ERROR_SUCCESS)
    {
        return status;
    }

    DWORD dwType = 0;
    DWORD cbData = sizeof(DWORD);
    status = RegQueryValueExA(hKey, lpValueName, NULL, amp;dwType, (LPBYTE)pdwData, amp;cbData);
    RegCloseKey(hKey);
    return status;
}
  

Вот пример использования:

 int main()
{
    char szPath[64] = "Software\Policies\Microsoft\Windows\System";
    char szValueName[32] = "DisableCMD";
    WriteDWORD(szPath, szValueName, 1234);
    DWORD dwValue = 0;
    ReadDWORD(szPath, szValueName, amp;dwValue); // dwValue now contains 1234
    return 0;
}
  

Обратите внимание, что я сделал несколько вещей:

  • Я использовал DWORD dwData для автора, но DWORD* pdwData для читателя.
  • Я предварительно инициализировал DWORD cbData = sizeof(DWORD); (т.е. 4)

Надеюсь, это даст вам представление о «двоичной» части вашего вопроса. A DWORD — это 4 байта. Когда вы записали его в реестр, вы указываете ему сохранить a DWORD , который представляет собой 32-битное число или 4 байта. Когда вы считываете его из реестра, для восстановления в вашем приложении вы должны указать указатель на DWORD. Поскольку вы дали ему массив байтов, 32-разрядное число заполнило первые 4 байта предоставленного вами массива. Возможно, вы этого не поняли, но это правильное поведение.

Если вы использовали std::cout , вы обнаружите, что он по-разному реагирует на одни и те же 4 байта из-за перегруженного типа C . Если бы вы использовали DWORD, вы бы увидели свой номер. Однако, поскольку оно есть в вашем байтовом массиве, это будет двоичная тарабарщина.