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