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 <algorithm> | 8 #include <algorithm> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 27 // a size in wchar_t that can store a truncated wchar_t if necessary. | 27 // a size in wchar_t that can store a truncated wchar_t if necessary. |
| 28 inline DWORD to_wchar_size(DWORD byte_size) { | 28 inline DWORD to_wchar_size(DWORD byte_size) { |
| 29 return (byte_size + sizeof(wchar_t) - 1) / sizeof(wchar_t); | 29 return (byte_size + sizeof(wchar_t) - 1) / sizeof(wchar_t); |
| 30 } | 30 } |
| 31 | 31 |
| 32 // Mask to pull WOW64 access flags out of REGSAM access. | 32 // Mask to pull WOW64 access flags out of REGSAM access. |
| 33 const REGSAM kWow64AccessMask = KEY_WOW64_32KEY | KEY_WOW64_64KEY; | 33 const REGSAM kWow64AccessMask = KEY_WOW64_32KEY | KEY_WOW64_64KEY; |
| 34 | 34 |
| 35 } // namespace | 35 } // namespace |
| 36 | 36 |
| 37 // Watches for modifications to a key. | |
| 38 class RegKey::Watcher : public ObjectWatcher::Delegate { | |
| 39 public: | |
| 40 explicit Watcher(RegKey* owner) : owner_(owner) {} | |
| 41 ~Watcher() {} | |
| 42 | |
| 43 bool StartWatching(HKEY key); | |
| 44 | |
| 45 // Implementation of ObjectWatcher::Delegate. | |
| 46 void OnObjectSignaled(HANDLE object) override { | |
| 47 DCHECK(watch_event_.IsValid() && watch_event_.Get() == object); | |
| 48 owner_->OnObjectSignaled(object); | |
| 49 } | |
| 50 | |
| 51 private: | |
| 52 RegKey* owner_; | |
| 53 ScopedHandle watch_event_; | |
| 54 ObjectWatcher object_watcher_; | |
| 55 DISALLOW_COPY_AND_ASSIGN(Watcher); | |
| 56 }; | |
| 57 | |
| 58 bool RegKey::Watcher::StartWatching(HKEY key) { | |
| 59 DCHECK(key); | |
| 60 if (GetVersion() < VERSION_VISTA) { | |
| 61 // It is an error to register multiple times before Vista. | |
| 62 if (watch_event_.IsValid()) | |
| 63 return true; | |
|
eroman
2014/10/10 21:34:35
This doesn't match my expectation of what StartWat
rvargas (doing something else)
2014/10/10 22:22:05
That failures closes watch_event_ (line 81)
| |
| 64 } | |
| 65 | |
| 66 if (!watch_event_.IsValid()) | |
| 67 watch_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL)); | |
| 68 | |
| 69 if (!watch_event_.IsValid()) | |
| 70 return false; | |
| 71 | |
| 72 DWORD filter = REG_NOTIFY_CHANGE_NAME | | |
| 73 REG_NOTIFY_CHANGE_ATTRIBUTES | | |
| 74 REG_NOTIFY_CHANGE_LAST_SET | | |
| 75 REG_NOTIFY_CHANGE_SECURITY; | |
| 76 | |
| 77 // Watch the registry key for a change of value. | |
| 78 LONG result = RegNotifyChangeKeyValue(key, TRUE, filter, watch_event_.Get(), | |
| 79 TRUE); | |
| 80 if (result != ERROR_SUCCESS) { | |
| 81 watch_event_.Close(); | |
| 82 return false; | |
| 83 } | |
| 84 | |
| 85 return object_watcher_.StartWatching(watch_event_.Get(), this); | |
| 86 } | |
| 87 | |
| 37 // RegKey ---------------------------------------------------------------------- | 88 // RegKey ---------------------------------------------------------------------- |
| 38 | 89 |
| 39 RegKey::RegKey() | 90 RegKey::RegKey() : key_(NULL), wow64access_(0) { |
| 40 : key_(NULL), | |
| 41 watch_event_(0), | |
| 42 wow64access_(0) { | |
| 43 } | 91 } |
| 44 | 92 |
| 45 RegKey::RegKey(HKEY key) | 93 RegKey::RegKey(HKEY key) : key_(key), wow64access_(0) { |
| 46 : key_(key), | |
| 47 watch_event_(0), | |
| 48 wow64access_(0) { | |
| 49 } | 94 } |
| 50 | 95 |
| 51 RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) | 96 RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) |
| 52 : key_(NULL), | 97 : key_(NULL), |
| 53 watch_event_(0), | |
| 54 wow64access_(0) { | 98 wow64access_(0) { |
| 55 if (rootkey) { | 99 if (rootkey) { |
| 56 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) | 100 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) |
| 57 Create(rootkey, subkey, access); | 101 Create(rootkey, subkey, access); |
| 58 else | 102 else |
| 59 Open(rootkey, subkey, access); | 103 Open(rootkey, subkey, access); |
| 60 } else { | 104 } else { |
| 61 DCHECK(!subkey); | 105 DCHECK(!subkey); |
| 62 wow64access_ = access & kWow64AccessMask; | 106 wow64access_ = access & kWow64AccessMask; |
| 63 } | 107 } |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 143 // one. | 187 // one. |
| 144 if (result == ERROR_SUCCESS) { | 188 if (result == ERROR_SUCCESS) { |
| 145 Close(); | 189 Close(); |
| 146 key_ = subkey; | 190 key_ = subkey; |
| 147 wow64access_ = access & kWow64AccessMask; | 191 wow64access_ = access & kWow64AccessMask; |
| 148 } | 192 } |
| 149 return result; | 193 return result; |
| 150 } | 194 } |
| 151 | 195 |
| 152 void RegKey::Close() { | 196 void RegKey::Close() { |
| 153 StopWatching(); | |
| 154 if (key_) { | 197 if (key_) { |
| 155 ::RegCloseKey(key_); | 198 ::RegCloseKey(key_); |
| 156 key_ = NULL; | 199 key_ = NULL; |
| 157 wow64access_ = 0; | 200 wow64access_ = 0; |
| 158 } | 201 } |
| 159 } | 202 } |
| 160 | 203 |
| 161 // TODO(wfh): Remove this and other unsafe methods. See http://crbug.com/375400 | 204 // TODO(wfh): Remove this and other unsafe methods. See http://crbug.com/375400 |
| 162 void RegKey::Set(HKEY key) { | 205 void RegKey::Set(HKEY key) { |
| 163 if (key_ != key) { | 206 if (key_ != key) { |
| 164 Close(); | 207 Close(); |
| 165 key_ = key; | 208 key_ = key; |
| 166 } | 209 } |
| 167 } | 210 } |
| 168 | 211 |
| 169 HKEY RegKey::Take() { | 212 HKEY RegKey::Take() { |
| 170 DCHECK(wow64access_ == 0); | 213 DCHECK(wow64access_ == 0); |
| 171 StopWatching(); | |
| 172 HKEY key = key_; | 214 HKEY key = key_; |
| 173 key_ = NULL; | 215 key_ = NULL; |
| 174 return key; | 216 return key; |
| 175 } | 217 } |
| 176 | 218 |
| 177 bool RegKey::HasValue(const wchar_t* name) const { | 219 bool RegKey::HasValue(const wchar_t* name) const { |
| 178 return RegQueryValueEx(key_, name, 0, NULL, NULL, NULL) == ERROR_SUCCESS; | 220 return RegQueryValueEx(key_, name, 0, NULL, NULL, NULL) == ERROR_SUCCESS; |
| 179 } | 221 } |
| 180 | 222 |
| 181 DWORD RegKey::GetValueCount() const { | 223 DWORD RegKey::GetValueCount() const { |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 360 const void* data, | 402 const void* data, |
| 361 DWORD dsize, | 403 DWORD dsize, |
| 362 DWORD dtype) { | 404 DWORD dtype) { |
| 363 DCHECK(data || !dsize); | 405 DCHECK(data || !dsize); |
| 364 | 406 |
| 365 LONG result = RegSetValueEx(key_, name, 0, dtype, | 407 LONG result = RegSetValueEx(key_, name, 0, dtype, |
| 366 reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize); | 408 reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize); |
| 367 return result; | 409 return result; |
| 368 } | 410 } |
| 369 | 411 |
| 370 LONG RegKey::StartWatching() { | 412 bool RegKey::StartWatching(const ChangeCallback& callback) { |
| 371 DCHECK(key_); | 413 DCHECK(callback_.is_null()); |
| 372 if (!watch_event_) | 414 if (!key_watcher_) |
| 373 watch_event_ = CreateEvent(NULL, TRUE, FALSE, NULL); | 415 key_watcher_.reset(new Watcher(this)); |
| 374 | 416 |
| 375 DWORD filter = REG_NOTIFY_CHANGE_NAME | | 417 if (!key_watcher_.get()->StartWatching(key_)) |
| 376 REG_NOTIFY_CHANGE_ATTRIBUTES | | 418 return false; |
| 377 REG_NOTIFY_CHANGE_LAST_SET | | |
| 378 REG_NOTIFY_CHANGE_SECURITY; | |
| 379 | 419 |
| 380 // Watch the registry key for a change of value. | 420 callback_ = callback; |
| 381 LONG result = RegNotifyChangeKeyValue(key_, TRUE, filter, watch_event_, TRUE); | 421 return true; |
| 382 if (result != ERROR_SUCCESS) { | |
| 383 CloseHandle(watch_event_); | |
| 384 watch_event_ = 0; | |
| 385 } | |
| 386 | |
| 387 return result; | |
| 388 } | |
| 389 | |
| 390 bool RegKey::HasChanged() { | |
| 391 if (watch_event_) { | |
| 392 if (WaitForSingleObject(watch_event_, 0) == WAIT_OBJECT_0) { | |
| 393 StartWatching(); | |
| 394 return true; | |
| 395 } | |
| 396 } | |
| 397 return false; | |
| 398 } | |
| 399 | |
| 400 LONG RegKey::StopWatching() { | |
| 401 LONG result = ERROR_INVALID_HANDLE; | |
| 402 if (watch_event_) { | |
| 403 CloseHandle(watch_event_); | |
| 404 watch_event_ = 0; | |
| 405 result = ERROR_SUCCESS; | |
| 406 } | |
| 407 return result; | |
| 408 } | 422 } |
| 409 | 423 |
| 410 // static | 424 // static |
| 411 LONG RegKey::RegDeleteKeyExWrapper(HKEY hKey, | 425 LONG RegKey::RegDeleteKeyExWrapper(HKEY hKey, |
| 412 const wchar_t* lpSubKey, | 426 const wchar_t* lpSubKey, |
| 413 REGSAM samDesired, | 427 REGSAM samDesired, |
| 414 DWORD Reserved) { | 428 DWORD Reserved) { |
| 415 typedef LSTATUS(WINAPI* RegDeleteKeyExPtr)(HKEY, LPCWSTR, REGSAM, DWORD); | 429 typedef LSTATUS(WINAPI* RegDeleteKeyExPtr)(HKEY, LPCWSTR, REGSAM, DWORD); |
| 416 | 430 |
| 417 RegDeleteKeyExPtr reg_delete_key_ex_func = | 431 RegDeleteKeyExPtr reg_delete_key_ex_func = |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 477 } | 491 } |
| 478 | 492 |
| 479 RegCloseKey(target_key); | 493 RegCloseKey(target_key); |
| 480 | 494 |
| 481 // Try again to delete the key. | 495 // Try again to delete the key. |
| 482 result = RegDeleteKeyExWrapper(root_key, name.c_str(), access, 0); | 496 result = RegDeleteKeyExWrapper(root_key, name.c_str(), access, 0); |
| 483 | 497 |
| 484 return result; | 498 return result; |
| 485 } | 499 } |
| 486 | 500 |
| 501 void RegKey::OnObjectSignaled(HANDLE object) { | |
| 502 ChangeCallback callback = callback_; | |
| 503 callback_.Reset(); | |
| 504 callback.Run(); | |
| 505 } | |
| 506 | |
| 487 // RegistryValueIterator ------------------------------------------------------ | 507 // RegistryValueIterator ------------------------------------------------------ |
| 488 | 508 |
| 489 RegistryValueIterator::RegistryValueIterator(HKEY root_key, | 509 RegistryValueIterator::RegistryValueIterator(HKEY root_key, |
| 490 const wchar_t* folder_key) | 510 const wchar_t* folder_key) |
| 491 : name_(MAX_PATH, L'\0'), | 511 : name_(MAX_PATH, L'\0'), |
| 492 value_(MAX_PATH, L'\0') { | 512 value_(MAX_PATH, L'\0') { |
| 493 LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_); | 513 LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_); |
| 494 if (result != ERROR_SUCCESS) { | 514 if (result != ERROR_SUCCESS) { |
| 495 key_ = NULL; | 515 key_ = NULL; |
| 496 } else { | 516 } else { |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 629 if (ERROR_SUCCESS == r) | 649 if (ERROR_SUCCESS == r) |
| 630 return true; | 650 return true; |
| 631 } | 651 } |
| 632 | 652 |
| 633 name_[0] = '\0'; | 653 name_[0] = '\0'; |
| 634 return false; | 654 return false; |
| 635 } | 655 } |
| 636 | 656 |
| 637 } // namespace win | 657 } // namespace win |
| 638 } // namespace base | 658 } // namespace base |
| OLD | NEW |