convert std::string to const BYTE* for RegSetValueEx()

11,898

Solution 1

void function(const std::string& newValue)
{
    HKEY keyHandle;
    if(RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("some key"),0,KEY_ALL_ACCESS,&keyHandle) == ERROR_SUCCESS)
    {

        if (RegSetValueExA(keyHandle, "some value", NULL, REG_SZ, (const BYTE*)newValue.c_str(), newValue.size() + 1)==ERROR_SUCCESS)
        {
                //do something
        }
        RegCloseKey(keyHandle);
    }
}

I removed the part where you convert your string to a wstring, instead you'll be using the ANSI version of RegSetValueEx explicitly.

quote from RegSetValueEx remarks in MSDN:

If dwType is the REG_SZ, REG_MULTI_SZ, or REG_EXPAND_SZ type and the ANSI version of this function is used (either by explicitly calling RegSetValueExA or by not defining UNICODE before including the Windows.h file), the data pointed to by the lpData parameter must be an ANSI character string. The string is converted to Unicode before it is stored in the registry.

Also note that the cbData parameter should include the size of the null termination aswell.

Solution 2

The * 2 is because RegSetValueEx wants to know the number of bytes to write und each char (wchar_t) in a wstring is two bytes wide. So the resulting byte-array has twice the size!

Solution 3

You could also copy the unicode string into a byte array:

LPWSTR pData = L"SampleGrabber";
int dwSize = wcslen(pData)*sizeof(TCHAR);
BYTE slump[256];
memset((void*) slump, 0, 256*sizeof(BYTE));
memcpy((void*) slump, (const void *) pData, dwSize*sizeof(BYTE));

globit = RegSetValueEx(hKey, NULL, 0, REG_SZ, (const BYTE*) slump, dwSize);

If you had the misfortune to be writing code for a WINCE 5.0 device and it lacked part of the regedit API.

Solution 4

Shouldn't it be wNewValue.size()*2+2 ? The +2 for the null character? MSDN says: 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.

Share:
11,898
Emile Vrijdags
Author by

Emile Vrijdags

I'm mostly interested in C++ and audio/multimedia, generally into lower level, more fundamental concepts.

Updated on June 04, 2022

Comments

  • Emile Vrijdags
    Emile Vrijdags over 1 year

    I have a function that gets a std::string. That function calls

    RegSetValueEx

    the 5th parameter is the value of the registry value and expects a variable of type const BYTE*. So I have to convert the std::string to const BYTE* and also give the length of the resulting array as the 6th parameter.

    I have found a way to do it, but it feels ugly and I don't really understand what is going on. Here is a slimmed down version of that function:

    void function(const std::string& newValue)
    {
        HKEY keyHandle;
        if(RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("some key"),0,KEY_ALL_ACCESS,&keyHandle) == ERROR_SUCCESS)
        {
            std::wstring wNewValue;
            wNewValue.assign(newValue.begin(),newValue.end());
    
            if (RegSetValueEx(keyHandle, TEXT("some value"), NULL, REG_SZ, (const BYTE*)(LPCTSTR)(wNewValue.c_str()), wNewValue.size()*2)==ERROR_SUCCESS)
            {
                //do something
            }
            RegCloseKey(keyHandle);
        }
    }
    

    As you can see, i first make a wide string (UNICODE is defined), then use a double cast, and for the length i have to do *2, else it will only set half of the input string.

    Is this form of cast the normal/best way to do it?

    Why the * 2, what would be a better way?

    • xtofl
      xtofl over 14 years
      Since you used a wstring, you know that the underlying type is wchar_t, and c_str() will return wchar_t*. So no need to cast to LPCTSTR.
  • C. K. Young
    C. K. Young over 14 years
    It's more portable to use "sizeof _TCHAR" insetad of 2. :-D
  • Mark Ruzon
    Mark Ruzon over 14 years
    So it would be better to write wNewValue.size()*sizeof(wchar_t) to make it clear what's going on.
  • Adam Rosenfield
    Adam Rosenfield over 14 years
    If you're explicitly using the ANSI version, you shouldn't use the TEXT() macro, which will expand to L"foo" if UNICODE is defined.
  • Emile Vrijdags
    Emile Vrijdags over 14 years
    So as long as I don't use any non-ANSI characters I'm just fine using the ANSI versions of winapi functions? (that seems logical, but I didn't think of that)
  • Idan K
    Idan K over 14 years
    the Win32API functions that expect text are divided to ANSI (ends with A in the function name) and Unicode (ends with W), most of them anyway. so you could use std::string with the A's and std::wstring with the W's.
  • michelson
    michelson over 14 years
    @ejac: your example would not have worked if your input has characters outside of (probably) ASCII anyway since you were doing a bitwise expansion with wNewValue.assign(newValue.begin(), newValue.end()). Remember that wNewValue is a UNICODE character sequence so the bitwise assignment will only work if all of the character points in newValue are valid UNICODE code points. In other words, newValue contains ONLY ISO-8859-1 characters.