| Index: base/win/registry.cc
|
| diff --git a/base/win/registry.cc b/base/win/registry.cc
|
| index 7330d08aa277e0ab5a67d84492176556bdd9dde0..deae10fbe95a69f2485e4275c24fd98f6ae35ef3 100644
|
| --- a/base/win/registry.cc
|
| +++ b/base/win/registry.cc
|
| @@ -10,8 +10,7 @@
|
| #include "base/logging.h"
|
| #include "base/strings/string_util.h"
|
| #include "base/threading/thread_restrictions.h"
|
| -
|
| -#pragma comment(lib, "shlwapi.lib") // for SHDeleteKey
|
| +#include "base/win/windows_version.h"
|
|
|
| namespace base {
|
| namespace win {
|
| @@ -30,23 +29,29 @@ inline DWORD to_wchar_size(DWORD byte_size) {
|
| return (byte_size + sizeof(wchar_t) - 1) / sizeof(wchar_t);
|
| }
|
|
|
| +// Mask to pull WOW64 access flags out of REGSAM access.
|
| +const REGSAM kWow64AccessMask = KEY_WOW64_32KEY | KEY_WOW64_64KEY;
|
| +
|
| } // namespace
|
|
|
| // RegKey ----------------------------------------------------------------------
|
|
|
| RegKey::RegKey()
|
| : key_(NULL),
|
| - watch_event_(0) {
|
| + watch_event_(0),
|
| + wow64access_(0) {
|
| }
|
|
|
| RegKey::RegKey(HKEY key)
|
| : key_(key),
|
| - watch_event_(0) {
|
| + watch_event_(0),
|
| + wow64access_(0) {
|
| }
|
|
|
| RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
|
| : key_(NULL),
|
| - watch_event_(0) {
|
| + watch_event_(0),
|
| + wow64access_(0) {
|
| if (rootkey) {
|
| if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
|
| Create(rootkey, subkey, access);
|
| @@ -54,6 +59,7 @@ RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
|
| Open(rootkey, subkey, access);
|
| } else {
|
| DCHECK(!subkey);
|
| + wow64access_ = access & kWow64AccessMask;
|
| }
|
| }
|
|
|
| @@ -76,6 +82,7 @@ LONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
|
| if (result == ERROR_SUCCESS) {
|
| Close();
|
| key_ = subhkey;
|
| + wow64access_ = access & kWow64AccessMask;
|
| }
|
|
|
| return result;
|
| @@ -83,13 +90,21 @@ LONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
|
|
|
| LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
|
| DCHECK(name && access);
|
| + // After the application has accessed an alternate registry view using one of
|
| + // the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent operations
|
| + // (create, delete, or open) on child registry keys must explicitly use the
|
| + // same flag. Otherwise, there can be unexpected behavior.
|
| + // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
|
| + if ((access & kWow64AccessMask) != wow64access_) {
|
| + NOTREACHED();
|
| + return ERROR_INVALID_PARAMETER;
|
| + }
|
| HKEY subkey = NULL;
|
| LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE,
|
| access, NULL, &subkey, NULL);
|
| - if (result == ERROR_SUCCESS) {
|
| - Close();
|
| -
|
| - key_ = subkey;
|
| + if (result == ERROR_SUCCESS) {
|
| + Close();
|
| + key_ = subkey;
|
| }
|
|
|
| return result;
|
| @@ -103,6 +118,7 @@ LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
|
| if (result == ERROR_SUCCESS) {
|
| Close();
|
| key_ = subhkey;
|
| + wow64access_ = access & kWow64AccessMask;
|
| }
|
|
|
| return result;
|
| @@ -110,6 +126,15 @@ LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
|
|
|
| LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) {
|
| DCHECK(relative_key_name && access);
|
| + // After the application has accessed an alternate registry view using one of
|
| + // the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent operations
|
| + // (create, delete, or open) on child registry keys must explicitly use the
|
| + // same flag. Otherwise, there can be unexpected behavior.
|
| + // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
|
| + if ((access & kWow64AccessMask) != wow64access_) {
|
| + NOTREACHED();
|
| + return ERROR_INVALID_PARAMETER;
|
| + }
|
| HKEY subkey = NULL;
|
| LONG result = RegOpenKeyEx(key_, relative_key_name, 0, access, &subkey);
|
|
|
| @@ -127,17 +152,21 @@ void RegKey::Close() {
|
| if (key_) {
|
| ::RegCloseKey(key_);
|
| key_ = NULL;
|
| + wow64access_ = 0;
|
| }
|
| }
|
|
|
| +// TODO(wfh): Remove this and other unsafe methods. See http://crbug.com/375400
|
| void RegKey::Set(HKEY key) {
|
| if (key_ != key) {
|
| Close();
|
| key_ = key;
|
| + wow64access_ = 0;
|
| }
|
| }
|
|
|
| HKEY RegKey::Take() {
|
| + DCHECK(wow64access_ == 0);
|
| StopWatching();
|
| HKEY key = key_;
|
| key_ = NULL;
|
| @@ -168,8 +197,43 @@ LONG RegKey::GetValueNameAt(int index, std::wstring* name) const {
|
| LONG RegKey::DeleteKey(const wchar_t* name) {
|
| DCHECK(key_);
|
| DCHECK(name);
|
| - LONG result = SHDeleteKey(key_, name);
|
| - return result;
|
| + HKEY subkey = NULL;
|
| +
|
| + // Verify the key exists before attempting delete to replicate previous
|
| + // behavior.
|
| + LONG result =
|
| + RegOpenKeyEx(key_, name, 0, READ_CONTROL | wow64access_, &subkey);
|
| + if (result != ERROR_SUCCESS)
|
| + return result;
|
| + RegCloseKey(subkey);
|
| +
|
| + return RegDelRecurse(key_, std::wstring(name), wow64access_);
|
| +}
|
| +
|
| +LONG RegKey::DeleteEmptyKey(const wchar_t* name) {
|
| + DCHECK(key_);
|
| + DCHECK(name);
|
| +
|
| + HKEY target_key = NULL;
|
| + LONG result = RegOpenKeyEx(key_, name, 0, KEY_READ | wow64access_,
|
| + &target_key);
|
| +
|
| + if (result != ERROR_SUCCESS)
|
| + return result;
|
| +
|
| + DWORD count = 0;
|
| + result = RegQueryInfoKey(target_key, NULL, 0, NULL, NULL, NULL, NULL, &count,
|
| + NULL, NULL, NULL, NULL);
|
| +
|
| + RegCloseKey(target_key);
|
| +
|
| + if (result != ERROR_SUCCESS)
|
| + return result;
|
| +
|
| + if (count == 0)
|
| + return RegDeleteKeyExWrapper(key_, name, wow64access_, 0);
|
| +
|
| + return ERROR_DIR_NOT_EMPTY;
|
| }
|
|
|
| LONG RegKey::DeleteValue(const wchar_t* value_name) {
|
| @@ -342,6 +406,83 @@ LONG RegKey::StopWatching() {
|
| return result;
|
| }
|
|
|
| +// static
|
| +LONG RegKey::RegDeleteKeyExWrapper(HKEY hKey,
|
| + const wchar_t* lpSubKey,
|
| + REGSAM samDesired,
|
| + DWORD Reserved) {
|
| + typedef LSTATUS(WINAPI* RegDeleteKeyExPtr)(HKEY, LPCWSTR, REGSAM, DWORD);
|
| +
|
| + RegDeleteKeyExPtr reg_delete_key_ex_func =
|
| + reinterpret_cast<RegDeleteKeyExPtr>(
|
| + GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegDeleteKeyExW"));
|
| +
|
| + if (reg_delete_key_ex_func)
|
| + return reg_delete_key_ex_func(hKey, lpSubKey, samDesired, Reserved);
|
| +
|
| + // Windows XP does not support RegDeleteKeyEx, so fallback to RegDeleteKey.
|
| + return RegDeleteKey(hKey, lpSubKey);
|
| +}
|
| +
|
| +// static
|
| +LONG RegKey::RegDelRecurse(HKEY root_key,
|
| + const std::wstring& name,
|
| + REGSAM access) {
|
| + // First, see if the key can be deleted without having to recurse.
|
| + LONG result = RegDeleteKeyExWrapper(root_key, name.c_str(), access, 0);
|
| + if (result == ERROR_SUCCESS)
|
| + return result;
|
| +
|
| + HKEY target_key = NULL;
|
| + result = RegOpenKeyEx(
|
| + root_key, name.c_str(), 0, KEY_ENUMERATE_SUB_KEYS | access, &target_key);
|
| +
|
| + if (result == ERROR_FILE_NOT_FOUND)
|
| + return ERROR_SUCCESS;
|
| + if (result != ERROR_SUCCESS)
|
| + return result;
|
| +
|
| + std::wstring subkey_name(name);
|
| +
|
| + // Check for an ending slash and add one if it is missing.
|
| + if (!name.empty() && subkey_name[name.length() - 1] != L'\\')
|
| + subkey_name += L"\\";
|
| +
|
| + // Enumerate the keys
|
| + result = ERROR_SUCCESS;
|
| + const DWORD kMaxKeyNameLength = MAX_PATH;
|
| + const size_t base_key_length = subkey_name.length();
|
| + std::wstring key_name;
|
| + while (result == ERROR_SUCCESS) {
|
| + DWORD key_size = kMaxKeyNameLength;
|
| + result = RegEnumKeyEx(target_key,
|
| + 0,
|
| + WriteInto(&key_name, kMaxKeyNameLength),
|
| + &key_size,
|
| + NULL,
|
| + NULL,
|
| + NULL,
|
| + NULL);
|
| +
|
| + if (result != ERROR_SUCCESS)
|
| + break;
|
| +
|
| + key_name.resize(key_size);
|
| + subkey_name.resize(base_key_length);
|
| + subkey_name += key_name;
|
| +
|
| + if (RegDelRecurse(root_key, subkey_name, access) != ERROR_SUCCESS)
|
| + break;
|
| + }
|
| +
|
| + RegCloseKey(target_key);
|
| +
|
| + // Try again to delete the key.
|
| + result = RegDeleteKeyExWrapper(root_key, name.c_str(), access, 0);
|
| +
|
| + return result;
|
| +}
|
| +
|
| // RegistryValueIterator ------------------------------------------------------
|
|
|
| RegistryValueIterator::RegistryValueIterator(HKEY root_key,
|
|
|