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