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