1 /* 2 * libjingle 3 * Copyright 2003-2008, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 // Registry configuration wrapers class implementation 29 // 30 // Change made by S. Ganesh - ganesh (at) google.com: 31 // Use SHQueryValueEx instead of RegQueryValueEx throughout. 32 // A call to the SHLWAPI function is essentially a call to the standard 33 // function but with post-processing: 34 // * to fix REG_SZ or REG_EXPAND_SZ data that is not properly null-terminated; 35 // * to expand REG_EXPAND_SZ data. 36 37 #include "talk/base/win32regkey.h" 38 39 #include <shlwapi.h> 40 41 #include "talk/base/common.h" 42 #include "talk/base/logging.h" 43 #include "talk/base/scoped_ptr.h" 44 45 namespace talk_base { 46 47 RegKey::RegKey() { 48 h_key_ = NULL; 49 } 50 51 RegKey::~RegKey() { 52 Close(); 53 } 54 55 HRESULT RegKey::Create(HKEY parent_key, const wchar_t* key_name) { 56 return Create(parent_key, 57 key_name, 58 REG_NONE, 59 REG_OPTION_NON_VOLATILE, 60 KEY_ALL_ACCESS, 61 NULL, 62 NULL); 63 } 64 65 HRESULT RegKey::Open(HKEY parent_key, const wchar_t* key_name) { 66 return Open(parent_key, key_name, KEY_ALL_ACCESS); 67 } 68 69 bool RegKey::HasValue(const TCHAR* value_name) const { 70 return (ERROR_SUCCESS == ::RegQueryValueEx(h_key_, value_name, NULL, 71 NULL, NULL, NULL)); 72 } 73 74 HRESULT RegKey::SetValue(const wchar_t* full_key_name, 75 const wchar_t* value_name, 76 DWORD value) { 77 ASSERT(full_key_name != NULL); 78 79 return SetValueStaticHelper(full_key_name, value_name, REG_DWORD, &value); 80 } 81 82 HRESULT RegKey::SetValue(const wchar_t* full_key_name, 83 const wchar_t* value_name, 84 DWORD64 value) { 85 ASSERT(full_key_name != NULL); 86 87 return SetValueStaticHelper(full_key_name, value_name, REG_QWORD, &value); 88 } 89 90 HRESULT RegKey::SetValue(const wchar_t* full_key_name, 91 const wchar_t* value_name, 92 float value) { 93 ASSERT(full_key_name != NULL); 94 95 return SetValueStaticHelper(full_key_name, value_name, 96 REG_BINARY, &value, sizeof(value)); 97 } 98 99 HRESULT RegKey::SetValue(const wchar_t* full_key_name, 100 const wchar_t* value_name, 101 double value) { 102 ASSERT(full_key_name != NULL); 103 104 return SetValueStaticHelper(full_key_name, value_name, 105 REG_BINARY, &value, sizeof(value)); 106 } 107 108 HRESULT RegKey::SetValue(const wchar_t* full_key_name, 109 const wchar_t* value_name, 110 const TCHAR* value) { 111 ASSERT(full_key_name != NULL); 112 ASSERT(value != NULL); 113 114 return SetValueStaticHelper(full_key_name, value_name, 115 REG_SZ, const_cast<wchar_t*>(value)); 116 } 117 118 HRESULT RegKey::SetValue(const wchar_t* full_key_name, 119 const wchar_t* value_name, 120 const uint8* value, 121 DWORD byte_count) { 122 ASSERT(full_key_name != NULL); 123 124 return SetValueStaticHelper(full_key_name, value_name, REG_BINARY, 125 const_cast<uint8*>(value), byte_count); 126 } 127 128 HRESULT RegKey::SetValueMultiSZ(const wchar_t* full_key_name, 129 const wchar_t* value_name, 130 const uint8* value, 131 DWORD byte_count) { 132 ASSERT(full_key_name != NULL); 133 134 return SetValueStaticHelper(full_key_name, value_name, REG_MULTI_SZ, 135 const_cast<uint8*>(value), byte_count); 136 } 137 138 HRESULT RegKey::GetValue(const wchar_t* full_key_name, 139 const wchar_t* value_name, 140 DWORD* value) { 141 ASSERT(full_key_name != NULL); 142 ASSERT(value != NULL); 143 144 return GetValueStaticHelper(full_key_name, value_name, REG_DWORD, value); 145 } 146 147 HRESULT RegKey::GetValue(const wchar_t* full_key_name, 148 const wchar_t* value_name, 149 DWORD64* value) { 150 ASSERT(full_key_name != NULL); 151 ASSERT(value != NULL); 152 153 return GetValueStaticHelper(full_key_name, value_name, REG_QWORD, value); 154 } 155 156 HRESULT RegKey::GetValue(const wchar_t* full_key_name, 157 const wchar_t* value_name, 158 float* value) { 159 ASSERT(value != NULL); 160 ASSERT(full_key_name != NULL); 161 162 DWORD byte_count = 0; 163 scoped_ptr<byte[]> buffer; 164 HRESULT hr = GetValueStaticHelper(full_key_name, value_name, 165 REG_BINARY, buffer.accept(), &byte_count); 166 if (SUCCEEDED(hr)) { 167 ASSERT(byte_count == sizeof(*value)); 168 if (byte_count == sizeof(*value)) { 169 *value = *reinterpret_cast<float*>(buffer.get()); 170 } 171 } 172 return hr; 173 } 174 175 HRESULT RegKey::GetValue(const wchar_t* full_key_name, 176 const wchar_t* value_name, 177 double* value) { 178 ASSERT(value != NULL); 179 ASSERT(full_key_name != NULL); 180 181 DWORD byte_count = 0; 182 scoped_ptr<byte[]> buffer; 183 HRESULT hr = GetValueStaticHelper(full_key_name, value_name, 184 REG_BINARY, buffer.accept(), &byte_count); 185 if (SUCCEEDED(hr)) { 186 ASSERT(byte_count == sizeof(*value)); 187 if (byte_count == sizeof(*value)) { 188 *value = *reinterpret_cast<double*>(buffer.get()); 189 } 190 } 191 return hr; 192 } 193 194 HRESULT RegKey::GetValue(const wchar_t* full_key_name, 195 const wchar_t* value_name, 196 wchar_t** value) { 197 ASSERT(full_key_name != NULL); 198 ASSERT(value != NULL); 199 200 return GetValueStaticHelper(full_key_name, value_name, REG_SZ, value); 201 } 202 203 HRESULT RegKey::GetValue(const wchar_t* full_key_name, 204 const wchar_t* value_name, 205 std::wstring* value) { 206 ASSERT(full_key_name != NULL); 207 ASSERT(value != NULL); 208 209 scoped_ptr<wchar_t[]> buffer; 210 HRESULT hr = RegKey::GetValue(full_key_name, value_name, buffer.accept()); 211 if (SUCCEEDED(hr)) { 212 value->assign(buffer.get()); 213 } 214 return hr; 215 } 216 217 HRESULT RegKey::GetValue(const wchar_t* full_key_name, 218 const wchar_t* value_name, 219 std::vector<std::wstring>* value) { 220 ASSERT(full_key_name != NULL); 221 ASSERT(value != NULL); 222 223 return GetValueStaticHelper(full_key_name, value_name, REG_MULTI_SZ, value); 224 } 225 226 HRESULT RegKey::GetValue(const wchar_t* full_key_name, 227 const wchar_t* value_name, 228 uint8** value, 229 DWORD* byte_count) { 230 ASSERT(full_key_name != NULL); 231 ASSERT(value != NULL); 232 ASSERT(byte_count != NULL); 233 234 return GetValueStaticHelper(full_key_name, value_name, 235 REG_BINARY, value, byte_count); 236 } 237 238 HRESULT RegKey::DeleteSubKey(const wchar_t* key_name) { 239 ASSERT(key_name != NULL); 240 ASSERT(h_key_ != NULL); 241 242 LONG res = ::RegDeleteKey(h_key_, key_name); 243 HRESULT hr = HRESULT_FROM_WIN32(res); 244 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || 245 hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) { 246 hr = S_FALSE; 247 } 248 return hr; 249 } 250 251 HRESULT RegKey::DeleteValue(const wchar_t* value_name) { 252 ASSERT(h_key_ != NULL); 253 254 LONG res = ::RegDeleteValue(h_key_, value_name); 255 HRESULT hr = HRESULT_FROM_WIN32(res); 256 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || 257 hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) { 258 hr = S_FALSE; 259 } 260 return hr; 261 } 262 263 HRESULT RegKey::Close() { 264 HRESULT hr = S_OK; 265 if (h_key_ != NULL) { 266 LONG res = ::RegCloseKey(h_key_); 267 hr = HRESULT_FROM_WIN32(res); 268 h_key_ = NULL; 269 } 270 return hr; 271 } 272 273 HRESULT RegKey::Create(HKEY parent_key, 274 const wchar_t* key_name, 275 wchar_t* lpszClass, 276 DWORD options, 277 REGSAM sam_desired, 278 LPSECURITY_ATTRIBUTES lpSecAttr, 279 LPDWORD lpdwDisposition) { 280 ASSERT(key_name != NULL); 281 ASSERT(parent_key != NULL); 282 283 DWORD dw = 0; 284 HKEY h_key = NULL; 285 LONG res = ::RegCreateKeyEx(parent_key, key_name, 0, lpszClass, options, 286 sam_desired, lpSecAttr, &h_key, &dw); 287 HRESULT hr = HRESULT_FROM_WIN32(res); 288 289 if (lpdwDisposition) { 290 *lpdwDisposition = dw; 291 } 292 293 // we have to close the currently opened key 294 // before replacing it with the new one 295 if (hr == S_OK) { 296 hr = Close(); 297 ASSERT(hr == S_OK); 298 h_key_ = h_key; 299 } 300 return hr; 301 } 302 303 HRESULT RegKey::Open(HKEY parent_key, 304 const wchar_t* key_name, 305 REGSAM sam_desired) { 306 ASSERT(key_name != NULL); 307 ASSERT(parent_key != NULL); 308 309 HKEY h_key = NULL; 310 LONG res = ::RegOpenKeyEx(parent_key, key_name, 0, sam_desired, &h_key); 311 HRESULT hr = HRESULT_FROM_WIN32(res); 312 313 // we have to close the currently opened key 314 // before replacing it with the new one 315 if (hr == S_OK) { 316 // close the currently opened key if any 317 hr = Close(); 318 ASSERT(hr == S_OK); 319 h_key_ = h_key; 320 } 321 return hr; 322 } 323 324 // save the key and all of its subkeys and values to a file 325 HRESULT RegKey::Save(const wchar_t* full_key_name, const wchar_t* file_name) { 326 ASSERT(full_key_name != NULL); 327 ASSERT(file_name != NULL); 328 329 std::wstring key_name(full_key_name); 330 HKEY h_key = GetRootKeyInfo(&key_name); 331 if (!h_key) { 332 return E_FAIL; 333 } 334 335 RegKey key; 336 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ); 337 if (FAILED(hr)) { 338 return hr; 339 } 340 341 AdjustCurrentProcessPrivilege(SE_BACKUP_NAME, true); 342 LONG res = ::RegSaveKey(key.h_key_, file_name, NULL); 343 AdjustCurrentProcessPrivilege(SE_BACKUP_NAME, false); 344 345 return HRESULT_FROM_WIN32(res); 346 } 347 348 // restore the key and all of its subkeys and values which are saved into a file 349 HRESULT RegKey::Restore(const wchar_t* full_key_name, 350 const wchar_t* file_name) { 351 ASSERT(full_key_name != NULL); 352 ASSERT(file_name != NULL); 353 354 std::wstring key_name(full_key_name); 355 HKEY h_key = GetRootKeyInfo(&key_name); 356 if (!h_key) { 357 return E_FAIL; 358 } 359 360 RegKey key; 361 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_WRITE); 362 if (FAILED(hr)) { 363 return hr; 364 } 365 366 AdjustCurrentProcessPrivilege(SE_RESTORE_NAME, true); 367 LONG res = ::RegRestoreKey(key.h_key_, file_name, REG_FORCE_RESTORE); 368 AdjustCurrentProcessPrivilege(SE_RESTORE_NAME, false); 369 370 return HRESULT_FROM_WIN32(res); 371 } 372 373 // check if the current key has the specified subkey 374 bool RegKey::HasSubkey(const wchar_t* key_name) const { 375 ASSERT(key_name != NULL); 376 377 RegKey key; 378 HRESULT hr = key.Open(h_key_, key_name, KEY_READ); 379 key.Close(); 380 return hr == S_OK; 381 } 382 383 // static flush key 384 HRESULT RegKey::FlushKey(const wchar_t* full_key_name) { 385 ASSERT(full_key_name != NULL); 386 387 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); 388 // get the root HKEY 389 std::wstring key_name(full_key_name); 390 HKEY h_key = GetRootKeyInfo(&key_name); 391 392 if (h_key != NULL) { 393 LONG res = ::RegFlushKey(h_key); 394 hr = HRESULT_FROM_WIN32(res); 395 } 396 return hr; 397 } 398 399 // static SET helper 400 HRESULT RegKey::SetValueStaticHelper(const wchar_t* full_key_name, 401 const wchar_t* value_name, 402 DWORD type, 403 LPVOID value, 404 DWORD byte_count) { 405 ASSERT(full_key_name != NULL); 406 407 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); 408 // get the root HKEY 409 std::wstring key_name(full_key_name); 410 HKEY h_key = GetRootKeyInfo(&key_name); 411 412 if (h_key != NULL) { 413 RegKey key; 414 hr = key.Create(h_key, key_name.c_str()); 415 if (hr == S_OK) { 416 switch (type) { 417 case REG_DWORD: 418 hr = key.SetValue(value_name, *(static_cast<DWORD*>(value))); 419 break; 420 case REG_QWORD: 421 hr = key.SetValue(value_name, *(static_cast<DWORD64*>(value))); 422 break; 423 case REG_SZ: 424 hr = key.SetValue(value_name, static_cast<const wchar_t*>(value)); 425 break; 426 case REG_BINARY: 427 hr = key.SetValue(value_name, static_cast<const uint8*>(value), 428 byte_count); 429 break; 430 case REG_MULTI_SZ: 431 hr = key.SetValue(value_name, static_cast<const uint8*>(value), 432 byte_count, type); 433 break; 434 default: 435 ASSERT(false); 436 hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH); 437 break; 438 } 439 // close the key after writing 440 HRESULT temp_hr = key.Close(); 441 if (hr == S_OK) { 442 hr = temp_hr; 443 } 444 } 445 } 446 return hr; 447 } 448 449 // static GET helper 450 HRESULT RegKey::GetValueStaticHelper(const wchar_t* full_key_name, 451 const wchar_t* value_name, 452 DWORD type, 453 LPVOID value, 454 DWORD* byte_count) { 455 ASSERT(full_key_name != NULL); 456 457 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); 458 // get the root HKEY 459 std::wstring key_name(full_key_name); 460 HKEY h_key = GetRootKeyInfo(&key_name); 461 462 if (h_key != NULL) { 463 RegKey key; 464 hr = key.Open(h_key, key_name.c_str(), KEY_READ); 465 if (hr == S_OK) { 466 switch (type) { 467 case REG_DWORD: 468 hr = key.GetValue(value_name, reinterpret_cast<DWORD*>(value)); 469 break; 470 case REG_QWORD: 471 hr = key.GetValue(value_name, reinterpret_cast<DWORD64*>(value)); 472 break; 473 case REG_SZ: 474 hr = key.GetValue(value_name, reinterpret_cast<wchar_t**>(value)); 475 break; 476 case REG_MULTI_SZ: 477 hr = key.GetValue(value_name, reinterpret_cast< 478 std::vector<std::wstring>*>(value)); 479 break; 480 case REG_BINARY: 481 hr = key.GetValue(value_name, reinterpret_cast<uint8**>(value), 482 byte_count); 483 break; 484 default: 485 ASSERT(false); 486 hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH); 487 break; 488 } 489 // close the key after writing 490 HRESULT temp_hr = key.Close(); 491 if (hr == S_OK) { 492 hr = temp_hr; 493 } 494 } 495 } 496 return hr; 497 } 498 499 // GET helper 500 HRESULT RegKey::GetValueHelper(const wchar_t* value_name, 501 DWORD* type, 502 uint8** value, 503 DWORD* byte_count) const { 504 ASSERT(byte_count != NULL); 505 ASSERT(value != NULL); 506 ASSERT(type != NULL); 507 508 // init return buffer 509 *value = NULL; 510 511 // get the size of the return data buffer 512 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, type, NULL, byte_count); 513 HRESULT hr = HRESULT_FROM_WIN32(res); 514 515 if (hr == S_OK) { 516 // if the value length is 0, nothing to do 517 if (*byte_count != 0) { 518 // allocate the buffer 519 *value = new byte[*byte_count]; 520 ASSERT(*value != NULL); 521 522 // make the call again to get the data 523 res = ::SHQueryValueEx(h_key_, value_name, NULL, 524 type, *value, byte_count); 525 hr = HRESULT_FROM_WIN32(res); 526 ASSERT(hr == S_OK); 527 } 528 } 529 return hr; 530 } 531 532 // Int32 Get 533 HRESULT RegKey::GetValue(const wchar_t* value_name, DWORD* value) const { 534 ASSERT(value != NULL); 535 536 DWORD type = 0; 537 DWORD byte_count = sizeof(DWORD); 538 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, &type, 539 value, &byte_count); 540 HRESULT hr = HRESULT_FROM_WIN32(res); 541 ASSERT((hr != S_OK) || (type == REG_DWORD)); 542 ASSERT((hr != S_OK) || (byte_count == sizeof(DWORD))); 543 return hr; 544 } 545 546 // Int64 Get 547 HRESULT RegKey::GetValue(const wchar_t* value_name, DWORD64* value) const { 548 ASSERT(value != NULL); 549 550 DWORD type = 0; 551 DWORD byte_count = sizeof(DWORD64); 552 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, &type, 553 value, &byte_count); 554 HRESULT hr = HRESULT_FROM_WIN32(res); 555 ASSERT((hr != S_OK) || (type == REG_QWORD)); 556 ASSERT((hr != S_OK) || (byte_count == sizeof(DWORD64))); 557 return hr; 558 } 559 560 // String Get 561 HRESULT RegKey::GetValue(const wchar_t* value_name, wchar_t** value) const { 562 ASSERT(value != NULL); 563 564 DWORD byte_count = 0; 565 DWORD type = 0; 566 567 // first get the size of the string buffer 568 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, 569 &type, NULL, &byte_count); 570 HRESULT hr = HRESULT_FROM_WIN32(res); 571 572 if (hr == S_OK) { 573 // allocate room for the string and a terminating \0 574 *value = new wchar_t[(byte_count / sizeof(wchar_t)) + 1]; 575 576 if ((*value) != NULL) { 577 if (byte_count != 0) { 578 // make the call again 579 res = ::SHQueryValueEx(h_key_, value_name, NULL, &type, 580 *value, &byte_count); 581 hr = HRESULT_FROM_WIN32(res); 582 } else { 583 (*value)[0] = L'\0'; 584 } 585 586 ASSERT((hr != S_OK) || (type == REG_SZ) || 587 (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ)); 588 } else { 589 hr = E_OUTOFMEMORY; 590 } 591 } 592 593 return hr; 594 } 595 596 // get a string value 597 HRESULT RegKey::GetValue(const wchar_t* value_name, std::wstring* value) const { 598 ASSERT(value != NULL); 599 600 DWORD byte_count = 0; 601 DWORD type = 0; 602 603 // first get the size of the string buffer 604 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, 605 &type, NULL, &byte_count); 606 HRESULT hr = HRESULT_FROM_WIN32(res); 607 608 if (hr == S_OK) { 609 if (byte_count != 0) { 610 // Allocate some memory and make the call again 611 value->resize(byte_count / sizeof(wchar_t) + 1); 612 res = ::SHQueryValueEx(h_key_, value_name, NULL, &type, 613 &value->at(0), &byte_count); 614 hr = HRESULT_FROM_WIN32(res); 615 value->resize(wcslen(value->data())); 616 } else { 617 value->clear(); 618 } 619 620 ASSERT((hr != S_OK) || (type == REG_SZ) || 621 (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ)); 622 } 623 624 return hr; 625 } 626 627 // convert REG_MULTI_SZ bytes to string array 628 HRESULT RegKey::MultiSZBytesToStringArray(const uint8* buffer, 629 DWORD byte_count, 630 std::vector<std::wstring>* value) { 631 ASSERT(buffer != NULL); 632 ASSERT(value != NULL); 633 634 const wchar_t* data = reinterpret_cast<const wchar_t*>(buffer); 635 DWORD data_len = byte_count / sizeof(wchar_t); 636 value->clear(); 637 if (data_len > 1) { 638 // must be terminated by two null characters 639 if (data[data_len - 1] != 0 || data[data_len - 2] != 0) { 640 return E_INVALIDARG; 641 } 642 643 // put null-terminated strings into arrays 644 while (*data) { 645 std::wstring str(data); 646 value->push_back(str); 647 data += str.length() + 1; 648 } 649 } 650 return S_OK; 651 } 652 653 // get a std::vector<std::wstring> value from REG_MULTI_SZ type 654 HRESULT RegKey::GetValue(const wchar_t* value_name, 655 std::vector<std::wstring>* value) const { 656 ASSERT(value != NULL); 657 658 DWORD byte_count = 0; 659 DWORD type = 0; 660 uint8* buffer = 0; 661 662 // first get the size of the buffer 663 HRESULT hr = GetValueHelper(value_name, &type, &buffer, &byte_count); 664 ASSERT((hr != S_OK) || (type == REG_MULTI_SZ)); 665 666 if (SUCCEEDED(hr)) { 667 hr = MultiSZBytesToStringArray(buffer, byte_count, value); 668 } 669 670 return hr; 671 } 672 673 // Binary data Get 674 HRESULT RegKey::GetValue(const wchar_t* value_name, 675 uint8** value, 676 DWORD* byte_count) const { 677 ASSERT(byte_count != NULL); 678 ASSERT(value != NULL); 679 680 DWORD type = 0; 681 HRESULT hr = GetValueHelper(value_name, &type, value, byte_count); 682 ASSERT((hr != S_OK) || (type == REG_MULTI_SZ) || (type == REG_BINARY)); 683 return hr; 684 } 685 686 // Raw data get 687 HRESULT RegKey::GetValue(const wchar_t* value_name, 688 uint8** value, 689 DWORD* byte_count, 690 DWORD*type) const { 691 ASSERT(type != NULL); 692 ASSERT(byte_count != NULL); 693 ASSERT(value != NULL); 694 695 return GetValueHelper(value_name, type, value, byte_count); 696 } 697 698 // Int32 set 699 HRESULT RegKey::SetValue(const wchar_t* value_name, DWORD value) const { 700 ASSERT(h_key_ != NULL); 701 702 LONG res = ::RegSetValueEx(h_key_, value_name, NULL, REG_DWORD, 703 reinterpret_cast<const uint8*>(&value), 704 sizeof(DWORD)); 705 return HRESULT_FROM_WIN32(res); 706 } 707 708 // Int64 set 709 HRESULT RegKey::SetValue(const wchar_t* value_name, DWORD64 value) const { 710 ASSERT(h_key_ != NULL); 711 712 LONG res = ::RegSetValueEx(h_key_, value_name, NULL, REG_QWORD, 713 reinterpret_cast<const uint8*>(&value), 714 sizeof(DWORD64)); 715 return HRESULT_FROM_WIN32(res); 716 } 717 718 // String set 719 HRESULT RegKey::SetValue(const wchar_t* value_name, 720 const wchar_t* value) const { 721 ASSERT(value != NULL); 722 ASSERT(h_key_ != NULL); 723 724 LONG res = ::RegSetValueEx(h_key_, value_name, NULL, REG_SZ, 725 reinterpret_cast<const uint8*>(value), 726 (lstrlen(value) + 1) * sizeof(wchar_t)); 727 return HRESULT_FROM_WIN32(res); 728 } 729 730 // Binary data set 731 HRESULT RegKey::SetValue(const wchar_t* value_name, 732 const uint8* value, 733 DWORD byte_count) const { 734 ASSERT(h_key_ != NULL); 735 736 // special case - if 'value' is NULL make sure byte_count is zero 737 if (value == NULL) { 738 byte_count = 0; 739 } 740 741 LONG res = ::RegSetValueEx(h_key_, value_name, NULL, 742 REG_BINARY, value, byte_count); 743 return HRESULT_FROM_WIN32(res); 744 } 745 746 // Raw data set 747 HRESULT RegKey::SetValue(const wchar_t* value_name, 748 const uint8* value, 749 DWORD byte_count, 750 DWORD type) const { 751 ASSERT(value != NULL); 752 ASSERT(h_key_ != NULL); 753 754 LONG res = ::RegSetValueEx(h_key_, value_name, NULL, type, value, byte_count); 755 return HRESULT_FROM_WIN32(res); 756 } 757 758 bool RegKey::HasKey(const wchar_t* full_key_name) { 759 ASSERT(full_key_name != NULL); 760 761 // get the root HKEY 762 std::wstring key_name(full_key_name); 763 HKEY h_key = GetRootKeyInfo(&key_name); 764 765 if (h_key != NULL) { 766 RegKey key; 767 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ); 768 key.Close(); 769 return S_OK == hr; 770 } 771 return false; 772 } 773 774 // static version of HasValue 775 bool RegKey::HasValue(const wchar_t* full_key_name, const wchar_t* value_name) { 776 ASSERT(full_key_name != NULL); 777 778 bool has_value = false; 779 // get the root HKEY 780 std::wstring key_name(full_key_name); 781 HKEY h_key = GetRootKeyInfo(&key_name); 782 783 if (h_key != NULL) { 784 RegKey key; 785 if (key.Open(h_key, key_name.c_str(), KEY_READ) == S_OK) { 786 has_value = key.HasValue(value_name); 787 key.Close(); 788 } 789 } 790 return has_value; 791 } 792 793 HRESULT RegKey::GetValueType(const wchar_t* full_key_name, 794 const wchar_t* value_name, 795 DWORD* value_type) { 796 ASSERT(full_key_name != NULL); 797 ASSERT(value_type != NULL); 798 799 *value_type = REG_NONE; 800 801 std::wstring key_name(full_key_name); 802 HKEY h_key = GetRootKeyInfo(&key_name); 803 804 RegKey key; 805 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ); 806 if (SUCCEEDED(hr)) { 807 LONG res = ::SHQueryValueEx(key.h_key_, value_name, NULL, value_type, 808 NULL, NULL); 809 if (res != ERROR_SUCCESS) { 810 hr = HRESULT_FROM_WIN32(res); 811 } 812 } 813 814 return hr; 815 } 816 817 HRESULT RegKey::DeleteKey(const wchar_t* full_key_name) { 818 ASSERT(full_key_name != NULL); 819 820 return DeleteKey(full_key_name, true); 821 } 822 823 HRESULT RegKey::DeleteKey(const wchar_t* full_key_name, bool recursively) { 824 ASSERT(full_key_name != NULL); 825 826 // need to open the parent key first 827 // get the root HKEY 828 std::wstring key_name(full_key_name); 829 HKEY h_key = GetRootKeyInfo(&key_name); 830 831 // get the parent key 832 std::wstring parent_key(GetParentKeyInfo(&key_name)); 833 834 RegKey key; 835 HRESULT hr = key.Open(h_key, parent_key.c_str()); 836 837 if (hr == S_OK) { 838 hr = recursively ? key.RecurseDeleteSubKey(key_name.c_str()) 839 : key.DeleteSubKey(key_name.c_str()); 840 } else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || 841 hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) { 842 hr = S_FALSE; 843 } 844 845 key.Close(); 846 return hr; 847 } 848 849 HRESULT RegKey::DeleteValue(const wchar_t* full_key_name, 850 const wchar_t* value_name) { 851 ASSERT(full_key_name != NULL); 852 853 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); 854 // get the root HKEY 855 std::wstring key_name(full_key_name); 856 HKEY h_key = GetRootKeyInfo(&key_name); 857 858 if (h_key != NULL) { 859 RegKey key; 860 hr = key.Open(h_key, key_name.c_str()); 861 if (hr == S_OK) { 862 hr = key.DeleteValue(value_name); 863 key.Close(); 864 } 865 } 866 return hr; 867 } 868 869 HRESULT RegKey::RecurseDeleteSubKey(const wchar_t* key_name) { 870 ASSERT(key_name != NULL); 871 872 RegKey key; 873 HRESULT hr = key.Open(h_key_, key_name); 874 875 if (hr == S_OK) { 876 // enumerate all subkeys of this key and recursivelly delete them 877 FILETIME time = {0}; 878 wchar_t key_name_buf[kMaxKeyNameChars] = {0}; 879 DWORD key_name_buf_size = kMaxKeyNameChars; 880 while (hr == S_OK && 881 ::RegEnumKeyEx(key.h_key_, 0, key_name_buf, &key_name_buf_size, 882 NULL, NULL, NULL, &time) == ERROR_SUCCESS) { 883 hr = key.RecurseDeleteSubKey(key_name_buf); 884 885 // restore the buffer size 886 key_name_buf_size = kMaxKeyNameChars; 887 } 888 // close the top key 889 key.Close(); 890 } 891 892 if (hr == S_OK) { 893 // the key has no more children keys 894 // delete the key and all of its values 895 hr = DeleteSubKey(key_name); 896 } 897 898 return hr; 899 } 900 901 HKEY RegKey::GetRootKeyInfo(std::wstring* full_key_name) { 902 ASSERT(full_key_name != NULL); 903 904 HKEY h_key = NULL; 905 // get the root HKEY 906 size_t index = full_key_name->find(L'\\'); 907 std::wstring root_key; 908 909 if (index == -1) { 910 root_key = *full_key_name; 911 *full_key_name = L""; 912 } else { 913 root_key = full_key_name->substr(0, index); 914 *full_key_name = full_key_name->substr(index + 1, 915 full_key_name->length() - index - 1); 916 } 917 918 for (std::wstring::iterator iter = root_key.begin(); 919 iter != root_key.end(); ++iter) { 920 *iter = toupper(*iter); 921 } 922 923 if (!root_key.compare(L"HKLM") || 924 !root_key.compare(L"HKEY_LOCAL_MACHINE")) { 925 h_key = HKEY_LOCAL_MACHINE; 926 } else if (!root_key.compare(L"HKCU") || 927 !root_key.compare(L"HKEY_CURRENT_USER")) { 928 h_key = HKEY_CURRENT_USER; 929 } else if (!root_key.compare(L"HKU") || 930 !root_key.compare(L"HKEY_USERS")) { 931 h_key = HKEY_USERS; 932 } else if (!root_key.compare(L"HKCR") || 933 !root_key.compare(L"HKEY_CLASSES_ROOT")) { 934 h_key = HKEY_CLASSES_ROOT; 935 } 936 937 return h_key; 938 } 939 940 941 // Returns true if this key name is 'safe' for deletion 942 // (doesn't specify a key root) 943 bool RegKey::SafeKeyNameForDeletion(const wchar_t* key_name) { 944 ASSERT(key_name != NULL); 945 std::wstring key(key_name); 946 947 HKEY root_key = GetRootKeyInfo(&key); 948 949 if (!root_key) { 950 key = key_name; 951 } 952 if (key.empty()) { 953 return false; 954 } 955 bool found_subkey = false, backslash_found = false; 956 for (size_t i = 0 ; i < key.length() ; ++i) { 957 if (key[i] == L'\\') { 958 backslash_found = true; 959 } else if (backslash_found) { 960 found_subkey = true; 961 break; 962 } 963 } 964 return (root_key == HKEY_USERS) ? found_subkey : true; 965 } 966 967 std::wstring RegKey::GetParentKeyInfo(std::wstring* key_name) { 968 ASSERT(key_name != NULL); 969 970 // get the parent key 971 size_t index = key_name->rfind(L'\\'); 972 std::wstring parent_key; 973 if (index == -1) { 974 parent_key = L""; 975 } else { 976 parent_key = key_name->substr(0, index); 977 *key_name = key_name->substr(index + 1, key_name->length() - index - 1); 978 } 979 980 return parent_key; 981 } 982 983 // get the number of values for this key 984 uint32 RegKey::GetValueCount() { 985 DWORD num_values = 0; 986 987 LONG res = ::RegQueryInfoKey( 988 h_key_, // key handle 989 NULL, // buffer for class name 990 NULL, // size of class string 991 NULL, // reserved 992 NULL, // number of subkeys 993 NULL, // longest subkey size 994 NULL, // longest class string 995 &num_values, // number of values for this key 996 NULL, // longest value name 997 NULL, // longest value data 998 NULL, // security descriptor 999 NULL); // last write time 1000 1001 ASSERT(res == ERROR_SUCCESS); 1002 return num_values; 1003 } 1004 1005 // Enumerators for the value_names for this key 1006 1007 // Called to get the value name for the given value name index 1008 // Use GetValueCount() to get the total value_name count for this key 1009 // Returns failure if no key at the specified index 1010 HRESULT RegKey::GetValueNameAt(int index, std::wstring* value_name, 1011 DWORD* type) { 1012 ASSERT(value_name != NULL); 1013 1014 LONG res = ERROR_SUCCESS; 1015 wchar_t value_name_buf[kMaxValueNameChars] = {0}; 1016 DWORD value_name_buf_size = kMaxValueNameChars; 1017 res = ::RegEnumValue(h_key_, index, value_name_buf, &value_name_buf_size, 1018 NULL, type, NULL, NULL); 1019 1020 if (res == ERROR_SUCCESS) { 1021 value_name->assign(value_name_buf); 1022 } 1023 1024 return HRESULT_FROM_WIN32(res); 1025 } 1026 1027 uint32 RegKey::GetSubkeyCount() { 1028 // number of values for key 1029 DWORD num_subkeys = 0; 1030 1031 LONG res = ::RegQueryInfoKey( 1032 h_key_, // key handle 1033 NULL, // buffer for class name 1034 NULL, // size of class string 1035 NULL, // reserved 1036 &num_subkeys, // number of subkeys 1037 NULL, // longest subkey size 1038 NULL, // longest class string 1039 NULL, // number of values for this key 1040 NULL, // longest value name 1041 NULL, // longest value data 1042 NULL, // security descriptor 1043 NULL); // last write time 1044 1045 ASSERT(res == ERROR_SUCCESS); 1046 return num_subkeys; 1047 } 1048 1049 HRESULT RegKey::GetSubkeyNameAt(int index, std::wstring* key_name) { 1050 ASSERT(key_name != NULL); 1051 1052 LONG res = ERROR_SUCCESS; 1053 wchar_t key_name_buf[kMaxKeyNameChars] = {0}; 1054 DWORD key_name_buf_size = kMaxKeyNameChars; 1055 1056 res = ::RegEnumKeyEx(h_key_, index, key_name_buf, &key_name_buf_size, 1057 NULL, NULL, NULL, NULL); 1058 1059 if (res == ERROR_SUCCESS) { 1060 key_name->assign(key_name_buf); 1061 } 1062 1063 return HRESULT_FROM_WIN32(res); 1064 } 1065 1066 // Is the key empty: having no sub-keys and values 1067 bool RegKey::IsKeyEmpty(const wchar_t* full_key_name) { 1068 ASSERT(full_key_name != NULL); 1069 1070 bool is_empty = true; 1071 1072 // Get the root HKEY 1073 std::wstring key_name(full_key_name); 1074 HKEY h_key = GetRootKeyInfo(&key_name); 1075 1076 // Open the key to check 1077 if (h_key != NULL) { 1078 RegKey key; 1079 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ); 1080 if (SUCCEEDED(hr)) { 1081 is_empty = key.GetSubkeyCount() == 0 && key.GetValueCount() == 0; 1082 key.Close(); 1083 } 1084 } 1085 1086 return is_empty; 1087 } 1088 1089 bool AdjustCurrentProcessPrivilege(const TCHAR* privilege, bool to_enable) { 1090 ASSERT(privilege != NULL); 1091 1092 bool ret = false; 1093 HANDLE token; 1094 if (::OpenProcessToken(::GetCurrentProcess(), 1095 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) { 1096 LUID luid; 1097 memset(&luid, 0, sizeof(luid)); 1098 if (::LookupPrivilegeValue(NULL, privilege, &luid)) { 1099 TOKEN_PRIVILEGES privs; 1100 privs.PrivilegeCount = 1; 1101 privs.Privileges[0].Luid = luid; 1102 privs.Privileges[0].Attributes = to_enable ? SE_PRIVILEGE_ENABLED : 0; 1103 if (::AdjustTokenPrivileges(token, FALSE, &privs, 0, NULL, 0)) { 1104 ret = true; 1105 } else { 1106 LOG_GLE(LS_ERROR) << "AdjustTokenPrivileges failed"; 1107 } 1108 } else { 1109 LOG_GLE(LS_ERROR) << "LookupPrivilegeValue failed"; 1110 } 1111 CloseHandle(token); 1112 } else { 1113 LOG_GLE(LS_ERROR) << "OpenProcessToken(GetCurrentProcess) failed"; 1114 } 1115 1116 return ret; 1117 } 1118 1119 } // namespace talk_base 1120