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
3 // found in the LICENSE file.
5 #include "base/win/registry.h"
10 #include "base/logging.h"
11 #include "base/strings/string_util.h"
12 #include "base/threading/thread_restrictions.h"
14 #pragma comment(lib, "shlwapi.lib") // for SHDeleteKey
21 // RegEnumValue() reports the number of characters from the name that were
22 // written to the buffer, not how many there are. This constant is the maximum
23 // name size, such that a buffer with this size should read any name.
24 const DWORD MAX_REGISTRY_NAME_SIZE
= 16384;
26 // Registry values are read as BYTE* but can have wchar_t* data whose last
27 // wchar_t is truncated. This function converts the reported |byte_size| to
28 // a size in wchar_t that can store a truncated wchar_t if necessary.
29 inline DWORD
to_wchar_size(DWORD byte_size
) {
30 return (byte_size
+ sizeof(wchar_t) - 1) / sizeof(wchar_t);
35 // RegKey ----------------------------------------------------------------------
42 RegKey::RegKey(HKEY key
)
47 RegKey::RegKey(HKEY rootkey
, const wchar_t* subkey
, REGSAM access
)
51 if (access
& (KEY_SET_VALUE
| KEY_CREATE_SUB_KEY
| KEY_CREATE_LINK
))
52 Create(rootkey
, subkey
, access
);
54 Open(rootkey
, subkey
, access
);
64 LONG
RegKey::Create(HKEY rootkey
, const wchar_t* subkey
, REGSAM access
) {
65 DWORD disposition_value
;
66 return CreateWithDisposition(rootkey
, subkey
, &disposition_value
, access
);
69 LONG
RegKey::CreateWithDisposition(HKEY rootkey
, const wchar_t* subkey
,
70 DWORD
* disposition
, REGSAM access
) {
71 DCHECK(rootkey
&& subkey
&& access
&& disposition
);
74 LONG result
= RegCreateKeyEx(rootkey
, subkey
, 0, NULL
,
75 REG_OPTION_NON_VOLATILE
, access
, NULL
, &key_
,
80 LONG
RegKey::CreateKey(const wchar_t* name
, REGSAM access
) {
81 DCHECK(name
&& access
);
83 LONG result
= RegCreateKeyEx(key_
, name
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
84 access
, NULL
, &subkey
, NULL
);
91 LONG
RegKey::Open(HKEY rootkey
, const wchar_t* subkey
, REGSAM access
) {
92 DCHECK(rootkey
&& subkey
&& access
);
95 LONG result
= RegOpenKeyEx(rootkey
, subkey
, 0, access
, &key_
);
99 LONG
RegKey::OpenKey(const wchar_t* relative_key_name
, REGSAM access
) {
100 DCHECK(relative_key_name
&& access
);
102 LONG result
= RegOpenKeyEx(key_
, relative_key_name
, 0, access
, &subkey
);
104 // We have to close the current opened key before replacing it with the new
112 void RegKey::Close() {
120 void RegKey::Set(HKEY key
) {
127 HKEY
RegKey::Take() {
134 bool RegKey::HasValue(const wchar_t* name
) const {
135 return RegQueryValueEx(key_
, name
, 0, NULL
, NULL
, NULL
) == ERROR_SUCCESS
;
138 DWORD
RegKey::GetValueCount() const {
140 LONG result
= RegQueryInfoKey(key_
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, &count
,
141 NULL
, NULL
, NULL
, NULL
);
142 return (result
== ERROR_SUCCESS
) ? count
: 0;
145 LONG
RegKey::GetValueNameAt(int index
, std::wstring
* name
) const {
147 DWORD bufsize
= arraysize(buf
);
148 LONG r
= ::RegEnumValue(key_
, index
, buf
, &bufsize
, NULL
, NULL
, NULL
, NULL
);
149 if (r
== ERROR_SUCCESS
)
155 LONG
RegKey::DeleteKey(const wchar_t* name
) {
158 LONG result
= SHDeleteKey(key_
, name
);
162 LONG
RegKey::DeleteValue(const wchar_t* value_name
) {
164 LONG result
= RegDeleteValue(key_
, value_name
);
168 LONG
RegKey::ReadValueDW(const wchar_t* name
, DWORD
* out_value
) const {
170 DWORD type
= REG_DWORD
;
171 DWORD size
= sizeof(DWORD
);
172 DWORD local_value
= 0;
173 LONG result
= ReadValue(name
, &local_value
, &size
, &type
);
174 if (result
== ERROR_SUCCESS
) {
175 if ((type
== REG_DWORD
|| type
== REG_BINARY
) && size
== sizeof(DWORD
))
176 *out_value
= local_value
;
178 result
= ERROR_CANTREAD
;
184 LONG
RegKey::ReadInt64(const wchar_t* name
, int64
* out_value
) const {
186 DWORD type
= REG_QWORD
;
187 int64 local_value
= 0;
188 DWORD size
= sizeof(local_value
);
189 LONG result
= ReadValue(name
, &local_value
, &size
, &type
);
190 if (result
== ERROR_SUCCESS
) {
191 if ((type
== REG_QWORD
|| type
== REG_BINARY
) &&
192 size
== sizeof(local_value
))
193 *out_value
= local_value
;
195 result
= ERROR_CANTREAD
;
201 LONG
RegKey::ReadValue(const wchar_t* name
, std::wstring
* out_value
) const {
203 const size_t kMaxStringLength
= 1024; // This is after expansion.
204 // Use the one of the other forms of ReadValue if 1024 is too small for you.
205 wchar_t raw_value
[kMaxStringLength
];
206 DWORD type
= REG_SZ
, size
= sizeof(raw_value
);
207 LONG result
= ReadValue(name
, raw_value
, &size
, &type
);
208 if (result
== ERROR_SUCCESS
) {
209 if (type
== REG_SZ
) {
210 *out_value
= raw_value
;
211 } else if (type
== REG_EXPAND_SZ
) {
212 wchar_t expanded
[kMaxStringLength
];
213 size
= ExpandEnvironmentStrings(raw_value
, expanded
, kMaxStringLength
);
214 // Success: returns the number of wchar_t's copied
215 // Fail: buffer too small, returns the size required
216 // Fail: other, returns 0
217 if (size
== 0 || size
> kMaxStringLength
) {
218 result
= ERROR_MORE_DATA
;
220 *out_value
= expanded
;
223 // Not a string. Oops.
224 result
= ERROR_CANTREAD
;
231 LONG
RegKey::ReadValue(const wchar_t* name
,
234 DWORD
* dtype
) const {
235 LONG result
= RegQueryValueEx(key_
, name
, 0, dtype
,
236 reinterpret_cast<LPBYTE
>(data
), dsize
);
240 LONG
RegKey::ReadValues(const wchar_t* name
,
241 std::vector
<std::wstring
>* values
) {
244 DWORD type
= REG_MULTI_SZ
;
246 LONG result
= ReadValue(name
, NULL
, &size
, &type
);
247 if (FAILED(result
) || size
== 0)
250 if (type
!= REG_MULTI_SZ
)
251 return ERROR_CANTREAD
;
253 std::vector
<wchar_t> buffer(size
/ sizeof(wchar_t));
254 result
= ReadValue(name
, &buffer
[0], &size
, NULL
);
255 if (FAILED(result
) || size
== 0)
258 // Parse the double-null-terminated list of strings.
259 // Note: This code is paranoid to not read outside of |buf|, in the case where
260 // it may not be properly terminated.
261 const wchar_t* entry
= &buffer
[0];
262 const wchar_t* buffer_end
= entry
+ (size
/ sizeof(wchar_t));
263 while (entry
< buffer_end
&& entry
[0] != '\0') {
264 const wchar_t* entry_end
= std::find(entry
, buffer_end
, L
'\0');
265 values
->push_back(std::wstring(entry
, entry_end
));
266 entry
= entry_end
+ 1;
271 LONG
RegKey::WriteValue(const wchar_t* name
, DWORD in_value
) {
273 name
, &in_value
, static_cast<DWORD
>(sizeof(in_value
)), REG_DWORD
);
276 LONG
RegKey::WriteValue(const wchar_t * name
, const wchar_t* in_value
) {
277 return WriteValue(name
, in_value
,
278 static_cast<DWORD
>(sizeof(*in_value
) * (wcslen(in_value
) + 1)), REG_SZ
);
281 LONG
RegKey::WriteValue(const wchar_t* name
,
285 DCHECK(data
|| !dsize
);
287 LONG result
= RegSetValueEx(key_
, name
, 0, dtype
,
288 reinterpret_cast<LPBYTE
>(const_cast<void*>(data
)), dsize
);
292 LONG
RegKey::StartWatching() {
295 watch_event_
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
297 DWORD filter
= REG_NOTIFY_CHANGE_NAME
|
298 REG_NOTIFY_CHANGE_ATTRIBUTES
|
299 REG_NOTIFY_CHANGE_LAST_SET
|
300 REG_NOTIFY_CHANGE_SECURITY
;
302 // Watch the registry key for a change of value.
303 LONG result
= RegNotifyChangeKeyValue(key_
, TRUE
, filter
, watch_event_
, TRUE
);
304 if (result
!= ERROR_SUCCESS
) {
305 CloseHandle(watch_event_
);
312 bool RegKey::HasChanged() {
314 if (WaitForSingleObject(watch_event_
, 0) == WAIT_OBJECT_0
) {
322 LONG
RegKey::StopWatching() {
323 LONG result
= ERROR_INVALID_HANDLE
;
325 CloseHandle(watch_event_
);
327 result
= ERROR_SUCCESS
;
332 // RegistryValueIterator ------------------------------------------------------
334 RegistryValueIterator::RegistryValueIterator(HKEY root_key
,
335 const wchar_t* folder_key
)
336 : name_(MAX_PATH
, L
'\0'),
337 value_(MAX_PATH
, L
'\0') {
338 LONG result
= RegOpenKeyEx(root_key
, folder_key
, 0, KEY_READ
, &key_
);
339 if (result
!= ERROR_SUCCESS
) {
343 result
= ::RegQueryInfoKey(key_
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, &count
,
344 NULL
, NULL
, NULL
, NULL
);
346 if (result
!= ERROR_SUCCESS
) {
357 RegistryValueIterator::~RegistryValueIterator() {
362 DWORD
RegistryValueIterator::ValueCount() const {
364 LONG result
= ::RegQueryInfoKey(key_
, NULL
, 0, NULL
, NULL
, NULL
, NULL
,
365 &count
, NULL
, NULL
, NULL
, NULL
);
366 if (result
!= ERROR_SUCCESS
)
372 bool RegistryValueIterator::Valid() const {
373 return key_
!= NULL
&& index_
>= 0;
376 void RegistryValueIterator::operator++() {
381 bool RegistryValueIterator::Read() {
383 DWORD capacity
= static_cast<DWORD
>(name_
.capacity());
384 DWORD name_size
= capacity
;
385 // |value_size_| is in bytes. Reserve the last character for a NUL.
386 value_size_
= static_cast<DWORD
>((value_
.size() - 1) * sizeof(wchar_t));
387 LONG result
= ::RegEnumValue(
388 key_
, index_
, WriteInto(&name_
, name_size
), &name_size
, NULL
, &type_
,
389 reinterpret_cast<BYTE
*>(vector_as_array(&value_
)), &value_size_
);
391 if (result
== ERROR_MORE_DATA
) {
392 // Registry key names are limited to 255 characters and fit within
393 // MAX_PATH (which is 260) but registry value names can use up to 16,383
394 // characters and the value itself is not limited
395 // (from http://msdn.microsoft.com/en-us/library/windows/desktop/
396 // ms724872(v=vs.85).aspx).
397 // Resize the buffers and retry if their size caused the failure.
398 DWORD value_size_in_wchars
= to_wchar_size(value_size_
);
399 if (value_size_in_wchars
+ 1 > value_
.size())
400 value_
.resize(value_size_in_wchars
+ 1, L
'\0');
401 value_size_
= static_cast<DWORD
>((value_
.size() - 1) * sizeof(wchar_t));
402 name_size
= name_size
== capacity
? MAX_REGISTRY_NAME_SIZE
: capacity
;
403 result
= ::RegEnumValue(
404 key_
, index_
, WriteInto(&name_
, name_size
), &name_size
, NULL
, &type_
,
405 reinterpret_cast<BYTE
*>(vector_as_array(&value_
)), &value_size_
);
408 if (result
== ERROR_SUCCESS
) {
409 DCHECK_LT(to_wchar_size(value_size_
), value_
.size());
410 value_
[to_wchar_size(value_size_
)] = L
'\0';
421 // RegistryKeyIterator --------------------------------------------------------
423 RegistryKeyIterator::RegistryKeyIterator(HKEY root_key
,
424 const wchar_t* folder_key
) {
425 LONG result
= RegOpenKeyEx(root_key
, folder_key
, 0, KEY_READ
, &key_
);
426 if (result
!= ERROR_SUCCESS
) {
430 LONG result
= ::RegQueryInfoKey(key_
, NULL
, 0, NULL
, &count
, NULL
, NULL
,
431 NULL
, NULL
, NULL
, NULL
, NULL
);
433 if (result
!= ERROR_SUCCESS
) {
444 RegistryKeyIterator::~RegistryKeyIterator() {
449 DWORD
RegistryKeyIterator::SubkeyCount() const {
451 LONG result
= ::RegQueryInfoKey(key_
, NULL
, 0, NULL
, &count
, NULL
, NULL
,
452 NULL
, NULL
, NULL
, NULL
, NULL
);
453 if (result
!= ERROR_SUCCESS
)
459 bool RegistryKeyIterator::Valid() const {
460 return key_
!= NULL
&& index_
>= 0;
463 void RegistryKeyIterator::operator++() {
468 bool RegistryKeyIterator::Read() {
470 DWORD ncount
= arraysize(name_
);
472 LONG r
= ::RegEnumKeyEx(key_
, index_
, name_
, &ncount
, NULL
, NULL
,
474 if (ERROR_SUCCESS
== r
)