registry.cc revision 731df977c0511bca2206b5f333555b1205ff1f43
1// Copyright (c) 2010 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.
4
5#include "base/win/registry.h"
6
7#include <shlwapi.h>
8
9#include "base/logging.h"
10
11#pragma comment(lib, "shlwapi.lib")  // for SHDeleteKey
12
13namespace base {
14namespace win {
15
16RegistryValueIterator::RegistryValueIterator(HKEY root_key,
17                                             const wchar_t* folder_key) {
18  LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
19  if (result != ERROR_SUCCESS) {
20    key_ = NULL;
21  } else {
22    DWORD count = 0;
23    result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
24                               NULL, NULL, NULL, NULL);
25
26    if (result != ERROR_SUCCESS) {
27      ::RegCloseKey(key_);
28      key_ = NULL;
29    } else {
30      index_ = count - 1;
31    }
32  }
33
34  Read();
35}
36
37RegistryValueIterator::~RegistryValueIterator() {
38  if (key_)
39    ::RegCloseKey(key_);
40}
41
42bool RegistryValueIterator::Valid() const {
43  return key_ != NULL && index_ >= 0;
44}
45
46void RegistryValueIterator::operator++() {
47  --index_;
48  Read();
49}
50
51bool RegistryValueIterator::Read() {
52  if (Valid()) {
53    DWORD ncount = arraysize(name_);
54    value_size_ = sizeof(value_);
55    LRESULT r = ::RegEnumValue(key_, index_, name_, &ncount, NULL, &type_,
56                               reinterpret_cast<BYTE*>(value_), &value_size_);
57    if (ERROR_SUCCESS == r)
58      return true;
59  }
60
61  name_[0] = '\0';
62  value_[0] = '\0';
63  value_size_ = 0;
64  return false;
65}
66
67DWORD RegistryValueIterator::ValueCount() const {
68  DWORD count = 0;
69  HRESULT result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL,
70                                     &count, NULL, NULL, NULL, NULL);
71
72  if (result != ERROR_SUCCESS)
73    return 0;
74
75  return count;
76}
77
78RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
79                                         const wchar_t* folder_key) {
80  LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_);
81  if (result != ERROR_SUCCESS) {
82    key_ = NULL;
83  } else {
84    DWORD count = 0;
85    HRESULT result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
86                                       NULL, NULL, NULL, NULL, NULL);
87
88    if (result != ERROR_SUCCESS) {
89      ::RegCloseKey(key_);
90      key_ = NULL;
91    } else {
92      index_ = count - 1;
93    }
94  }
95
96  Read();
97}
98
99RegistryKeyIterator::~RegistryKeyIterator() {
100  if (key_)
101    ::RegCloseKey(key_);
102}
103
104bool RegistryKeyIterator::Valid() const {
105  return key_ != NULL && index_ >= 0;
106}
107
108void RegistryKeyIterator::operator++() {
109  --index_;
110  Read();
111}
112
113bool RegistryKeyIterator::Read() {
114  if (Valid()) {
115    DWORD ncount = arraysize(name_);
116    FILETIME written;
117    LRESULT r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL,
118                               NULL, &written);
119    if (ERROR_SUCCESS == r)
120      return true;
121  }
122
123  name_[0] = '\0';
124  return false;
125}
126
127DWORD RegistryKeyIterator::SubkeyCount() const {
128  DWORD count = 0;
129  HRESULT result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
130                                     NULL, NULL, NULL, NULL, NULL);
131
132  if (result != ERROR_SUCCESS)
133    return 0;
134
135  return count;
136}
137
138RegKey::RegKey()
139    : key_(NULL),
140      watch_event_(0) {
141}
142
143RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
144    : key_(NULL),
145      watch_event_(0) {
146  if (rootkey) {
147    if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
148      Create(rootkey, subkey, access);
149    else
150      Open(rootkey, subkey, access);
151  } else {
152    DCHECK(!subkey);
153  }
154}
155
156RegKey::~RegKey() {
157  Close();
158}
159
160void RegKey::Close() {
161  StopWatching();
162  if (key_) {
163    ::RegCloseKey(key_);
164    key_ = NULL;
165  }
166}
167
168bool RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
169  DWORD disposition_value;
170  return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
171}
172
173bool RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
174                                   DWORD* disposition, REGSAM access) {
175  DCHECK(rootkey && subkey && access && disposition);
176  Close();
177
178  LONG result = RegCreateKeyEx(rootkey,
179                               subkey,
180                               0,
181                               NULL,
182                               REG_OPTION_NON_VOLATILE,
183                               access,
184                               NULL,
185                               &key_,
186                               disposition);
187  if (result != ERROR_SUCCESS) {
188    key_ = NULL;
189    return false;
190  }
191
192  return true;
193}
194
195bool RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
196  DCHECK(rootkey && subkey && access);
197  Close();
198
199  LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &key_);
200  if (result != ERROR_SUCCESS) {
201    key_ = NULL;
202    return false;
203  }
204  return true;
205}
206
207bool RegKey::CreateKey(const wchar_t* name, REGSAM access) {
208  DCHECK(name && access);
209
210  HKEY subkey = NULL;
211  LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE,
212                               access, NULL, &subkey, NULL);
213  Close();
214
215  key_ = subkey;
216  return (result == ERROR_SUCCESS);
217}
218
219bool RegKey::OpenKey(const wchar_t* name, REGSAM access) {
220  DCHECK(name && access);
221
222  HKEY subkey = NULL;
223  LONG result = RegOpenKeyEx(key_, name, 0, access, &subkey);
224
225  Close();
226
227  key_ = subkey;
228  return (result == ERROR_SUCCESS);
229}
230
231DWORD RegKey::ValueCount() {
232  DWORD count = 0;
233  HRESULT result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL,
234                                   NULL, &count, NULL, NULL, NULL, NULL);
235  return (result != ERROR_SUCCESS) ? 0 : count;
236}
237
238bool RegKey::ReadName(int index, std::wstring* name) {
239  wchar_t buf[256];
240  DWORD bufsize = arraysize(buf);
241  LRESULT r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL,
242                             NULL, NULL);
243  if (r != ERROR_SUCCESS)
244    return false;
245  if (name)
246    *name = buf;
247  return true;
248}
249
250bool RegKey::ValueExists(const wchar_t* name) {
251  if (!key_)
252    return false;
253  HRESULT result = RegQueryValueEx(key_, name, 0, NULL, NULL, NULL);
254  return (result == ERROR_SUCCESS);
255}
256
257bool RegKey::ReadValue(const wchar_t* name, void* data,
258                       DWORD* dsize, DWORD* dtype) {
259  if (!key_)
260    return false;
261  HRESULT result = RegQueryValueEx(key_, name, 0, dtype,
262                                   reinterpret_cast<LPBYTE>(data), dsize);
263  return (result == ERROR_SUCCESS);
264}
265
266bool RegKey::ReadValue(const wchar_t* name, std::wstring* value) {
267  DCHECK(value);
268  const size_t kMaxStringLength = 1024;  // This is after expansion.
269  // Use the one of the other forms of ReadValue if 1024 is too small for you.
270  wchar_t raw_value[kMaxStringLength];
271  DWORD type = REG_SZ, size = sizeof(raw_value);
272  if (ReadValue(name, raw_value, &size, &type)) {
273    if (type == REG_SZ) {
274      *value = raw_value;
275    } else if (type == REG_EXPAND_SZ) {
276      wchar_t expanded[kMaxStringLength];
277      size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength);
278      // Success: returns the number of wchar_t's copied
279      // Fail: buffer too small, returns the size required
280      // Fail: other, returns 0
281      if (size == 0 || size > kMaxStringLength)
282        return false;
283      *value = expanded;
284    } else {
285      // Not a string. Oops.
286      return false;
287    }
288    return true;
289  }
290
291  return false;
292}
293
294bool RegKey::ReadValueDW(const wchar_t* name, DWORD* value) {
295  DCHECK(value);
296  DWORD type = REG_DWORD;
297  DWORD size = sizeof(DWORD);
298  DWORD result = 0;
299  if (ReadValue(name, &result, &size, &type) &&
300      (type == REG_DWORD || type == REG_BINARY) &&
301      size == sizeof(DWORD)) {
302    *value = result;
303    return true;
304  }
305
306  return false;
307}
308
309bool RegKey::WriteValue(const wchar_t* name, const void * data,
310                        DWORD dsize, DWORD dtype) {
311  DCHECK(data);
312
313  if (!key_)
314    return false;
315
316  HRESULT result = RegSetValueEx(
317      key_,
318      name,
319      0,
320      dtype,
321      reinterpret_cast<LPBYTE>(const_cast<void*>(data)),
322      dsize);
323  return (result == ERROR_SUCCESS);
324}
325
326bool RegKey::WriteValue(const wchar_t * name, const wchar_t* value) {
327  return WriteValue(name, value,
328      static_cast<DWORD>(sizeof(*value) * (wcslen(value) + 1)), REG_SZ);
329}
330
331bool RegKey::WriteValue(const wchar_t* name, DWORD value) {
332  return WriteValue(name, &value,
333      static_cast<DWORD>(sizeof(value)), REG_DWORD);
334}
335
336bool RegKey::DeleteKey(const wchar_t* name) {
337  return (!key_) ? false : (ERROR_SUCCESS == SHDeleteKey(key_, name));
338}
339
340bool RegKey::DeleteValue(const wchar_t* value_name) {
341  DCHECK(value_name);
342  HRESULT result = RegDeleteValue(key_, value_name);
343  return (result == ERROR_SUCCESS);
344}
345
346bool RegKey::StartWatching() {
347  if (!watch_event_)
348    watch_event_ = CreateEvent(NULL, TRUE, FALSE, NULL);
349
350  DWORD filter = REG_NOTIFY_CHANGE_NAME |
351                 REG_NOTIFY_CHANGE_ATTRIBUTES |
352                 REG_NOTIFY_CHANGE_LAST_SET |
353                 REG_NOTIFY_CHANGE_SECURITY;
354
355  // Watch the registry key for a change of value.
356  HRESULT result = RegNotifyChangeKeyValue(key_, TRUE, filter,
357                                           watch_event_, TRUE);
358  if (SUCCEEDED(result)) {
359    return true;
360  } else {
361    CloseHandle(watch_event_);
362    watch_event_ = 0;
363    return false;
364  }
365}
366
367bool RegKey::StopWatching() {
368  if (watch_event_) {
369    CloseHandle(watch_event_);
370    watch_event_ = 0;
371    return true;
372  }
373  return false;
374}
375
376bool RegKey::HasChanged() {
377  if (watch_event_) {
378    if (WaitForSingleObject(watch_event_, 0) == WAIT_OBJECT_0) {
379      StartWatching();
380      return true;
381    }
382  }
383  return false;
384}
385
386}  // namespace win
387}  // namespace base
388