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. 4 5 #include "base/win/registry.h" 6 7 #include <shlwapi.h> 8 #include <algorithm> 9 10 #include "base/logging.h" 11 #include "base/strings/string_util.h" 12 #include "base/threading/thread_restrictions.h" 13 14 #pragma comment(lib, "shlwapi.lib") // for SHDeleteKey 15 16 namespace base { 17 namespace win { 18 19 namespace { 20 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; 25 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); 31 } 32 33 } // namespace 34 35 // RegKey ---------------------------------------------------------------------- 36 37 RegKey::RegKey() 38 : key_(NULL), 39 watch_event_(0) { 40 } 41 42 RegKey::RegKey(HKEY key) 43 : key_(key), 44 watch_event_(0) { 45 } 46 47 RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) 48 : key_(NULL), 49 watch_event_(0) { 50 if (rootkey) { 51 if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK)) 52 Create(rootkey, subkey, access); 53 else 54 Open(rootkey, subkey, access); 55 } else { 56 DCHECK(!subkey); 57 } 58 } 59 60 RegKey::~RegKey() { 61 Close(); 62 } 63 64 LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) { 65 DWORD disposition_value; 66 return CreateWithDisposition(rootkey, subkey, &disposition_value, access); 67 } 68 69 LONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey, 70 DWORD* disposition, REGSAM access) { 71 DCHECK(rootkey && subkey && access && disposition); 72 Close(); 73 74 LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL, 75 REG_OPTION_NON_VOLATILE, access, NULL, &key_, 76 disposition); 77 return result; 78 } 79 80 LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) { 81 DCHECK(name && access); 82 HKEY subkey = NULL; 83 LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE, 84 access, NULL, &subkey, NULL); 85 Close(); 86 87 key_ = subkey; 88 return result; 89 } 90 91 LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) { 92 DCHECK(rootkey && subkey && access); 93 Close(); 94 95 LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &key_); 96 return result; 97 } 98 99 LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) { 100 DCHECK(relative_key_name && access); 101 HKEY subkey = NULL; 102 LONG result = RegOpenKeyEx(key_, relative_key_name, 0, access, &subkey); 103 104 // We have to close the current opened key before replacing it with the new 105 // one. 106 Close(); 107 108 key_ = subkey; 109 return result; 110 } 111 112 void RegKey::Close() { 113 StopWatching(); 114 if (key_) { 115 ::RegCloseKey(key_); 116 key_ = NULL; 117 } 118 } 119 120 void RegKey::Set(HKEY key) { 121 if (key_ != key) { 122 Close(); 123 key_ = key; 124 } 125 } 126 127 HKEY RegKey::Take() { 128 StopWatching(); 129 HKEY key = key_; 130 key_ = NULL; 131 return key; 132 } 133 134 bool RegKey::HasValue(const wchar_t* name) const { 135 return RegQueryValueEx(key_, name, 0, NULL, NULL, NULL) == ERROR_SUCCESS; 136 } 137 138 DWORD RegKey::GetValueCount() const { 139 DWORD count = 0; 140 LONG result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count, 141 NULL, NULL, NULL, NULL); 142 return (result == ERROR_SUCCESS) ? count : 0; 143 } 144 145 LONG RegKey::GetValueNameAt(int index, std::wstring* name) const { 146 wchar_t buf[256]; 147 DWORD bufsize = arraysize(buf); 148 LONG r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL, NULL, NULL); 149 if (r == ERROR_SUCCESS) 150 *name = buf; 151 152 return r; 153 } 154 155 LONG RegKey::DeleteKey(const wchar_t* name) { 156 DCHECK(key_); 157 DCHECK(name); 158 LONG result = SHDeleteKey(key_, name); 159 return result; 160 } 161 162 LONG RegKey::DeleteValue(const wchar_t* value_name) { 163 DCHECK(key_); 164 LONG result = RegDeleteValue(key_, value_name); 165 return result; 166 } 167 168 LONG RegKey::ReadValueDW(const wchar_t* name, DWORD* out_value) const { 169 DCHECK(out_value); 170 DWORD type = REG_DWORD; 171 DWORD size = sizeof(DWORD); 172 DWORD local_value = 0; 173 LONG result = ReadValue(name, &local_value, &size, &type); 174 if (result == ERROR_SUCCESS) { 175 if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD)) 176 *out_value = local_value; 177 else 178 result = ERROR_CANTREAD; 179 } 180 181 return result; 182 } 183 184 LONG RegKey::ReadInt64(const wchar_t* name, int64* out_value) const { 185 DCHECK(out_value); 186 DWORD type = REG_QWORD; 187 int64 local_value = 0; 188 DWORD size = sizeof(local_value); 189 LONG result = ReadValue(name, &local_value, &size, &type); 190 if (result == ERROR_SUCCESS) { 191 if ((type == REG_QWORD || type == REG_BINARY) && 192 size == sizeof(local_value)) 193 *out_value = local_value; 194 else 195 result = ERROR_CANTREAD; 196 } 197 198 return result; 199 } 200 201 LONG RegKey::ReadValue(const wchar_t* name, std::wstring* out_value) const { 202 DCHECK(out_value); 203 const size_t kMaxStringLength = 1024; // This is after expansion. 204 // Use the one of the other forms of ReadValue if 1024 is too small for you. 205 wchar_t raw_value[kMaxStringLength]; 206 DWORD type = REG_SZ, size = sizeof(raw_value); 207 LONG result = ReadValue(name, raw_value, &size, &type); 208 if (result == ERROR_SUCCESS) { 209 if (type == REG_SZ) { 210 *out_value = raw_value; 211 } else if (type == REG_EXPAND_SZ) { 212 wchar_t expanded[kMaxStringLength]; 213 size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength); 214 // Success: returns the number of wchar_t's copied 215 // Fail: buffer too small, returns the size required 216 // Fail: other, returns 0 217 if (size == 0 || size > kMaxStringLength) { 218 result = ERROR_MORE_DATA; 219 } else { 220 *out_value = expanded; 221 } 222 } else { 223 // Not a string. Oops. 224 result = ERROR_CANTREAD; 225 } 226 } 227 228 return result; 229 } 230 231 LONG RegKey::ReadValue(const wchar_t* name, 232 void* data, 233 DWORD* dsize, 234 DWORD* dtype) const { 235 LONG result = RegQueryValueEx(key_, name, 0, dtype, 236 reinterpret_cast<LPBYTE>(data), dsize); 237 return result; 238 } 239 240 LONG RegKey::ReadValues(const wchar_t* name, 241 std::vector<std::wstring>* values) { 242 values->clear(); 243 244 DWORD type = REG_MULTI_SZ; 245 DWORD size = 0; 246 LONG result = ReadValue(name, NULL, &size, &type); 247 if (FAILED(result) || size == 0) 248 return result; 249 250 if (type != REG_MULTI_SZ) 251 return ERROR_CANTREAD; 252 253 std::vector<wchar_t> buffer(size / sizeof(wchar_t)); 254 result = ReadValue(name, &buffer[0], &size, NULL); 255 if (FAILED(result) || size == 0) 256 return result; 257 258 // Parse the double-null-terminated list of strings. 259 // Note: This code is paranoid to not read outside of |buf|, in the case where 260 // it may not be properly terminated. 261 const wchar_t* entry = &buffer[0]; 262 const wchar_t* buffer_end = entry + (size / sizeof(wchar_t)); 263 while (entry < buffer_end && entry[0] != '\0') { 264 const wchar_t* entry_end = std::find(entry, buffer_end, L'\0'); 265 values->push_back(std::wstring(entry, entry_end)); 266 entry = entry_end + 1; 267 } 268 return 0; 269 } 270 271 LONG RegKey::WriteValue(const wchar_t* name, DWORD in_value) { 272 return WriteValue( 273 name, &in_value, static_cast<DWORD>(sizeof(in_value)), REG_DWORD); 274 } 275 276 LONG RegKey::WriteValue(const wchar_t * name, const wchar_t* in_value) { 277 return WriteValue(name, in_value, 278 static_cast<DWORD>(sizeof(*in_value) * (wcslen(in_value) + 1)), REG_SZ); 279 } 280 281 LONG RegKey::WriteValue(const wchar_t* name, 282 const void* data, 283 DWORD dsize, 284 DWORD dtype) { 285 DCHECK(data || !dsize); 286 287 LONG result = RegSetValueEx(key_, name, 0, dtype, 288 reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize); 289 return result; 290 } 291 292 LONG RegKey::StartWatching() { 293 DCHECK(key_); 294 if (!watch_event_) 295 watch_event_ = CreateEvent(NULL, TRUE, FALSE, NULL); 296 297 DWORD filter = REG_NOTIFY_CHANGE_NAME | 298 REG_NOTIFY_CHANGE_ATTRIBUTES | 299 REG_NOTIFY_CHANGE_LAST_SET | 300 REG_NOTIFY_CHANGE_SECURITY; 301 302 // Watch the registry key for a change of value. 303 LONG result = RegNotifyChangeKeyValue(key_, TRUE, filter, watch_event_, TRUE); 304 if (result != ERROR_SUCCESS) { 305 CloseHandle(watch_event_); 306 watch_event_ = 0; 307 } 308 309 return result; 310 } 311 312 bool RegKey::HasChanged() { 313 if (watch_event_) { 314 if (WaitForSingleObject(watch_event_, 0) == WAIT_OBJECT_0) { 315 StartWatching(); 316 return true; 317 } 318 } 319 return false; 320 } 321 322 LONG RegKey::StopWatching() { 323 LONG result = ERROR_INVALID_HANDLE; 324 if (watch_event_) { 325 CloseHandle(watch_event_); 326 watch_event_ = 0; 327 result = ERROR_SUCCESS; 328 } 329 return result; 330 } 331 332 // RegistryValueIterator ------------------------------------------------------ 333 334 RegistryValueIterator::RegistryValueIterator(HKEY root_key, 335 const wchar_t* folder_key) 336 : name_(MAX_PATH, L'\0'), 337 value_(MAX_PATH, L'\0') { 338 LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_); 339 if (result != ERROR_SUCCESS) { 340 key_ = NULL; 341 } else { 342 DWORD count = 0; 343 result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count, 344 NULL, NULL, NULL, NULL); 345 346 if (result != ERROR_SUCCESS) { 347 ::RegCloseKey(key_); 348 key_ = NULL; 349 } else { 350 index_ = count - 1; 351 } 352 } 353 354 Read(); 355 } 356 357 RegistryValueIterator::~RegistryValueIterator() { 358 if (key_) 359 ::RegCloseKey(key_); 360 } 361 362 DWORD RegistryValueIterator::ValueCount() const { 363 DWORD count = 0; 364 LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, 365 &count, NULL, NULL, NULL, NULL); 366 if (result != ERROR_SUCCESS) 367 return 0; 368 369 return count; 370 } 371 372 bool RegistryValueIterator::Valid() const { 373 return key_ != NULL && index_ >= 0; 374 } 375 376 void RegistryValueIterator::operator++() { 377 --index_; 378 Read(); 379 } 380 381 bool RegistryValueIterator::Read() { 382 if (Valid()) { 383 DWORD capacity = static_cast<DWORD>(name_.capacity()); 384 DWORD name_size = capacity; 385 // |value_size_| is in bytes. Reserve the last character for a NUL. 386 value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t)); 387 LONG result = ::RegEnumValue( 388 key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_, 389 reinterpret_cast<BYTE*>(vector_as_array(&value_)), &value_size_); 390 391 if (result == ERROR_MORE_DATA) { 392 // Registry key names are limited to 255 characters and fit within 393 // MAX_PATH (which is 260) but registry value names can use up to 16,383 394 // characters and the value itself is not limited 395 // (from http://msdn.microsoft.com/en-us/library/windows/desktop/ 396 // ms724872(v=vs.85).aspx). 397 // Resize the buffers and retry if their size caused the failure. 398 DWORD value_size_in_wchars = to_wchar_size(value_size_); 399 if (value_size_in_wchars + 1 > value_.size()) 400 value_.resize(value_size_in_wchars + 1, L'\0'); 401 value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t)); 402 name_size = name_size == capacity ? MAX_REGISTRY_NAME_SIZE : capacity; 403 result = ::RegEnumValue( 404 key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_, 405 reinterpret_cast<BYTE*>(vector_as_array(&value_)), &value_size_); 406 } 407 408 if (result == ERROR_SUCCESS) { 409 DCHECK_LT(to_wchar_size(value_size_), value_.size()); 410 value_[to_wchar_size(value_size_)] = L'\0'; 411 return true; 412 } 413 } 414 415 name_[0] = L'\0'; 416 value_[0] = L'\0'; 417 value_size_ = 0; 418 return false; 419 } 420 421 // RegistryKeyIterator -------------------------------------------------------- 422 423 RegistryKeyIterator::RegistryKeyIterator(HKEY root_key, 424 const wchar_t* folder_key) { 425 LONG result = RegOpenKeyEx(root_key, folder_key, 0, KEY_READ, &key_); 426 if (result != ERROR_SUCCESS) { 427 key_ = NULL; 428 } else { 429 DWORD count = 0; 430 LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL, 431 NULL, NULL, NULL, NULL, NULL); 432 433 if (result != ERROR_SUCCESS) { 434 ::RegCloseKey(key_); 435 key_ = NULL; 436 } else { 437 index_ = count - 1; 438 } 439 } 440 441 Read(); 442 } 443 444 RegistryKeyIterator::~RegistryKeyIterator() { 445 if (key_) 446 ::RegCloseKey(key_); 447 } 448 449 DWORD RegistryKeyIterator::SubkeyCount() const { 450 DWORD count = 0; 451 LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL, 452 NULL, NULL, NULL, NULL, NULL); 453 if (result != ERROR_SUCCESS) 454 return 0; 455 456 return count; 457 } 458 459 bool RegistryKeyIterator::Valid() const { 460 return key_ != NULL && index_ >= 0; 461 } 462 463 void RegistryKeyIterator::operator++() { 464 --index_; 465 Read(); 466 } 467 468 bool RegistryKeyIterator::Read() { 469 if (Valid()) { 470 DWORD ncount = arraysize(name_); 471 FILETIME written; 472 LONG r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL, 473 NULL, &written); 474 if (ERROR_SUCCESS == r) 475 return true; 476 } 477 478 name_[0] = '\0'; 479 return false; 480 } 481 482 } // namespace win 483 } // namespace base 484