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/threading/thread_restrictions.h"
13 #pragma comment(lib, "shlwapi.lib") // for SHDeleteKey
18 // RegKey ----------------------------------------------------------------------
25 RegKey::RegKey(HKEY rootkey
, const wchar_t* subkey
, REGSAM access
)
28 base::ThreadRestrictions::AssertIOAllowed();
30 if (access
& (KEY_SET_VALUE
| KEY_CREATE_SUB_KEY
| KEY_CREATE_LINK
))
31 Create(rootkey
, subkey
, access
);
33 Open(rootkey
, subkey
, access
);
43 LONG
RegKey::Create(HKEY rootkey
, const wchar_t* subkey
, REGSAM access
) {
44 DWORD disposition_value
;
45 return CreateWithDisposition(rootkey
, subkey
, &disposition_value
, access
);
48 LONG
RegKey::CreateWithDisposition(HKEY rootkey
, const wchar_t* subkey
,
49 DWORD
* disposition
, REGSAM access
) {
50 base::ThreadRestrictions::AssertIOAllowed();
51 DCHECK(rootkey
&& subkey
&& access
&& disposition
);
54 LONG result
= RegCreateKeyEx(rootkey
, subkey
, 0, NULL
,
55 REG_OPTION_NON_VOLATILE
, access
, NULL
, &key_
,
60 LONG
RegKey::CreateKey(const wchar_t* name
, REGSAM access
) {
61 base::ThreadRestrictions::AssertIOAllowed();
62 DCHECK(name
&& access
);
65 LONG result
= RegCreateKeyEx(key_
, name
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
66 access
, NULL
, &subkey
, NULL
);
73 LONG
RegKey::Open(HKEY rootkey
, const wchar_t* subkey
, REGSAM access
) {
74 base::ThreadRestrictions::AssertIOAllowed();
75 DCHECK(rootkey
&& subkey
&& access
);
78 LONG result
= RegOpenKeyEx(rootkey
, subkey
, 0, access
, &key_
);
82 LONG
RegKey::OpenKey(const wchar_t* relative_key_name
, REGSAM access
) {
83 base::ThreadRestrictions::AssertIOAllowed();
84 DCHECK(relative_key_name
&& access
);
87 LONG result
= RegOpenKeyEx(key_
, relative_key_name
, 0, access
, &subkey
);
89 // We have to close the current opened key before replacing it with the new
97 void RegKey::Close() {
98 base::ThreadRestrictions::AssertIOAllowed();
106 bool RegKey::HasValue(const wchar_t* name
) const {
107 base::ThreadRestrictions::AssertIOAllowed();
108 return RegQueryValueEx(key_
, name
, 0, NULL
, NULL
, NULL
) == ERROR_SUCCESS
;
111 DWORD
RegKey::GetValueCount() const {
112 base::ThreadRestrictions::AssertIOAllowed();
114 LONG result
= RegQueryInfoKey(key_
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, &count
,
115 NULL
, NULL
, NULL
, NULL
);
116 return (result
== ERROR_SUCCESS
) ? count
: 0;
119 LONG
RegKey::GetValueNameAt(int index
, std::wstring
* name
) const {
120 base::ThreadRestrictions::AssertIOAllowed();
122 DWORD bufsize
= arraysize(buf
);
123 LONG r
= ::RegEnumValue(key_
, index
, buf
, &bufsize
, NULL
, NULL
, NULL
, NULL
);
124 if (r
== ERROR_SUCCESS
)
130 LONG
RegKey::DeleteKey(const wchar_t* name
) {
131 base::ThreadRestrictions::AssertIOAllowed();
134 LONG result
= SHDeleteKey(key_
, name
);
138 LONG
RegKey::DeleteValue(const wchar_t* value_name
) {
139 base::ThreadRestrictions::AssertIOAllowed();
142 LONG result
= RegDeleteValue(key_
, value_name
);
146 LONG
RegKey::ReadValueDW(const wchar_t* name
, DWORD
* out_value
) const {
148 DWORD type
= REG_DWORD
;
149 DWORD size
= sizeof(DWORD
);
150 DWORD local_value
= 0;
151 LONG result
= ReadValue(name
, &local_value
, &size
, &type
);
152 if (result
== ERROR_SUCCESS
) {
153 if ((type
== REG_DWORD
|| type
== REG_BINARY
) && size
== sizeof(DWORD
))
154 *out_value
= local_value
;
156 result
= ERROR_CANTREAD
;
162 LONG
RegKey::ReadInt64(const wchar_t* name
, int64
* out_value
) const {
164 DWORD type
= REG_QWORD
;
165 int64 local_value
= 0;
166 DWORD size
= sizeof(local_value
);
167 LONG result
= ReadValue(name
, &local_value
, &size
, &type
);
168 if (result
== ERROR_SUCCESS
) {
169 if ((type
== REG_QWORD
|| type
== REG_BINARY
) &&
170 size
== sizeof(local_value
))
171 *out_value
= local_value
;
173 result
= ERROR_CANTREAD
;
179 LONG
RegKey::ReadValue(const wchar_t* name
, std::wstring
* out_value
) const {
180 base::ThreadRestrictions::AssertIOAllowed();
182 const size_t kMaxStringLength
= 1024; // This is after expansion.
183 // Use the one of the other forms of ReadValue if 1024 is too small for you.
184 wchar_t raw_value
[kMaxStringLength
];
185 DWORD type
= REG_SZ
, size
= sizeof(raw_value
);
186 LONG result
= ReadValue(name
, raw_value
, &size
, &type
);
187 if (result
== ERROR_SUCCESS
) {
188 if (type
== REG_SZ
) {
189 *out_value
= raw_value
;
190 } else if (type
== REG_EXPAND_SZ
) {
191 wchar_t expanded
[kMaxStringLength
];
192 size
= ExpandEnvironmentStrings(raw_value
, expanded
, kMaxStringLength
);
193 // Success: returns the number of wchar_t's copied
194 // Fail: buffer too small, returns the size required
195 // Fail: other, returns 0
196 if (size
== 0 || size
> kMaxStringLength
) {
197 result
= ERROR_MORE_DATA
;
199 *out_value
= expanded
;
202 // Not a string. Oops.
203 result
= ERROR_CANTREAD
;
210 LONG
RegKey::ReadValue(const wchar_t* name
,
213 DWORD
* dtype
) const {
214 base::ThreadRestrictions::AssertIOAllowed();
215 LONG result
= RegQueryValueEx(key_
, name
, 0, dtype
,
216 reinterpret_cast<LPBYTE
>(data
), dsize
);
220 LONG
RegKey::ReadValues(const wchar_t* name
,
221 std::vector
<std::wstring
>* values
) {
222 base::ThreadRestrictions::AssertIOAllowed();
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 base::ThreadRestrictions::AssertIOAllowed();
267 DCHECK(data
|| !dsize
);
269 LONG result
= RegSetValueEx(key_
, name
, 0, dtype
,
270 reinterpret_cast<LPBYTE
>(const_cast<void*>(data
)), dsize
);
274 LONG
RegKey::StartWatching() {
277 watch_event_
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
279 DWORD filter
= REG_NOTIFY_CHANGE_NAME
|
280 REG_NOTIFY_CHANGE_ATTRIBUTES
|
281 REG_NOTIFY_CHANGE_LAST_SET
|
282 REG_NOTIFY_CHANGE_SECURITY
;
284 // Watch the registry key for a change of value.
285 LONG result
= RegNotifyChangeKeyValue(key_
, TRUE
, filter
, watch_event_
, TRUE
);
286 if (result
!= ERROR_SUCCESS
) {
287 CloseHandle(watch_event_
);
294 bool RegKey::HasChanged() {
296 if (WaitForSingleObject(watch_event_
, 0) == WAIT_OBJECT_0
) {
304 LONG
RegKey::StopWatching() {
305 LONG result
= ERROR_INVALID_HANDLE
;
307 CloseHandle(watch_event_
);
309 result
= ERROR_SUCCESS
;
314 // RegistryValueIterator ------------------------------------------------------
316 RegistryValueIterator::RegistryValueIterator(HKEY root_key
,
317 const wchar_t* folder_key
) {
318 base::ThreadRestrictions::AssertIOAllowed();
320 LONG result
= RegOpenKeyEx(root_key
, folder_key
, 0, KEY_READ
, &key_
);
321 if (result
!= ERROR_SUCCESS
) {
325 result
= ::RegQueryInfoKey(key_
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, &count
,
326 NULL
, NULL
, NULL
, NULL
);
328 if (result
!= ERROR_SUCCESS
) {
339 RegistryValueIterator::~RegistryValueIterator() {
340 base::ThreadRestrictions::AssertIOAllowed();
345 DWORD
RegistryValueIterator::ValueCount() const {
346 base::ThreadRestrictions::AssertIOAllowed();
348 LONG result
= ::RegQueryInfoKey(key_
, NULL
, 0, NULL
, NULL
, NULL
, NULL
,
349 &count
, NULL
, NULL
, NULL
, NULL
);
350 if (result
!= ERROR_SUCCESS
)
356 bool RegistryValueIterator::Valid() const {
357 return key_
!= NULL
&& index_
>= 0;
360 void RegistryValueIterator::operator++() {
365 bool RegistryValueIterator::Read() {
366 base::ThreadRestrictions::AssertIOAllowed();
368 DWORD ncount
= arraysize(name_
);
369 value_size_
= sizeof(value_
);
370 LONG r
= ::RegEnumValue(key_
, index_
, name_
, &ncount
, NULL
, &type_
,
371 reinterpret_cast<BYTE
*>(value_
), &value_size_
);
372 if (ERROR_SUCCESS
== r
)
382 // RegistryKeyIterator --------------------------------------------------------
384 RegistryKeyIterator::RegistryKeyIterator(HKEY root_key
,
385 const wchar_t* folder_key
) {
386 base::ThreadRestrictions::AssertIOAllowed();
387 LONG result
= RegOpenKeyEx(root_key
, folder_key
, 0, KEY_READ
, &key_
);
388 if (result
!= ERROR_SUCCESS
) {
392 LONG result
= ::RegQueryInfoKey(key_
, NULL
, 0, NULL
, &count
, NULL
, NULL
,
393 NULL
, NULL
, NULL
, NULL
, NULL
);
395 if (result
!= ERROR_SUCCESS
) {
406 RegistryKeyIterator::~RegistryKeyIterator() {
407 base::ThreadRestrictions::AssertIOAllowed();
412 DWORD
RegistryKeyIterator::SubkeyCount() const {
413 base::ThreadRestrictions::AssertIOAllowed();
415 LONG result
= ::RegQueryInfoKey(key_
, NULL
, 0, NULL
, &count
, NULL
, NULL
,
416 NULL
, NULL
, NULL
, NULL
, NULL
);
417 if (result
!= ERROR_SUCCESS
)
423 bool RegistryKeyIterator::Valid() const {
424 return key_
!= NULL
&& index_
>= 0;
427 void RegistryKeyIterator::operator++() {
432 bool RegistryKeyIterator::Read() {
433 base::ThreadRestrictions::AssertIOAllowed();
435 DWORD ncount
= arraysize(name_
);
437 LONG r
= ::RegEnumKeyEx(key_
, index_
, name_
, &ncount
, NULL
, NULL
,
439 if (ERROR_SUCCESS
== r
)