WindowsRegistry questions


#1
  1. Why do WindowsRegistry::deleteValue and WindowsRegistry::deleteKey not return a value or a Result?

  2. Could you add a function to delete a Key and all it’s Subkeys (see Microsoft Example)

Thanks,

Rail


#2

Okay… Here’s what I came up with:

/** Deletes a registry value. */
static bool JUCE_CALLTYPE deleteValue (const String& regValuePath, WoW64Mode mode = WoW64_Default);

/** Deletes a registry key (which is registry-talk for 'folder'). */
static bool JUCE_CALLTYPE deleteKey (const String& regKeyPath, WoW64Mode mode = WoW64_Default);

/** Deletes a registry key and all it's subkeys. */
static bool JUCE_CALLTYPE deleteNode (const String& regKeyPath, WoW64Mode mode = WoW64_Default);

Implementation:

 bool JUCE_CALLTYPE WindowsRegistry::deleteValue (const String& regValuePath, WoW64Mode mode)
{
    const RegistryKeyWrapper key (regValuePath, true, (DWORD) mode);

    if (key.key != 0)
        if (RegDeleteValue (key.key, key.wideCharValueName) == ERROR_SUCCESS)
            return true;

    return false;
}

 bool JUCE_CALLTYPE WindowsRegistry::deleteKey (const String& regKeyPath, WoW64Mode mode)
{
    const RegistryKeyWrapper key (regKeyPath, true, (DWORD) mode);

    if (key.key != 0)
        if (RegDeleteKey (key.key, key.wideCharValueName) == ERROR_SUCCESS)
            return true;

    return false;
}

 bool JUCE_CALLTYPE WindowsRegistry:: deleteNode (const String& regKeyPath, WoW64Mode mode)
{
    // First, see if we can delete the key without having
    // to recurse.

    if (deleteKey (regKeyPath, mode))
        return true;

    {

    const RegistryKeyWrapper key (regKeyPath + "\\ZZZZZZZ_DUMMY_02122012", false, mode);    // RegistryKeyWrapper requires a value 
                                                                                            // so we make a fake one which hopefully will never exist

    if (key.key != 0)
        {
        TCHAR    szSubKey[MAX_PATH];
        DWORD    dwSize;
        FILETIME ftWrite;
        LONG     lResult;

        // Enumerate the keys

        dwSize = MAX_PATH;

        lResult = RegEnumKeyEx (key.key, 0, szSubKey, &dwSize, NULL, NULL, NULL, &ftWrite);

        if (lResult == ERROR_SUCCESS)
            {
            String mutableRegKeyPath = regKeyPath;        // need a mutable String

            do {
                mutableRegKeyPath += "\\" + String (szSubKey);

                if (! deleteNode (mutableRegKeyPath, mode))
                    break;

                mutableRegKeyPath = mutableRegKeyPath.upToLastOccurrenceOf ("\\", false, true);

                dwSize = MAX_PATH;

                lResult = RegEnumKeyEx (key.key, 0, szSubKey, &dwSize, NULL, NULL, NULL, &ftWrite);

                } while (lResult == ERROR_SUCCESS);
            }
        }

    }

    // Try again to delete the key.

    return deleteKey (regKeyPath, mode);
}

Rail


#3

Cheers Rail - I’ll take a look at this when I get a moment.


#4

Wow, Microsoft example code can be pretty tortuous! Here’s a version where I’ve tried to strip out all the unnecessary spam - does this still work in your use-case?

bool JUCE_CALLTYPE WindowsRegistry::deleteNode (const String& regKeyPath, WoW64Mode mode)
{
    if (deleteKey (regKeyPath, mode))
        return true;

    {
        // (RegistryKeyWrapper needs a sub-path, so use a dummy one that will be ignored)
        const RegistryKeyWrapper key (regKeyPath + "\\DUMMY_KEY_987654321X", false, mode);

        if (key.key != 0)
        {
            for (;;)
            {
                wchar_t subKey[MAX_PATH + 1] = {};
                DWORD subKeySize = MAX_PATH;

                if (RegEnumKeyEx (key.key, 0, subKey, &subKeySize, nullptr, nullptr, nullptr, nullptr) != ERROR_SUCCESS
                     || ! deleteNode (regKeyPath + "\\" + String (subKey), mode))
                    break;
            }
        }
    }

    return deleteKey (regKeyPath, mode);
}

#5

Perfect :smiley:

I was actually worried about using the dummy value… but it seemed the easiest solution.

Thanks!

Rail


#6

Yeah, perhaps it could be even simpler if we just make sure that deleteKey is itself recursive, e.g.

bool JUCE_CALLTYPE WindowsRegistry::deleteKey (const String& regKeyPath, WoW64Mode mode)
{
    const RegistryKeyWrapper key (regKeyPath, true, (DWORD) mode);

    if (key.key == 0)
        return false;

    if (RegDeleteKey (key.key, key.wideCharValueName) == ERROR_SUCCESS)
        return true;

    for (;;)
    {
        wchar_t subKey[MAX_PATH + 1] = {};
        DWORD subKeySize = MAX_PATH;

        if (RegEnumKeyEx (key.key, 0, subKey, &subKeySize, nullptr, nullptr, nullptr, nullptr) != ERROR_SUCCESS
             || ! deleteKey (regKeyPath + "\\" + String (subKey), mode))
            break;
    }

    return RegDeleteKey (key.key, key.wideCharValueName) == ERROR_SUCCESS;
}

?


#7

Tried that but RegEnumKeyEx() is failing… perhaps because we’re opening in write mode??

Yup… https://msdn.microsoft.com/en-us/library/windows/desktop/ms724878(v=vs.85).aspx

write doesn’t have the KEY_ENUMERATE_SUB_KEYS flag set.

Rail


#8

… and even if I add the flag:

const RegistryKeyWrapper key (regKeyPath, true, (DWORD)(mode | KEY_ENUMERATE_SUB_KEYS));

without the dummy value the key structure is off.

Rail


#10

Hmm. How about

static bool deleteKeyNonRecursive (const String& regKeyPath, WoW64Mode mode)
{
    const RegistryKeyWrapper key (regKeyPath, true, (DWORD) mode);

    return key.key != 0 && RegDeleteKey (key.key, key.wideCharValueName) == ERROR_SUCCESS;
}

bool JUCE_CALLTYPE WindowsRegistry::deleteKey (const String& regKeyPath, WoW64Mode mode)
{
    if (deleteKeyNonRecursive (regKeyPath, mode))
        return true;

    for (const RegistryKeyWrapper key (regKeyPath, false, (DWORD) mode);;)
    {
        wchar_t subKey[MAX_PATH + 1] = {};
        DWORD subKeySize = MAX_PATH;

        if (RegEnumKeyEx (key.key, 0, subKey, &subKeySize, nullptr, nullptr, nullptr, nullptr) != ERROR_SUCCESS
             || ! deleteKey (regKeyPath + "\\" + String (subKey), mode))
            break;
    }

    return deleteKeyNonRecursive (regKeyPath, mode);
}

#11

I haven’t tried that… but it looks like it’ll have the same issues as the previous version where I just set the flag… where the first nested folder is off because of the “value”.

Yeah… with my test call to:

return WindowsRegistry::deleteKey (“HKEY_LOCAL_MACHINE\SOFTWARE\Platinum Samples\Accent”, WindowsRegistry::WoW64_64bit);

I get: HKEY_LOCAL_MACHINE\SOFTWARE\Platinum Samples\Accent\Accent\…

Rail


#12

oh yes, sorry. Surely enough just to add this?

for (const RegistryKeyWrapper key (regKeyPath + "\\", false, (DWORD) mode);;)

#13

Bingo! We have a winner. Now you can mix the KEY_WRITE and the KEY_ENUMERATE_SUB_KEYS flag if you don’t want to split it out… but that’s your call.

Thanks,

Rail


#14

Great, thanks for your help. I’ll leave the RegCreateKeyEx flags the same if this works, and will push it shortly…