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 |