1 // Copyright (c) 2011 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"
9 #include "base/logging.h"
10 #include "base/threading/thread_restrictions.h"
12 #pragma comment(lib, "shlwapi.lib") // for SHDeleteKey
17 // RegKey ----------------------------------------------------------------------
24 RegKey::RegKey(HKEY rootkey
, const wchar_t* subkey
, REGSAM access
)
27 base::ThreadRestrictions::AssertIOAllowed();
29 if (access
& (KEY_SET_VALUE
| KEY_CREATE_SUB_KEY
| KEY_CREATE_LINK
))
30 Create(rootkey
, subkey
, access
);
32 Open(rootkey
, subkey
, access
);
42 LONG
RegKey::Create(HKEY rootkey
, const wchar_t* subkey
, REGSAM access
) {
43 DWORD disposition_value
;
44 return CreateWithDisposition(rootkey
, subkey
, &disposition_value
, access
);
47 LONG
RegKey::CreateWithDisposition(HKEY rootkey
, const wchar_t* subkey
,
48 DWORD
* disposition
, REGSAM access
) {
49 base::ThreadRestrictions::AssertIOAllowed();
50 DCHECK(rootkey
&& subkey
&& access
&& disposition
);
53 LONG result
= RegCreateKeyEx(rootkey
, subkey
, 0, NULL
,
54 REG_OPTION_NON_VOLATILE
, access
, NULL
, &key_
,
59 LONG
RegKey::CreateKey(const wchar_t* name
, REGSAM access
) {
60 base::ThreadRestrictions::AssertIOAllowed();
61 DCHECK(name
&& access
);
64 LONG result
= RegCreateKeyEx(key_
, name
, 0, NULL
, REG_OPTION_NON_VOLATILE
,
65 access
, NULL
, &subkey
, NULL
);
72 LONG
RegKey::Open(HKEY rootkey
, const wchar_t* subkey
, REGSAM access
) {
73 base::ThreadRestrictions::AssertIOAllowed();
74 DCHECK(rootkey
&& subkey
&& access
);
77 LONG result
= RegOpenKeyEx(rootkey
, subkey
, 0, access
, &key_
);
81 LONG
RegKey::OpenKey(const wchar_t* relative_key_name
, REGSAM access
) {
82 base::ThreadRestrictions::AssertIOAllowed();
83 DCHECK(relative_key_name
&& access
);
86 LONG result
= RegOpenKeyEx(key_
, relative_key_name
, 0, access
, &subkey
);
88 // We have to close the current opened key before replacing it with the new
96 void RegKey::Close() {
97 base::ThreadRestrictions::AssertIOAllowed();
105 bool RegKey::HasValue(const wchar_t* name
) const {
106 base::ThreadRestrictions::AssertIOAllowed();
107 return RegQueryValueEx(key_
, name
, 0, NULL
, NULL
, NULL
) == ERROR_SUCCESS
;
110 DWORD
RegKey::GetValueCount() const {
111 base::ThreadRestrictions::AssertIOAllowed();
113 LONG result
= RegQueryInfoKey(key_
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, &count
,
114 NULL
, NULL
, NULL
, NULL
);
115 return (result
== ERROR_SUCCESS
) ? count
: 0;
118 LONG
RegKey::GetValueNameAt(int index
, std::wstring
* name
) const {
119 base::ThreadRestrictions::AssertIOAllowed();
121 DWORD bufsize
= arraysize(buf
);
122 LONG r
= ::RegEnumValue(key_
, index
, buf
, &bufsize
, NULL
, NULL
, NULL
, NULL
);
123 if (r
== ERROR_SUCCESS
)
129 LONG
RegKey::DeleteKey(const wchar_t* name
) {
130 base::ThreadRestrictions::AssertIOAllowed();
133 LONG result
= SHDeleteKey(key_
, name
);
137 LONG
RegKey::DeleteValue(const wchar_t* value_name
) {
138 base::ThreadRestrictions::AssertIOAllowed();
141 LONG result
= RegDeleteValue(key_
, value_name
);
145 LONG
RegKey::ReadValueDW(const wchar_t* name
, DWORD
* out_value
) const {
147 DWORD type
= REG_DWORD
;
148 DWORD size
= sizeof(DWORD
);
149 DWORD local_value
= 0;
150 LONG result
= ReadValue(name
, &local_value
, &size
, &type
);
151 if (result
== ERROR_SUCCESS
) {
152 if ((type
== REG_DWORD
|| type
== REG_BINARY
) && size
== sizeof(DWORD
))
153 *out_value
= local_value
;
155 result
= ERROR_CANTREAD
;
161 LONG
RegKey::ReadInt64(const wchar_t* name
, int64
* out_value
) const {
163 DWORD type
= REG_QWORD
;
164 int64 local_value
= 0;
165 DWORD size
= sizeof(local_value
);
166 LONG result
= ReadValue(name
, &local_value
, &size
, &type
);
167 if (result
== ERROR_SUCCESS
) {
168 if ((type
== REG_QWORD
|| type
== REG_BINARY
) &&
169 size
== sizeof(local_value
))
170 *out_value
= local_value
;
172 result
= ERROR_CANTREAD
;
178 LONG
RegKey::ReadValue(const wchar_t* name
, std::wstring
* out_value
) const {
179 base::ThreadRestrictions::AssertIOAllowed();
181 const size_t kMaxStringLength
= 1024; // This is after expansion.
182 // Use the one of the other forms of ReadValue if 1024 is too small for you.
183 wchar_t raw_value
[kMaxStringLength
];
184 DWORD type
= REG_SZ
, size
= sizeof(raw_value
);
185 LONG result
= ReadValue(name
, raw_value
, &size
, &type
);
186 if (result
== ERROR_SUCCESS
) {
187 if (type
== REG_SZ
) {
188 *out_value
= raw_value
;
189 } else if (type
== REG_EXPAND_SZ
) {
190 wchar_t expanded
[kMaxStringLength
];
191 size
= ExpandEnvironmentStrings(raw_value
, expanded
, kMaxStringLength
);
192 // Success: returns the number of wchar_t's copied
193 // Fail: buffer too small, returns the size required
194 // Fail: other, returns 0
195 if (size
== 0 || size
> kMaxStringLength
) {
196 result
= ERROR_MORE_DATA
;
198 *out_value
= expanded
;
201 // Not a string. Oops.
202 result
= ERROR_CANTREAD
;
209 LONG
RegKey::ReadValue(const wchar_t* name
,
212 DWORD
* dtype
) const {
213 base::ThreadRestrictions::AssertIOAllowed();
214 LONG result
= RegQueryValueEx(key_
, name
, 0, dtype
,
215 reinterpret_cast<LPBYTE
>(data
), dsize
);
219 LONG
RegKey::WriteValue(const wchar_t* name
, DWORD in_value
) {
221 name
, &in_value
, static_cast<DWORD
>(sizeof(in_value
)), REG_DWORD
);
224 LONG
RegKey::WriteValue(const wchar_t * name
, const wchar_t* in_value
) {
225 return WriteValue(name
, in_value
,
226 static_cast<DWORD
>(sizeof(*in_value
) * (wcslen(in_value
) + 1)), REG_SZ
);
229 LONG
RegKey::WriteValue(const wchar_t* name
,
233 base::ThreadRestrictions::AssertIOAllowed();
234 DCHECK(data
|| !dsize
);
236 LONG result
= RegSetValueEx(key_
, name
, 0, dtype
,
237 reinterpret_cast<LPBYTE
>(const_cast<void*>(data
)), dsize
);
241 LONG
RegKey::StartWatching() {
244 watch_event_
= CreateEvent(NULL
, TRUE
, FALSE
, NULL
);
246 DWORD filter
= REG_NOTIFY_CHANGE_NAME
|
247 REG_NOTIFY_CHANGE_ATTRIBUTES
|
248 REG_NOTIFY_CHANGE_LAST_SET
|
249 REG_NOTIFY_CHANGE_SECURITY
;
251 // Watch the registry key for a change of value.
252 LONG result
= RegNotifyChangeKeyValue(key_
, TRUE
, filter
, watch_event_
, TRUE
);
253 if (result
!= ERROR_SUCCESS
) {
254 CloseHandle(watch_event_
);
261 bool RegKey::HasChanged() {
263 if (WaitForSingleObject(watch_event_
, 0) == WAIT_OBJECT_0
) {
271 LONG
RegKey::StopWatching() {
272 LONG result
= ERROR_INVALID_HANDLE
;
274 CloseHandle(watch_event_
);
276 result
= ERROR_SUCCESS
;
281 // RegistryValueIterator ------------------------------------------------------
283 RegistryValueIterator::RegistryValueIterator(HKEY root_key
,
284 const wchar_t* folder_key
) {
285 base::ThreadRestrictions::AssertIOAllowed();
287 LONG result
= RegOpenKeyEx(root_key
, folder_key
, 0, KEY_READ
, &key_
);
288 if (result
!= ERROR_SUCCESS
) {
292 result
= ::RegQueryInfoKey(key_
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, &count
,
293 NULL
, NULL
, NULL
, NULL
);
295 if (result
!= ERROR_SUCCESS
) {
306 RegistryValueIterator::~RegistryValueIterator() {
307 base::ThreadRestrictions::AssertIOAllowed();
312 DWORD
RegistryValueIterator::ValueCount() const {
313 base::ThreadRestrictions::AssertIOAllowed();
315 LONG result
= ::RegQueryInfoKey(key_
, NULL
, 0, NULL
, NULL
, NULL
, NULL
,
316 &count
, NULL
, NULL
, NULL
, NULL
);
317 if (result
!= ERROR_SUCCESS
)
323 bool RegistryValueIterator::Valid() const {
324 return key_
!= NULL
&& index_
>= 0;
327 void RegistryValueIterator::operator++() {
332 bool RegistryValueIterator::Read() {
333 base::ThreadRestrictions::AssertIOAllowed();
335 DWORD ncount
= arraysize(name_
);
336 value_size_
= sizeof(value_
);
337 LONG r
= ::RegEnumValue(key_
, index_
, name_
, &ncount
, NULL
, &type_
,
338 reinterpret_cast<BYTE
*>(value_
), &value_size_
);
339 if (ERROR_SUCCESS
== r
)
349 // RegistryKeyIterator --------------------------------------------------------
351 RegistryKeyIterator::RegistryKeyIterator(HKEY root_key
,
352 const wchar_t* folder_key
) {
353 base::ThreadRestrictions::AssertIOAllowed();
354 LONG result
= RegOpenKeyEx(root_key
, folder_key
, 0, KEY_READ
, &key_
);
355 if (result
!= ERROR_SUCCESS
) {
359 LONG result
= ::RegQueryInfoKey(key_
, NULL
, 0, NULL
, &count
, NULL
, NULL
,
360 NULL
, NULL
, NULL
, NULL
, NULL
);
362 if (result
!= ERROR_SUCCESS
) {
373 RegistryKeyIterator::~RegistryKeyIterator() {
374 base::ThreadRestrictions::AssertIOAllowed();
379 DWORD
RegistryKeyIterator::SubkeyCount() const {
380 base::ThreadRestrictions::AssertIOAllowed();
382 LONG result
= ::RegQueryInfoKey(key_
, NULL
, 0, NULL
, &count
, NULL
, NULL
,
383 NULL
, NULL
, NULL
, NULL
, NULL
);
384 if (result
!= ERROR_SUCCESS
)
390 bool RegistryKeyIterator::Valid() const {
391 return key_
!= NULL
&& index_
>= 0;
394 void RegistryKeyIterator::operator++() {
399 bool RegistryKeyIterator::Read() {
400 base::ThreadRestrictions::AssertIOAllowed();
402 DWORD ncount
= arraysize(name_
);
404 LONG r
= ::RegEnumKeyEx(key_
, index_
, name_
, &ncount
, NULL
, NULL
,
406 if (ERROR_SUCCESS
== r
)