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