Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / base / win / registry.cc
blob83eb59065c5abcf509445200ff8dfed06e76ec5a
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"
7 #include <shlwapi.h>
8 #include <algorithm>
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
16 namespace base {
17 namespace win {
19 namespace {
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);
33 } // namespace
35 // RegKey ----------------------------------------------------------------------
37 RegKey::RegKey()
38 : key_(NULL),
39 watch_event_(0) {
42 RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
43 : key_(NULL),
44 watch_event_(0) {
45 if (rootkey) {
46 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
47 Create(rootkey, subkey, access);
48 else
49 Open(rootkey, subkey, access);
50 } else {
51 DCHECK(!subkey);
55 RegKey::~RegKey() {
56 Close();
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);
67 Close();
69 LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL,
70 REG_OPTION_NON_VOLATILE, access, NULL, &key_,
71 disposition);
72 return result;
75 LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
76 DCHECK(name && access);
77 HKEY subkey = NULL;
78 LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE,
79 access, NULL, &subkey, NULL);
80 Close();
82 key_ = subkey;
83 return result;
86 LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
87 DCHECK(rootkey && subkey && access);
88 Close();
90 LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &key_);
91 return result;
94 LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) {
95 DCHECK(relative_key_name && access);
96 HKEY subkey = NULL;
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
100 // one.
101 Close();
103 key_ = subkey;
104 return result;
107 void RegKey::Close() {
108 StopWatching();
109 if (key_) {
110 ::RegCloseKey(key_);
111 key_ = NULL;
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 {
120 DWORD count = 0;
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 {
127 wchar_t buf[256];
128 DWORD bufsize = arraysize(buf);
129 LONG r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL, NULL, NULL);
130 if (r == ERROR_SUCCESS)
131 *name = buf;
133 return r;
136 LONG RegKey::DeleteKey(const wchar_t* name) {
137 DCHECK(key_);
138 DCHECK(name);
139 LONG result = SHDeleteKey(key_, name);
140 return result;
143 LONG RegKey::DeleteValue(const wchar_t* value_name) {
144 DCHECK(key_);
145 LONG result = RegDeleteValue(key_, value_name);
146 return result;
149 LONG RegKey::ReadValueDW(const wchar_t* name, DWORD* out_value) const {
150 DCHECK(out_value);
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;
158 else
159 result = ERROR_CANTREAD;
162 return result;
165 LONG RegKey::ReadInt64(const wchar_t* name, int64* out_value) const {
166 DCHECK(out_value);
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;
175 else
176 result = ERROR_CANTREAD;
179 return result;
182 LONG RegKey::ReadValue(const wchar_t* name, std::wstring* out_value) const {
183 DCHECK(out_value);
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;
200 } else {
201 *out_value = expanded;
203 } else {
204 // Not a string. Oops.
205 result = ERROR_CANTREAD;
209 return result;
212 LONG RegKey::ReadValue(const wchar_t* name,
213 void* data,
214 DWORD* dsize,
215 DWORD* dtype) const {
216 LONG result = RegQueryValueEx(key_, name, 0, dtype,
217 reinterpret_cast<LPBYTE>(data), dsize);
218 return result;
221 LONG RegKey::ReadValues(const wchar_t* name,
222 std::vector<std::wstring>* values) {
223 values->clear();
225 DWORD type = REG_MULTI_SZ;
226 DWORD size = 0;
227 LONG result = ReadValue(name, NULL, &size, &type);
228 if (FAILED(result) || size == 0)
229 return result;
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)
237 return result;
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;
249 return 0;
252 LONG RegKey::WriteValue(const wchar_t* name, DWORD in_value) {
253 return WriteValue(
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,
263 const void* data,
264 DWORD dsize,
265 DWORD dtype) {
266 DCHECK(data || !dsize);
268 LONG result = RegSetValueEx(key_, name, 0, dtype,
269 reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize);
270 return result;
273 LONG RegKey::StartWatching() {
274 DCHECK(key_);
275 if (!watch_event_)
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_);
287 watch_event_ = 0;
290 return result;
293 bool RegKey::HasChanged() {
294 if (watch_event_) {
295 if (WaitForSingleObject(watch_event_, 0) == WAIT_OBJECT_0) {
296 StartWatching();
297 return true;
300 return false;
303 LONG RegKey::StopWatching() {
304 LONG result = ERROR_INVALID_HANDLE;
305 if (watch_event_) {
306 CloseHandle(watch_event_);
307 watch_event_ = 0;
308 result = ERROR_SUCCESS;
310 return result;
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) {
321 key_ = NULL;
322 } else {
323 DWORD count = 0;
324 result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
325 NULL, NULL, NULL, NULL);
327 if (result != ERROR_SUCCESS) {
328 ::RegCloseKey(key_);
329 key_ = NULL;
330 } else {
331 index_ = count - 1;
335 Read();
338 RegistryValueIterator::~RegistryValueIterator() {
339 if (key_)
340 ::RegCloseKey(key_);
343 DWORD RegistryValueIterator::ValueCount() const {
344 DWORD count = 0;
345 LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL,
346 &count, NULL, NULL, NULL, NULL);
347 if (result != ERROR_SUCCESS)
348 return 0;
350 return count;
353 bool RegistryValueIterator::Valid() const {
354 return key_ != NULL && index_ >= 0;
357 void RegistryValueIterator::operator++() {
358 --index_;
359 Read();
362 bool RegistryValueIterator::Read() {
363 if (Valid()) {
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';
392 return true;
396 name_[0] = L'\0';
397 value_[0] = L'\0';
398 value_size_ = 0;
399 return false;
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) {
408 key_ = NULL;
409 } else {
410 DWORD count = 0;
411 LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
412 NULL, NULL, NULL, NULL, NULL);
414 if (result != ERROR_SUCCESS) {
415 ::RegCloseKey(key_);
416 key_ = NULL;
417 } else {
418 index_ = count - 1;
422 Read();
425 RegistryKeyIterator::~RegistryKeyIterator() {
426 if (key_)
427 ::RegCloseKey(key_);
430 DWORD RegistryKeyIterator::SubkeyCount() const {
431 DWORD count = 0;
432 LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
433 NULL, NULL, NULL, NULL, NULL);
434 if (result != ERROR_SUCCESS)
435 return 0;
437 return count;
440 bool RegistryKeyIterator::Valid() const {
441 return key_ != NULL && index_ >= 0;
444 void RegistryKeyIterator::operator++() {
445 --index_;
446 Read();
449 bool RegistryKeyIterator::Read() {
450 if (Valid()) {
451 DWORD ncount = arraysize(name_);
452 FILETIME written;
453 LONG r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL,
454 NULL, &written);
455 if (ERROR_SUCCESS == r)
456 return true;
459 name_[0] = '\0';
460 return false;
463 } // namespace win
464 } // namespace base