Registry DWORD and binary set/get


#1

Hi Jules,

would you consider implementing registry read/write functions for ints and binary data?

On a quick test (except for the QWORD) these functions seem to work:

void WindowsRegistry::setValue (const String& regValuePath, const uint32 value)
{
  const RegistryKeyWrapper key (regValuePath, true);

  if (key.key != 0)
  RegSetValueEx (key.key, key.wideCharValueName, 0, REG_DWORD,
                         (const BYTE*) (&value),
                         (DWORD) sizeof(DWORD));
}

void WindowsRegistry::setValue (const String& regValuePath, const uint64 value)
{
  const RegistryKeyWrapper key (regValuePath, true);

  if (key.key != 0)
  RegSetValueEx (key.key, key.wideCharValueName, 0, REG_QWORD,
                         (const BYTE*) (&value),
                         (DWORD) sizeof(uint64));
}


void WindowsRegistry::setValue (const String& regValuePath, const MemoryBlock& value)
{
  const RegistryKeyWrapper key (regValuePath, true);

  if (key.key != 0)
    RegSetValueEx (key.key, key.wideCharValueName, 0, REG_BINARY,
                           (const BYTE*) value.getData(),
                           (DWORD) value.getSize());
}

uint32 WindowsRegistry::getDataValue (const String& regValuePath, MemoryBlock& value)
{
  jassert(value.getSize() == 0);

  const RegistryKeyWrapper key (regValuePath, false);

  if (key.key != 0)
  {
    WCHAR buffer [2048];
    unsigned long bufferSize = sizeof (buffer);
    DWORD type = REG_SZ;

    if (RegQueryValueEx (key.key, key.wideCharValueName, 0, &type, (LPBYTE) buffer, &bufferSize) == ERROR_SUCCESS)
    {
      value.ensureSize(bufferSize, false);
      value.copyFrom(buffer, 0, bufferSize);
      return type;
     } 
  }

  return REG_NONE;
}

There aren’t int-getValue()s, as this can be done via converting the String-getValue() to ints. Also there are further types I ignored. These could be made accesible by using setDataValue (const String& regValuePath, const MemoryBlock& value, uint32 type = REG_BINARY) instead of the given implementation, though I don’t know how to implement this in the header where windows.h isn’t included (which is why the above code uses uint32 instead of DWORD)

Chris


#2

Seems like a good request!


#3

Hi Jules,

thanks for implementing the int and data set/get functions.

I ran into the need to read from the 64-bit registry from a 32-bit application. This is generally rather easy as in the key’s opening/creating only KEY_WOW64_64KEY needs to be added.
Here are the changes to RegistryKeyWrapper and a example readValue (which is merely a copy of your getValue()):

struct RegistryKeyWrapper
{
  RegistryKeyWrapper (String name, const bool createForWriting, const bool wow64 = false)
    : key (0), wideCharValueName (nullptr)
  {
    HKEY rootKey = 0;

    if (name.startsWithIgnoreCase ("HKEY_CURRENT_USER\\"))    rootKey = HKEY_CURRENT_USER;
    else if (name.startsWithIgnoreCase ("HKEY_LOCAL_MACHINE\\"))  rootKey = HKEY_LOCAL_MACHINE;
    else if (name.startsWithIgnoreCase ("HKEY_CLASSES_ROOT\\"))   rootKey = HKEY_CLASSES_ROOT;

    if (rootKey != 0)
    {
      name = name.substring (name.indexOfChar ('\\') + 1);

      const int lastSlash = name.lastIndexOfChar ('\\');
      valueName = name.substring (lastSlash + 1);
      wideCharValueName = valueName.toWideCharPointer();

      name = name.substring (0, lastSlash);
      const wchar_t* const wideCharName = name.toWideCharPointer();
      DWORD result;

      if (createForWriting)
	  {
		if (wow64)
		{
		  RegCreateKeyEx (rootKey, wideCharName, 0, 0, REG_OPTION_NON_VOLATILE,
		  (KEY_WOW64_64KEY | KEY_WRITE | KEY_QUERY_VALUE), 0, &key, &result);
		}
		else
		{
		  RegCreateKeyEx (rootKey, wideCharName, 0, 0, REG_OPTION_NON_VOLATILE,
		  (KEY_WRITE | KEY_QUERY_VALUE), 0, &key, &result);
		}
	  }
      else
	  {
		if (wow64)
		  RegOpenKeyEx (rootKey, wideCharName, 0, KEY_WOW64_64KEY | KEY_READ, &key);
		else
		  RegOpenKeyEx (rootKey, wideCharName, 0, KEY_READ, &key);
	  }
    }
  }

  ~RegistryKeyWrapper()
  {
    if (key != 0)
      RegCloseKey (key);
  }

  HKEY key;
  const wchar_t* wideCharValueName;
  String valueName;

  JUCE_DECLARE_NON_COPYABLE (RegistryKeyWrapper);
};


String WindowsRegistry::getValueWow64 (const String& regValuePath, const String& defaultValue)
{
  const RegistryKeyWrapper key (regValuePath, false, true);

  if (key.key != 0)
  {
    WCHAR buffer [2048];
    unsigned long bufferSize = sizeof (buffer);
    DWORD type = REG_SZ;

    if (RegQueryValueEx (key.key, key.wideCharValueName, 0, &type, (LPBYTE) buffer, &bufferSize) == ERROR_SUCCESS)
    {
      if (type == REG_SZ)
        return buffer;
      else if (type == REG_DWORD)
        return String ((int) *(DWORD*) buffer);
    }
  }

  return defaultValue;
}

I’m not sure how to implement this the best way (using the same setValue/getValue is probably better) and whether it needs some checking to avoid calling from a 32-bit Windows.

Could you have a look at this?

Thanks,
Chris


#4

Thanks, I’ll take a look!


#5

I would like to request functions for reading REG_QWORD values from the registry, not just REG_DWORD values. I.e. a uint64 binary reader together with the already-existing uint32 reader. This should be fairly easy to add, right?


#6

Probably easy enough - why not have a go!