Define DevTools content API
[chromium-blink-merge.git] / base / win / registry.cc
blob25499d3b35d0e9b12d72ef88992b299c72b99421
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"
7 #include <shlwapi.h>
9 #include "base/logging.h"
10 #include "base/threading/thread_restrictions.h"
12 #pragma comment(lib, "shlwapi.lib") // for SHDeleteKey
14 namespace base {
15 namespace win {
17 // RegKey ----------------------------------------------------------------------
19 RegKey::RegKey()
20 : key_(NULL),
21 watch_event_(0) {
24 RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
25 : key_(NULL),
26 watch_event_(0) {
27 base::ThreadRestrictions::AssertIOAllowed();
28 if (rootkey) {
29 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
30 Create(rootkey, subkey, access);
31 else
32 Open(rootkey, subkey, access);
33 } else {
34 DCHECK(!subkey);
38 RegKey::~RegKey() {
39 Close();
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);
51 Close();
53 LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL,
54 REG_OPTION_NON_VOLATILE, access, NULL, &key_,
55 disposition);
56 return result;
59 LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
60 base::ThreadRestrictions::AssertIOAllowed();
61 DCHECK(name && access);
63 HKEY subkey = NULL;
64 LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE,
65 access, NULL, &subkey, NULL);
66 Close();
68 key_ = subkey;
69 return result;
72 LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
73 base::ThreadRestrictions::AssertIOAllowed();
74 DCHECK(rootkey && subkey && access);
75 Close();
77 LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &key_);
78 return result;
81 LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) {
82 base::ThreadRestrictions::AssertIOAllowed();
83 DCHECK(relative_key_name && access);
85 HKEY subkey = NULL;
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
89 // one.
90 Close();
92 key_ = subkey;
93 return result;
96 void RegKey::Close() {
97 base::ThreadRestrictions::AssertIOAllowed();
98 StopWatching();
99 if (key_) {
100 ::RegCloseKey(key_);
101 key_ = NULL;
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();
112 DWORD count = 0;
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();
120 wchar_t buf[256];
121 DWORD bufsize = arraysize(buf);
122 LONG r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL, NULL, NULL);
123 if (r == ERROR_SUCCESS)
124 *name = buf;
126 return r;
129 LONG RegKey::DeleteKey(const wchar_t* name) {
130 base::ThreadRestrictions::AssertIOAllowed();
131 DCHECK(key_);
132 DCHECK(name);
133 LONG result = SHDeleteKey(key_, name);
134 return result;
137 LONG RegKey::DeleteValue(const wchar_t* value_name) {
138 base::ThreadRestrictions::AssertIOAllowed();
139 DCHECK(key_);
140 DCHECK(value_name);
141 LONG result = RegDeleteValue(key_, value_name);
142 return result;
145 LONG RegKey::ReadValueDW(const wchar_t* name, DWORD* out_value) const {
146 DCHECK(out_value);
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;
154 else
155 result = ERROR_CANTREAD;
158 return result;
161 LONG RegKey::ReadInt64(const wchar_t* name, int64* out_value) const {
162 DCHECK(out_value);
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;
171 else
172 result = ERROR_CANTREAD;
175 return result;
178 LONG RegKey::ReadValue(const wchar_t* name, std::wstring* out_value) const {
179 base::ThreadRestrictions::AssertIOAllowed();
180 DCHECK(out_value);
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;
197 } else {
198 *out_value = expanded;
200 } else {
201 // Not a string. Oops.
202 result = ERROR_CANTREAD;
206 return result;
209 LONG RegKey::ReadValue(const wchar_t* name,
210 void* data,
211 DWORD* dsize,
212 DWORD* dtype) const {
213 base::ThreadRestrictions::AssertIOAllowed();
214 LONG result = RegQueryValueEx(key_, name, 0, dtype,
215 reinterpret_cast<LPBYTE>(data), dsize);
216 return result;
219 LONG RegKey::WriteValue(const wchar_t* name, DWORD in_value) {
220 return WriteValue(
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,
230 const void* data,
231 DWORD dsize,
232 DWORD dtype) {
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);
238 return result;
241 LONG RegKey::StartWatching() {
242 DCHECK(key_);
243 if (!watch_event_)
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_);
255 watch_event_ = 0;
258 return result;
261 bool RegKey::HasChanged() {
262 if (watch_event_) {
263 if (WaitForSingleObject(watch_event_, 0) == WAIT_OBJECT_0) {
264 StartWatching();
265 return true;
268 return false;
271 LONG RegKey::StopWatching() {
272 LONG result = ERROR_INVALID_HANDLE;
273 if (watch_event_) {
274 CloseHandle(watch_event_);
275 watch_event_ = 0;
276 result = ERROR_SUCCESS;
278 return result;
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) {
289 key_ = NULL;
290 } else {
291 DWORD count = 0;
292 result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
293 NULL, NULL, NULL, NULL);
295 if (result != ERROR_SUCCESS) {
296 ::RegCloseKey(key_);
297 key_ = NULL;
298 } else {
299 index_ = count - 1;
303 Read();
306 RegistryValueIterator::~RegistryValueIterator() {
307 base::ThreadRestrictions::AssertIOAllowed();
308 if (key_)
309 ::RegCloseKey(key_);
312 DWORD RegistryValueIterator::ValueCount() const {
313 base::ThreadRestrictions::AssertIOAllowed();
314 DWORD count = 0;
315 LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL,
316 &count, NULL, NULL, NULL, NULL);
317 if (result != ERROR_SUCCESS)
318 return 0;
320 return count;
323 bool RegistryValueIterator::Valid() const {
324 return key_ != NULL && index_ >= 0;
327 void RegistryValueIterator::operator++() {
328 --index_;
329 Read();
332 bool RegistryValueIterator::Read() {
333 base::ThreadRestrictions::AssertIOAllowed();
334 if (Valid()) {
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)
340 return true;
343 name_[0] = '\0';
344 value_[0] = '\0';
345 value_size_ = 0;
346 return false;
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) {
356 key_ = NULL;
357 } else {
358 DWORD count = 0;
359 LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
360 NULL, NULL, NULL, NULL, NULL);
362 if (result != ERROR_SUCCESS) {
363 ::RegCloseKey(key_);
364 key_ = NULL;
365 } else {
366 index_ = count - 1;
370 Read();
373 RegistryKeyIterator::~RegistryKeyIterator() {
374 base::ThreadRestrictions::AssertIOAllowed();
375 if (key_)
376 ::RegCloseKey(key_);
379 DWORD RegistryKeyIterator::SubkeyCount() const {
380 base::ThreadRestrictions::AssertIOAllowed();
381 DWORD count = 0;
382 LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
383 NULL, NULL, NULL, NULL, NULL);
384 if (result != ERROR_SUCCESS)
385 return 0;
387 return count;
390 bool RegistryKeyIterator::Valid() const {
391 return key_ != NULL && index_ >= 0;
394 void RegistryKeyIterator::operator++() {
395 --index_;
396 Read();
399 bool RegistryKeyIterator::Read() {
400 base::ThreadRestrictions::AssertIOAllowed();
401 if (Valid()) {
402 DWORD ncount = arraysize(name_);
403 FILETIME written;
404 LONG r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL,
405 NULL, &written);
406 if (ERROR_SUCCESS == r)
407 return true;
410 name_[0] = '\0';
411 return false;
414 } // namespace win
415 } // namespace base