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/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 rootkey
, const wchar_t* subkey
, REGSAM access
)
46 if (access
& (KEY_SET_VALUE
| KEY_CREATE_SUB_KEY
| KEY_CREATE_LINK
))
47 Create(rootkey
, subkey
, access
);
49 Open(rootkey
, subkey
, access
);
59 LONG
RegKey::Create(HKEY rootkey
, const wchar_t* subkey
, REGSAM access
) {
60 DWORD disposition_value
;
61 return CreateWithDisposition(rootkey
, subkey
, &disposition_value
, access
);
64 LONG
RegKey::CreateWithDisposition(HKEY rootkey
, const wchar_t* subkey
,
65 DWORD
* disposition
, REGSAM access
) {
66 DCHECK(rootkey
&& subkey
&& access
&& disposition
);
69 LONG result
= RegCreateKeyEx(rootkey
, subkey
, 0, NULL
,
70 REG_OPTION_NON_VOLATILE
, access
, NULL
, &key_
,
75 LONG
RegKey::CreateKey(const wchar_t* name
, REGSAM access
) {
76 DCHECK(name
&& access
);
78 LONG result
= RegCreateKeyEx(key_
, name
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
79 access
, NULL
, &subkey
, NULL
);
86 LONG
RegKey::Open(HKEY rootkey
, const wchar_t* subkey
, REGSAM access
) {
87 DCHECK(rootkey
&& subkey
&& access
);
90 LONG result
= RegOpenKeyEx(rootkey
, subkey
, 0, access
, &key_
);
94 LONG
RegKey::OpenKey(const wchar_t* relative_key_name
, REGSAM access
) {
95 DCHECK(relative_key_name
&& access
);
97 LONG result
= RegOpenKeyEx(key_
, relative_key_name
, 0, access
, &subkey
);
99 // We have to close the current opened key before replacing it with the new
107 void RegKey::Close() {
115 bool RegKey::HasValue(const wchar_t* name
) const {
116 return RegQueryValueEx(key_
, name
, 0, NULL
, NULL
, NULL
) == ERROR_SUCCESS
;
119 DWORD
RegKey::GetValueCount() const {
121 LONG result
= RegQueryInfoKey(key_
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, &count
,
122 NULL
, NULL
, NULL
, NULL
);
123 return (result
== ERROR_SUCCESS
) ? count
: 0;
126 LONG
RegKey::GetValueNameAt(int index
, std::wstring
* name
) const {
128 DWORD bufsize
= arraysize(buf
);
129 LONG r
= ::RegEnumValue(key_
, index
, buf
, &bufsize
, NULL
, NULL
, NULL
, NULL
);
130 if (r
== ERROR_SUCCESS
)
136 LONG
RegKey::DeleteKey(const wchar_t* name
) {
139 LONG result
= SHDeleteKey(key_
, name
);
143 LONG
RegKey::DeleteValue(const wchar_t* value_name
) {
145 LONG result
= RegDeleteValue(key_
, value_name
);
149 LONG
RegKey::ReadValueDW(const wchar_t* name
, DWORD
* out_value
) const {
151 DWORD type
= REG_DWORD
;
152 DWORD size
= sizeof(DWORD
);
153 DWORD local_value
= 0;
154 LONG result
= ReadValue(name
, &local_value
, &size
, &type
);
155 if (result
== ERROR_SUCCESS
) {
156 if ((type
== REG_DWORD
|| type
== REG_BINARY
) && size
== sizeof(DWORD
))
157 *out_value
= local_value
;
159 result
= ERROR_CANTREAD
;
165 LONG
RegKey::ReadInt64(const wchar_t* name
, int64
* out_value
) const {
167 DWORD type
= REG_QWORD
;
168 int64 local_value
= 0;
169 DWORD size
= sizeof(local_value
);
170 LONG result
= ReadValue(name
, &local_value
, &size
, &type
);
171 if (result
== ERROR_SUCCESS
) {
172 if ((type
== REG_QWORD
|| type
== REG_BINARY
) &&
173 size
== sizeof(local_value
))
174 *out_value
= local_value
;
176 result
= ERROR_CANTREAD
;
182 LONG
RegKey::ReadValue(const wchar_t* name
, std::wstring
* out_value
) const {
184 const size_t kMaxStringLength
= 1024; // This is after expansion.
185 // Use the one of the other forms of ReadValue if 1024 is too small for you.
186 wchar_t raw_value
[kMaxStringLength
];
187 DWORD type
= REG_SZ
, size
= sizeof(raw_value
);
188 LONG result
= ReadValue(name
, raw_value
, &size
, &type
);
189 if (result
== ERROR_SUCCESS
) {
190 if (type
== REG_SZ
) {
191 *out_value
= raw_value
;
192 } else if (type
== REG_EXPAND_SZ
) {
193 wchar_t expanded
[kMaxStringLength
];
194 size
= ExpandEnvironmentStrings(raw_value
, expanded
, kMaxStringLength
);
195 // Success: returns the number of wchar_t's copied
196 // Fail: buffer too small, returns the size required
197 // Fail: other, returns 0
198 if (size
== 0 || size
> kMaxStringLength
) {
199 result
= ERROR_MORE_DATA
;
201 *out_value
= expanded
;
204 // Not a string. Oops.
205 result
= ERROR_CANTREAD
;
212 LONG
RegKey::ReadValue(const wchar_t* name
,
215 DWORD
* dtype
) const {
216 LONG result
= RegQueryValueEx(key_
, name
, 0, dtype
,
217 reinterpret_cast<LPBYTE
>(data
), dsize
);
221 LONG
RegKey::ReadValues(const wchar_t* name
,
222 std::vector
<std::wstring
>* values
) {
225 DWORD type
= REG_MULTI_SZ
;
227 LONG result
= ReadValue(name
, NULL
, &size
, &type
);
228 if (FAILED(result
) || size
== 0)
231 if (type
!= REG_MULTI_SZ
)
232 return ERROR_CANTREAD
;
234 std::vector
<wchar_t> buffer(size
/ sizeof(wchar_t));
235 result
= ReadValue(name
, &buffer
[0], &size
, NULL
);
236 if (FAILED(result
) || size
== 0)
239 // Parse the double-null-terminated list of strings.
240 // Note: This code is paranoid to not read outside of |buf|, in the case where
241 // it may not be properly terminated.
242 const wchar_t* entry
= &buffer
[0];
243 const wchar_t* buffer_end
= entry
+ (size
/ sizeof(wchar_t));
244 while (entry
< buffer_end
&& entry
[0] != '\0') {
245 const wchar_t* entry_end
= std::find(entry
, buffer_end
, L
'\0');
246 values
->push_back(std::wstring(entry
, entry_end
));
247 entry
= entry_end
+ 1;
252 LONG
RegKey::WriteValue(const wchar_t* name
, DWORD in_value
) {
254 name
, &in_value
, static_cast<DWORD
>(sizeof(in_value
)), REG_DWORD
);
257 LONG
RegKey::WriteValue(const wchar_t * name
, const wchar_t* in_value
) {
258 return WriteValue(name
, in_value
,
259 static_cast<DWORD
>(sizeof(*in_value
) * (wcslen(in_value
) + 1)), REG_SZ
);
262 LONG
RegKey::WriteValue(const wchar_t* name
,
266 DCHECK(data
|| !dsize
);
268 LONG result
= RegSetValueEx(key_
, name
, 0, dtype
,
269 reinterpret_cast<LPBYTE
>(const_cast<void*>(data
)), dsize
);
273 LONG
RegKey::StartWatching() {
276 watch_event_
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
278 DWORD filter
= REG_NOTIFY_CHANGE_NAME
|
279 REG_NOTIFY_CHANGE_ATTRIBUTES
|
280 REG_NOTIFY_CHANGE_LAST_SET
|
281 REG_NOTIFY_CHANGE_SECURITY
;
283 // Watch the registry key for a change of value.
284 LONG result
= RegNotifyChangeKeyValue(key_
, TRUE
, filter
, watch_event_
, TRUE
);
285 if (result
!= ERROR_SUCCESS
) {
286 CloseHandle(watch_event_
);
293 bool RegKey::HasChanged() {
295 if (WaitForSingleObject(watch_event_
, 0) == WAIT_OBJECT_0
) {
303 LONG
RegKey::StopWatching() {
304 LONG result
= ERROR_INVALID_HANDLE
;
306 CloseHandle(watch_event_
);
308 result
= ERROR_SUCCESS
;
313 // RegistryValueIterator ------------------------------------------------------
315 RegistryValueIterator::RegistryValueIterator(HKEY root_key
,
316 const wchar_t* folder_key
)
317 : name_(MAX_PATH
, L
'\0'),
318 value_(MAX_PATH
, L
'\0') {
319 LONG result
= RegOpenKeyEx(root_key
, folder_key
, 0, KEY_READ
, &key_
);
320 if (result
!= ERROR_SUCCESS
) {
324 result
= ::RegQueryInfoKey(key_
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, &count
,
325 NULL
, NULL
, NULL
, NULL
);
327 if (result
!= ERROR_SUCCESS
) {
338 RegistryValueIterator::~RegistryValueIterator() {
343 DWORD
RegistryValueIterator::ValueCount() const {
345 LONG result
= ::RegQueryInfoKey(key_
, NULL
, 0, NULL
, NULL
, NULL
, NULL
,
346 &count
, NULL
, NULL
, NULL
, NULL
);
347 if (result
!= ERROR_SUCCESS
)
353 bool RegistryValueIterator::Valid() const {
354 return key_
!= NULL
&& index_
>= 0;
357 void RegistryValueIterator::operator++() {
362 bool RegistryValueIterator::Read() {
364 DWORD capacity
= static_cast<DWORD
>(name_
.capacity());
365 DWORD name_size
= capacity
;
366 // |value_size_| is in bytes. Reserve the last character for a NUL.
367 value_size_
= static_cast<DWORD
>((value_
.size() - 1) * sizeof(wchar_t));
368 LONG result
= ::RegEnumValue(
369 key_
, index_
, WriteInto(&name_
, name_size
), &name_size
, NULL
, &type_
,
370 reinterpret_cast<BYTE
*>(vector_as_array(&value_
)), &value_size_
);
372 if (result
== ERROR_MORE_DATA
) {
373 // Registry key names are limited to 255 characters and fit within
374 // MAX_PATH (which is 260) but registry value names can use up to 16,383
375 // characters and the value itself is not limited
376 // (from http://msdn.microsoft.com/en-us/library/windows/desktop/
377 // ms724872(v=vs.85).aspx).
378 // Resize the buffers and retry if their size caused the failure.
379 DWORD value_size_in_wchars
= to_wchar_size(value_size_
);
380 if (value_size_in_wchars
+ 1 > value_
.size())
381 value_
.resize(value_size_in_wchars
+ 1, L
'\0');
382 value_size_
= static_cast<DWORD
>((value_
.size() - 1) * sizeof(wchar_t));
383 name_size
= name_size
== capacity
? MAX_REGISTRY_NAME_SIZE
: capacity
;
384 result
= ::RegEnumValue(
385 key_
, index_
, WriteInto(&name_
, name_size
), &name_size
, NULL
, &type_
,
386 reinterpret_cast<BYTE
*>(vector_as_array(&value_
)), &value_size_
);
389 if (result
== ERROR_SUCCESS
) {
390 DCHECK_LT(to_wchar_size(value_size_
), value_
.size());
391 value_
[to_wchar_size(value_size_
)] = L
'\0';
402 // RegistryKeyIterator --------------------------------------------------------
404 RegistryKeyIterator::RegistryKeyIterator(HKEY root_key
,
405 const wchar_t* folder_key
) {
406 LONG result
= RegOpenKeyEx(root_key
, folder_key
, 0, KEY_READ
, &key_
);
407 if (result
!= ERROR_SUCCESS
) {
411 LONG result
= ::RegQueryInfoKey(key_
, NULL
, 0, NULL
, &count
, NULL
, NULL
,
412 NULL
, NULL
, NULL
, NULL
, NULL
);
414 if (result
!= ERROR_SUCCESS
) {
425 RegistryKeyIterator::~RegistryKeyIterator() {
430 DWORD
RegistryKeyIterator::SubkeyCount() const {
432 LONG result
= ::RegQueryInfoKey(key_
, NULL
, 0, NULL
, &count
, NULL
, NULL
,
433 NULL
, NULL
, NULL
, NULL
, NULL
);
434 if (result
!= ERROR_SUCCESS
)
440 bool RegistryKeyIterator::Valid() const {
441 return key_
!= NULL
&& index_
>= 0;
444 void RegistryKeyIterator::operator++() {
449 bool RegistryKeyIterator::Read() {
451 DWORD ncount
= arraysize(name_
);
453 LONG r
= ::RegEnumKeyEx(key_
, index_
, name_
, &ncount
, NULL
, NULL
,
455 if (ERROR_SUCCESS
== r
)