Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/win/registry.h" | 5 #include "base/win/registry.h" |
| 6 | 6 |
| 7 #include <shlwapi.h> | 7 #include <shlwapi.h> |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 | 10 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 27 // Registry values are read as BYTE* but can have wchar_t* data whose last | 27 // Registry values are read as BYTE* but can have wchar_t* data whose last |
| 28 // wchar_t is truncated. This function converts the reported |byte_size| to | 28 // wchar_t is truncated. This function converts the reported |byte_size| to |
| 29 // a size in wchar_t that can store a truncated wchar_t if necessary. | 29 // a size in wchar_t that can store a truncated wchar_t if necessary. |
| 30 inline DWORD to_wchar_size(DWORD byte_size) { | 30 inline DWORD to_wchar_size(DWORD byte_size) { |
| 31 return (byte_size + sizeof(wchar_t) - 1) / sizeof(wchar_t); | 31 return (byte_size + sizeof(wchar_t) - 1) / sizeof(wchar_t); |
| 32 } | 32 } |
| 33 | 33 |
| 34 // Mask to pull WOW64 access flags out of REGSAM access. | 34 // Mask to pull WOW64 access flags out of REGSAM access. |
| 35 const REGSAM kWow64AccessMask = KEY_WOW64_32KEY | KEY_WOW64_64KEY; | 35 const REGSAM kWow64AccessMask = KEY_WOW64_32KEY | KEY_WOW64_64KEY; |
| 36 | 36 |
| 37 #if DCHECK_IS_ON() | |
| 38 inline bool isValidRootKey(HKEY key) { | |
| 39 return key == HKEY_CLASSES_ROOT || key == HKEY_CURRENT_USER || | |
| 40 key == HKEY_LOCAL_MACHINE || key == HKEY_USERS || | |
| 41 key == HKEY_PERFORMANCE_DATA || key == HKEY_PERFORMANCE_TEXT || | |
| 42 key == HKEY_PERFORMANCE_NLSTEXT || key == HKEY_CURRENT_CONFIG || | |
| 43 key == HKEY_DYN_DATA || key == HKEY_CURRENT_USER_LOCAL_SETTINGS; | |
| 44 } | |
| 45 #endif // DCHECK_IS_ON() | |
| 46 | |
| 37 } // namespace | 47 } // namespace |
| 38 | 48 |
| 39 // Watches for modifications to a key. | 49 // Watches for modifications to a key. |
| 40 class RegKey::Watcher : public ObjectWatcher::Delegate { | 50 class RegKey::Watcher : public ObjectWatcher::Delegate { |
| 41 public: | 51 public: |
| 42 Watcher() {} | 52 Watcher() {} |
| 43 ~Watcher() override {} | 53 ~Watcher() override {} |
| 44 | 54 |
| 55 Watcher(Watcher&&) = default; | |
| 56 Watcher& operator=(Watcher&&) = default; | |
| 57 | |
| 45 bool StartWatching(HKEY key, const ChangeCallback& callback); | 58 bool StartWatching(HKEY key, const ChangeCallback& callback); |
| 46 | 59 |
| 47 // Implementation of ObjectWatcher::Delegate. | 60 // Implementation of ObjectWatcher::Delegate. |
| 48 void OnObjectSignaled(HANDLE object) override { | 61 void OnObjectSignaled(HANDLE object) override { |
| 49 DCHECK(watch_event_.IsValid() && watch_event_.Get() == object); | 62 DCHECK(watch_event_.IsValid() && watch_event_.Get() == object); |
| 50 ChangeCallback callback = callback_; | 63 ChangeCallback callback = callback_; |
| 51 callback_.Reset(); | 64 callback_.Reset(); |
| 52 callback.Run(); | 65 callback.Run(); |
| 53 } | 66 } |
| 54 | 67 |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 84 | 97 |
| 85 callback_ = callback; | 98 callback_ = callback; |
| 86 return object_watcher_.StartWatchingOnce(watch_event_.Get(), this); | 99 return object_watcher_.StartWatchingOnce(watch_event_.Get(), this); |
| 87 } | 100 } |
| 88 | 101 |
| 89 // RegKey ---------------------------------------------------------------------- | 102 // RegKey ---------------------------------------------------------------------- |
| 90 | 103 |
| 91 RegKey::RegKey() : key_(NULL), wow64access_(0) { | 104 RegKey::RegKey() : key_(NULL), wow64access_(0) { |
| 92 } | 105 } |
| 93 | 106 |
| 94 RegKey::RegKey(HKEY key) : key_(key), wow64access_(0) { | 107 RegKey::RegKey(HKEY rootkey) : key_(rootkey), wow64access_(0) { |
| 108 DCHECK(isValidRootKey(rootkey)); | |
| 95 } | 109 } |
| 96 | 110 |
| 97 RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) | 111 RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) |
| 98 : key_(NULL), | 112 : key_(NULL), |
| 99 wow64access_(0) { | 113 wow64access_(0) { |
| 100 if (rootkey) { | 114 if (rootkey) { |
| 101 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) | 115 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) |
| 102 Create(rootkey, subkey, access); | 116 Create(rootkey, subkey, access); |
| 103 else | 117 else |
| 104 Open(rootkey, subkey, access); | 118 Open(rootkey, subkey, access); |
| 105 } else { | 119 } else { |
| 106 DCHECK(!subkey); | 120 DCHECK(!subkey); |
| 107 wow64access_ = access & kWow64AccessMask; | 121 wow64access_ = access & kWow64AccessMask; |
| 108 } | 122 } |
| 109 } | 123 } |
| 110 | 124 |
| 111 RegKey::~RegKey() { | 125 RegKey::~RegKey() { |
| 112 Close(); | 126 Close(); |
| 113 } | 127 } |
| 114 | 128 |
| 129 RegKey::RegKey(RegKey&&) = default; | |
| 130 | |
| 131 RegKey& RegKey::operator=(RegKey&&) = default; | |
| 132 | |
| 115 LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) { | 133 LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) { |
| 134 DCHECK(isValidRootKey(rootkey)); | |
| 116 DWORD disposition_value; | 135 DWORD disposition_value; |
| 117 return CreateWithDisposition(rootkey, subkey, &disposition_value, access); | 136 return CreateWithDisposition(rootkey, subkey, &disposition_value, access); |
| 118 } | 137 } |
| 119 | 138 |
| 120 LONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey, | 139 LONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey, |
| 121 DWORD* disposition, REGSAM access) { | 140 DWORD* disposition, REGSAM access) { |
| 122 DCHECK(rootkey && subkey && access && disposition); | 141 DCHECK(rootkey && subkey && access && disposition); |
| 142 DCHECK(isValidRootKey(rootkey)); | |
| 123 HKEY subhkey = NULL; | 143 HKEY subhkey = NULL; |
| 124 LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL, | 144 LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL, |
| 125 REG_OPTION_NON_VOLATILE, access, NULL, &subhkey, | 145 REG_OPTION_NON_VOLATILE, access, NULL, &subhkey, |
| 126 disposition); | 146 disposition); |
| 127 if (result == ERROR_SUCCESS) { | 147 if (result == ERROR_SUCCESS) { |
| 128 Close(); | 148 Close(); |
| 129 key_ = subhkey; | 149 key_ = subhkey; |
| 130 wow64access_ = access & kWow64AccessMask; | 150 wow64access_ = access & kWow64AccessMask; |
| 131 } | 151 } |
| 132 | 152 |
| 133 return result; | 153 return result; |
| 134 } | 154 } |
| 135 | 155 |
| 136 LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) { | 156 LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) { |
| 137 DCHECK(name && access); | 157 DCHECK(name && access); |
| 158 DCHECK(key_); | |
|
grt (UTC plus 2)
2017/06/29 08:49:47
i'm not sure about this. when you don't care about
| |
| 138 // After the application has accessed an alternate registry view using one of | 159 // After the application has accessed an alternate registry view using one of |
| 139 // the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent operations | 160 // the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent operations |
| 140 // (create, delete, or open) on child registry keys must explicitly use the | 161 // (create, delete, or open) on child registry keys must explicitly use the |
| 141 // same flag. Otherwise, there can be unexpected behavior. | 162 // same flag. Otherwise, there can be unexpected behavior. |
| 142 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx. | 163 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx. |
| 143 if ((access & kWow64AccessMask) != wow64access_) { | 164 if ((access & kWow64AccessMask) != wow64access_) { |
| 144 NOTREACHED(); | 165 NOTREACHED(); |
| 145 return ERROR_INVALID_PARAMETER; | 166 return ERROR_INVALID_PARAMETER; |
| 146 } | 167 } |
| 147 HKEY subkey = NULL; | 168 HKEY subkey = NULL; |
| 148 LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE, | 169 LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE, |
| 149 access, NULL, &subkey, NULL); | 170 access, NULL, &subkey, NULL); |
| 150 if (result == ERROR_SUCCESS) { | 171 if (result == ERROR_SUCCESS) { |
| 151 Close(); | 172 Close(); |
| 152 key_ = subkey; | 173 key_ = subkey; |
| 153 wow64access_ = access & kWow64AccessMask; | 174 wow64access_ = access & kWow64AccessMask; |
| 154 } | 175 } |
| 155 | 176 |
| 156 return result; | 177 return result; |
| 157 } | 178 } |
| 158 | 179 |
| 159 LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) { | 180 LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) { |
| 160 DCHECK(rootkey && subkey && access); | 181 DCHECK(rootkey && subkey && access); |
| 182 DCHECK(isValidRootKey(rootkey)); | |
| 161 HKEY subhkey = NULL; | 183 HKEY subhkey = NULL; |
| 162 | 184 |
| 163 LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &subhkey); | 185 LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &subhkey); |
| 164 if (result == ERROR_SUCCESS) { | 186 if (result == ERROR_SUCCESS) { |
| 165 Close(); | 187 Close(); |
| 166 key_ = subhkey; | 188 key_ = subhkey; |
| 167 wow64access_ = access & kWow64AccessMask; | 189 wow64access_ = access & kWow64AccessMask; |
| 168 } | 190 } |
| 169 | 191 |
| 170 return result; | 192 return result; |
| 171 } | 193 } |
| 172 | 194 |
| 173 LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) { | 195 LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) { |
| 174 DCHECK(relative_key_name && access); | 196 DCHECK(relative_key_name && access); |
| 197 DCHECK(key_); | |
| 175 // After the application has accessed an alternate registry view using one of | 198 // After the application has accessed an alternate registry view using one of |
| 176 // the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent operations | 199 // the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent operations |
| 177 // (create, delete, or open) on child registry keys must explicitly use the | 200 // (create, delete, or open) on child registry keys must explicitly use the |
| 178 // same flag. Otherwise, there can be unexpected behavior. | 201 // same flag. Otherwise, there can be unexpected behavior. |
| 179 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx. | 202 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx. |
| 180 if ((access & kWow64AccessMask) != wow64access_) { | 203 if ((access & kWow64AccessMask) != wow64access_) { |
| 181 NOTREACHED(); | 204 NOTREACHED(); |
| 182 return ERROR_INVALID_PARAMETER; | 205 return ERROR_INVALID_PARAMETER; |
| 183 } | 206 } |
| 184 HKEY subkey = NULL; | 207 HKEY subkey = NULL; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 195 } | 218 } |
| 196 | 219 |
| 197 void RegKey::Close() { | 220 void RegKey::Close() { |
| 198 if (key_) { | 221 if (key_) { |
| 199 ::RegCloseKey(key_); | 222 ::RegCloseKey(key_); |
| 200 key_ = NULL; | 223 key_ = NULL; |
| 201 wow64access_ = 0; | 224 wow64access_ = 0; |
| 202 } | 225 } |
| 203 } | 226 } |
| 204 | 227 |
| 205 // TODO(wfh): Remove this and other unsafe methods. See http://crbug.com/375400 | |
| 206 void RegKey::Set(HKEY key) { | |
| 207 if (key_ != key) { | |
| 208 Close(); | |
| 209 key_ = key; | |
| 210 } | |
| 211 } | |
| 212 | |
| 213 HKEY RegKey::Take() { | |
| 214 DCHECK_EQ(wow64access_, 0u); | |
| 215 HKEY key = key_; | |
| 216 key_ = NULL; | |
| 217 return key; | |
| 218 } | |
| 219 | |
| 220 bool RegKey::HasValue(const wchar_t* name) const { | 228 bool RegKey::HasValue(const wchar_t* name) const { |
| 229 DCHECK(key_); | |
| 221 return RegQueryValueEx(key_, name, 0, NULL, NULL, NULL) == ERROR_SUCCESS; | 230 return RegQueryValueEx(key_, name, 0, NULL, NULL, NULL) == ERROR_SUCCESS; |
| 222 } | 231 } |
| 223 | 232 |
| 224 DWORD RegKey::GetValueCount() const { | 233 DWORD RegKey::GetValueCount() const { |
| 234 DCHECK(key_); | |
| 225 DWORD count = 0; | 235 DWORD count = 0; |
| 226 LONG result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count, | 236 LONG result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count, |
| 227 NULL, NULL, NULL, NULL); | 237 NULL, NULL, NULL, NULL); |
| 228 return (result == ERROR_SUCCESS) ? count : 0; | 238 return (result == ERROR_SUCCESS) ? count : 0; |
| 229 } | 239 } |
| 230 | 240 |
| 231 LONG RegKey::GetValueNameAt(int index, std::wstring* name) const { | 241 LONG RegKey::GetValueNameAt(int index, std::wstring* name) const { |
| 242 DCHECK(key_); | |
| 232 wchar_t buf[256]; | 243 wchar_t buf[256]; |
| 233 DWORD bufsize = arraysize(buf); | 244 DWORD bufsize = arraysize(buf); |
| 234 LONG r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL, NULL, NULL); | 245 LONG r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL, NULL, NULL); |
| 235 if (r == ERROR_SUCCESS) | 246 if (r == ERROR_SUCCESS) |
| 236 *name = buf; | 247 *name = buf; |
| 237 | 248 |
| 238 return r; | 249 return r; |
| 239 } | 250 } |
| 240 | 251 |
| 241 LONG RegKey::DeleteKey(const wchar_t* name) { | 252 LONG RegKey::DeleteKey(const wchar_t* name) { |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 346 } | 357 } |
| 347 } | 358 } |
| 348 | 359 |
| 349 return result; | 360 return result; |
| 350 } | 361 } |
| 351 | 362 |
| 352 LONG RegKey::ReadValue(const wchar_t* name, | 363 LONG RegKey::ReadValue(const wchar_t* name, |
| 353 void* data, | 364 void* data, |
| 354 DWORD* dsize, | 365 DWORD* dsize, |
| 355 DWORD* dtype) const { | 366 DWORD* dtype) const { |
| 367 DCHECK(key_); | |
| 356 LONG result = RegQueryValueEx(key_, name, 0, dtype, | 368 LONG result = RegQueryValueEx(key_, name, 0, dtype, |
| 357 reinterpret_cast<LPBYTE>(data), dsize); | 369 reinterpret_cast<LPBYTE>(data), dsize); |
| 358 return result; | 370 return result; |
| 359 } | 371 } |
| 360 | 372 |
| 361 LONG RegKey::ReadValues(const wchar_t* name, | 373 LONG RegKey::ReadValues(const wchar_t* name, |
| 362 std::vector<std::wstring>* values) { | 374 std::vector<std::wstring>* values) { |
| 363 values->clear(); | 375 values->clear(); |
| 364 | 376 |
| 365 DWORD type = REG_MULTI_SZ; | 377 DWORD type = REG_MULTI_SZ; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 397 LONG RegKey::WriteValue(const wchar_t * name, const wchar_t* in_value) { | 409 LONG RegKey::WriteValue(const wchar_t * name, const wchar_t* in_value) { |
| 398 return WriteValue(name, in_value, | 410 return WriteValue(name, in_value, |
| 399 static_cast<DWORD>(sizeof(*in_value) * (wcslen(in_value) + 1)), REG_SZ); | 411 static_cast<DWORD>(sizeof(*in_value) * (wcslen(in_value) + 1)), REG_SZ); |
| 400 } | 412 } |
| 401 | 413 |
| 402 LONG RegKey::WriteValue(const wchar_t* name, | 414 LONG RegKey::WriteValue(const wchar_t* name, |
| 403 const void* data, | 415 const void* data, |
| 404 DWORD dsize, | 416 DWORD dsize, |
| 405 DWORD dtype) { | 417 DWORD dtype) { |
| 406 DCHECK(data || !dsize); | 418 DCHECK(data || !dsize); |
| 419 DCHECK(key_); | |
| 407 | 420 |
| 408 LONG result = RegSetValueEx(key_, name, 0, dtype, | 421 LONG result = RegSetValueEx(key_, name, 0, dtype, |
| 409 reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize); | 422 reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize); |
| 410 return result; | 423 return result; |
| 411 } | 424 } |
| 412 | 425 |
| 413 bool RegKey::StartWatching(const ChangeCallback& callback) { | 426 bool RegKey::StartWatching(const ChangeCallback& callback) { |
| 414 if (!key_watcher_) | 427 if (!key_watcher_) |
| 415 key_watcher_.reset(new Watcher()); | 428 key_watcher_.reset(new Watcher()); |
| 416 | 429 |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 614 REGSAM wow64access) { | 627 REGSAM wow64access) { |
| 615 Initialize(root_key, folder_key, wow64access); | 628 Initialize(root_key, folder_key, wow64access); |
| 616 } | 629 } |
| 617 | 630 |
| 618 RegistryKeyIterator::~RegistryKeyIterator() { | 631 RegistryKeyIterator::~RegistryKeyIterator() { |
| 619 if (key_) | 632 if (key_) |
| 620 ::RegCloseKey(key_); | 633 ::RegCloseKey(key_); |
| 621 } | 634 } |
| 622 | 635 |
| 623 DWORD RegistryKeyIterator::SubkeyCount() const { | 636 DWORD RegistryKeyIterator::SubkeyCount() const { |
| 637 DCHECK(key_); | |
| 624 DWORD count = 0; | 638 DWORD count = 0; |
| 625 LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL, | 639 LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL, |
| 626 NULL, NULL, NULL, NULL, NULL); | 640 NULL, NULL, NULL, NULL, NULL); |
| 627 if (result != ERROR_SUCCESS) | 641 if (result != ERROR_SUCCESS) |
| 628 return 0; | 642 return 0; |
| 629 | 643 |
| 630 return count; | 644 return count; |
| 631 } | 645 } |
| 632 | 646 |
| 633 bool RegistryKeyIterator::Valid() const { | 647 bool RegistryKeyIterator::Valid() const { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 672 } else { | 686 } else { |
| 673 index_ = count - 1; | 687 index_ = count - 1; |
| 674 } | 688 } |
| 675 } | 689 } |
| 676 | 690 |
| 677 Read(); | 691 Read(); |
| 678 } | 692 } |
| 679 | 693 |
| 680 } // namespace win | 694 } // namespace win |
| 681 } // namespace base | 695 } // namespace base |
| OLD | NEW |