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. | 37 // RegKey ---------------------------------------------------------------------- |
38 class RegKey::Watcher : public ObjectWatcher::Delegate { | |
39 public: | |
40 explicit Watcher(RegKey* owner) : owner_(owner) {} | |
41 ~Watcher() {} | |
42 | 38 |
43 bool StartWatching(HKEY key, const ChangeCallback& callback); | 39 RegKey::RegKey() |
44 | 40 : key_(NULL), |
45 // Implementation of ObjectWatcher::Delegate. | 41 watch_event_(0), |
46 void OnObjectSignaled(HANDLE object) override { | 42 wow64access_(0) { |
47 DCHECK(watch_event_.IsValid() && watch_event_.Get() == object); | |
48 ChangeCallback callback = callback_; | |
49 callback_.Reset(); | |
50 callback.Run(); | |
51 } | |
52 | |
53 private: | |
54 RegKey* owner_; | |
55 ScopedHandle watch_event_; | |
56 ObjectWatcher object_watcher_; | |
57 ChangeCallback callback_; | |
58 DISALLOW_COPY_AND_ASSIGN(Watcher); | |
59 }; | |
60 | |
61 bool RegKey::Watcher::StartWatching(HKEY key, const ChangeCallback& callback) { | |
62 DCHECK(key); | |
63 DCHECK(callback_.is_null()); | |
64 if (GetVersion() < VERSION_VISTA) { | |
65 // It is an error to register multiple times before Vista. | |
66 if (watch_event_.IsValid()) { | |
67 callback_ = callback; | |
68 return true; | |
69 } | |
70 } | |
71 | |
72 if (!watch_event_.IsValid()) | |
73 watch_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL)); | |
74 | |
75 if (!watch_event_.IsValid()) | |
76 return false; | |
77 | |
78 DWORD filter = REG_NOTIFY_CHANGE_NAME | | |
79 REG_NOTIFY_CHANGE_ATTRIBUTES | | |
80 REG_NOTIFY_CHANGE_LAST_SET | | |
81 REG_NOTIFY_CHANGE_SECURITY; | |
82 | |
83 // Watch the registry key for a change of value. | |
84 LONG result = RegNotifyChangeKeyValue(key, TRUE, filter, watch_event_.Get(), | |
85 TRUE); | |
86 if (result != ERROR_SUCCESS) { | |
87 watch_event_.Close(); | |
88 return false; | |
89 } | |
90 | |
91 callback_ = callback; | |
92 return object_watcher_.StartWatching(watch_event_.Get(), this); | |
93 } | 43 } |
94 | 44 |
95 // RegKey ---------------------------------------------------------------------- | 45 RegKey::RegKey(HKEY key) |
96 | 46 : key_(key), |
97 RegKey::RegKey() : key_(NULL), wow64access_(0) { | 47 watch_event_(0), |
98 } | 48 wow64access_(0) { |
99 | |
100 RegKey::RegKey(HKEY key) : key_(key), wow64access_(0) { | |
101 } | 49 } |
102 | 50 |
103 RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) | 51 RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) |
104 : key_(NULL), | 52 : key_(NULL), |
| 53 watch_event_(0), |
105 wow64access_(0) { | 54 wow64access_(0) { |
106 if (rootkey) { | 55 if (rootkey) { |
107 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) | 56 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) |
108 Create(rootkey, subkey, access); | 57 Create(rootkey, subkey, access); |
109 else | 58 else |
110 Open(rootkey, subkey, access); | 59 Open(rootkey, subkey, access); |
111 } else { | 60 } else { |
112 DCHECK(!subkey); | 61 DCHECK(!subkey); |
113 wow64access_ = access & kWow64AccessMask; | 62 wow64access_ = access & kWow64AccessMask; |
114 } | 63 } |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 // one. | 143 // one. |
195 if (result == ERROR_SUCCESS) { | 144 if (result == ERROR_SUCCESS) { |
196 Close(); | 145 Close(); |
197 key_ = subkey; | 146 key_ = subkey; |
198 wow64access_ = access & kWow64AccessMask; | 147 wow64access_ = access & kWow64AccessMask; |
199 } | 148 } |
200 return result; | 149 return result; |
201 } | 150 } |
202 | 151 |
203 void RegKey::Close() { | 152 void RegKey::Close() { |
| 153 StopWatching(); |
204 if (key_) { | 154 if (key_) { |
205 ::RegCloseKey(key_); | 155 ::RegCloseKey(key_); |
206 key_ = NULL; | 156 key_ = NULL; |
207 wow64access_ = 0; | 157 wow64access_ = 0; |
208 } | 158 } |
209 } | 159 } |
210 | 160 |
211 // TODO(wfh): Remove this and other unsafe methods. See http://crbug.com/375400 | 161 // TODO(wfh): Remove this and other unsafe methods. See http://crbug.com/375400 |
212 void RegKey::Set(HKEY key) { | 162 void RegKey::Set(HKEY key) { |
213 if (key_ != key) { | 163 if (key_ != key) { |
214 Close(); | 164 Close(); |
215 key_ = key; | 165 key_ = key; |
216 } | 166 } |
217 } | 167 } |
218 | 168 |
219 HKEY RegKey::Take() { | 169 HKEY RegKey::Take() { |
220 DCHECK(wow64access_ == 0); | 170 DCHECK(wow64access_ == 0); |
| 171 StopWatching(); |
221 HKEY key = key_; | 172 HKEY key = key_; |
222 key_ = NULL; | 173 key_ = NULL; |
223 return key; | 174 return key; |
224 } | 175 } |
225 | 176 |
226 bool RegKey::HasValue(const wchar_t* name) const { | 177 bool RegKey::HasValue(const wchar_t* name) const { |
227 return RegQueryValueEx(key_, name, 0, NULL, NULL, NULL) == ERROR_SUCCESS; | 178 return RegQueryValueEx(key_, name, 0, NULL, NULL, NULL) == ERROR_SUCCESS; |
228 } | 179 } |
229 | 180 |
230 DWORD RegKey::GetValueCount() const { | 181 DWORD RegKey::GetValueCount() const { |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
409 const void* data, | 360 const void* data, |
410 DWORD dsize, | 361 DWORD dsize, |
411 DWORD dtype) { | 362 DWORD dtype) { |
412 DCHECK(data || !dsize); | 363 DCHECK(data || !dsize); |
413 | 364 |
414 LONG result = RegSetValueEx(key_, name, 0, dtype, | 365 LONG result = RegSetValueEx(key_, name, 0, dtype, |
415 reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize); | 366 reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize); |
416 return result; | 367 return result; |
417 } | 368 } |
418 | 369 |
419 bool RegKey::StartWatching(const ChangeCallback& callback) { | 370 LONG RegKey::StartWatching() { |
420 if (!key_watcher_) | 371 DCHECK(key_); |
421 key_watcher_.reset(new Watcher(this)); | 372 if (!watch_event_) |
| 373 watch_event_ = CreateEvent(NULL, TRUE, FALSE, NULL); |
422 | 374 |
423 if (!key_watcher_.get()->StartWatching(key_, callback)) | 375 DWORD filter = REG_NOTIFY_CHANGE_NAME | |
424 return false; | 376 REG_NOTIFY_CHANGE_ATTRIBUTES | |
| 377 REG_NOTIFY_CHANGE_LAST_SET | |
| 378 REG_NOTIFY_CHANGE_SECURITY; |
425 | 379 |
426 return true; | 380 // Watch the registry key for a change of value. |
| 381 LONG result = RegNotifyChangeKeyValue(key_, TRUE, filter, watch_event_, 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; |
427 } | 408 } |
428 | 409 |
429 // static | 410 // static |
430 LONG RegKey::RegDeleteKeyExWrapper(HKEY hKey, | 411 LONG RegKey::RegDeleteKeyExWrapper(HKEY hKey, |
431 const wchar_t* lpSubKey, | 412 const wchar_t* lpSubKey, |
432 REGSAM samDesired, | 413 REGSAM samDesired, |
433 DWORD Reserved) { | 414 DWORD Reserved) { |
434 typedef LSTATUS(WINAPI* RegDeleteKeyExPtr)(HKEY, LPCWSTR, REGSAM, DWORD); | 415 typedef LSTATUS(WINAPI* RegDeleteKeyExPtr)(HKEY, LPCWSTR, REGSAM, DWORD); |
435 | 416 |
436 RegDeleteKeyExPtr reg_delete_key_ex_func = | 417 RegDeleteKeyExPtr reg_delete_key_ex_func = |
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
678 } else { | 659 } else { |
679 index_ = count - 1; | 660 index_ = count - 1; |
680 } | 661 } |
681 } | 662 } |
682 | 663 |
683 Read(); | 664 Read(); |
684 } | 665 } |
685 | 666 |
686 } // namespace win | 667 } // namespace win |
687 } // namespace base | 668 } // namespace base |
OLD | NEW |