3 * Copyright 2003-2008, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
28 // Registry configuration wrapers class implementation
30 // Change made by S. Ganesh - ganesh@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.
37 #include "talk/base/win32regkey.h"
41 #include "talk/base/common.h"
42 #include "talk/base/logging.h"
43 #include "talk/base/scoped_ptr.h"
55 HRESULT RegKey::Create(HKEY parent_key, const wchar_t* key_name) {
56 return Create(parent_key,
59 REG_OPTION_NON_VOLATILE,
65 HRESULT RegKey::Open(HKEY parent_key, const wchar_t* key_name) {
66 return Open(parent_key, key_name, KEY_ALL_ACCESS);
69 bool RegKey::HasValue(const TCHAR* value_name) const {
70 return (ERROR_SUCCESS == ::RegQueryValueEx(h_key_, value_name, NULL,
74 HRESULT RegKey::SetValue(const wchar_t* full_key_name,
75 const wchar_t* value_name,
77 ASSERT(full_key_name != NULL);
79 return SetValueStaticHelper(full_key_name, value_name, REG_DWORD, &value);
82 HRESULT RegKey::SetValue(const wchar_t* full_key_name,
83 const wchar_t* value_name,
85 ASSERT(full_key_name != NULL);
87 return SetValueStaticHelper(full_key_name, value_name, REG_QWORD, &value);
90 HRESULT RegKey::SetValue(const wchar_t* full_key_name,
91 const wchar_t* value_name,
93 ASSERT(full_key_name != NULL);
95 return SetValueStaticHelper(full_key_name, value_name,
96 REG_BINARY, &value, sizeof(value));
99 HRESULT RegKey::SetValue(const wchar_t* full_key_name,
100 const wchar_t* value_name,
102 ASSERT(full_key_name != NULL);
104 return SetValueStaticHelper(full_key_name, value_name,
105 REG_BINARY, &value, sizeof(value));
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);
114 return SetValueStaticHelper(full_key_name, value_name,
115 REG_SZ, const_cast<wchar_t*>(value));
118 HRESULT RegKey::SetValue(const wchar_t* full_key_name,
119 const wchar_t* value_name,
122 ASSERT(full_key_name != NULL);
124 return SetValueStaticHelper(full_key_name, value_name, REG_BINARY,
125 const_cast<uint8*>(value), byte_count);
128 HRESULT RegKey::SetValueMultiSZ(const wchar_t* full_key_name,
129 const wchar_t* value_name,
132 ASSERT(full_key_name != NULL);
134 return SetValueStaticHelper(full_key_name, value_name, REG_MULTI_SZ,
135 const_cast<uint8*>(value), byte_count);
138 HRESULT RegKey::GetValue(const wchar_t* full_key_name,
139 const wchar_t* value_name,
141 ASSERT(full_key_name != NULL);
142 ASSERT(value != NULL);
144 return GetValueStaticHelper(full_key_name, value_name, REG_DWORD, value);
147 HRESULT RegKey::GetValue(const wchar_t* full_key_name,
148 const wchar_t* value_name,
150 ASSERT(full_key_name != NULL);
151 ASSERT(value != NULL);
153 return GetValueStaticHelper(full_key_name, value_name, REG_QWORD, value);
156 HRESULT RegKey::GetValue(const wchar_t* full_key_name,
157 const wchar_t* value_name,
159 ASSERT(value != NULL);
160 ASSERT(full_key_name != NULL);
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);
167 ASSERT(byte_count == sizeof(*value));
168 if (byte_count == sizeof(*value)) {
169 *value = *reinterpret_cast<float*>(buffer.get());
175 HRESULT RegKey::GetValue(const wchar_t* full_key_name,
176 const wchar_t* value_name,
178 ASSERT(value != NULL);
179 ASSERT(full_key_name != NULL);
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);
186 ASSERT(byte_count == sizeof(*value));
187 if (byte_count == sizeof(*value)) {
188 *value = *reinterpret_cast<double*>(buffer.get());
194 HRESULT RegKey::GetValue(const wchar_t* full_key_name,
195 const wchar_t* value_name,
197 ASSERT(full_key_name != NULL);
198 ASSERT(value != NULL);
200 return GetValueStaticHelper(full_key_name, value_name, REG_SZ, value);
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);
209 scoped_ptr<wchar_t[]> buffer;
210 HRESULT hr = RegKey::GetValue(full_key_name, value_name, buffer.accept());
212 value->assign(buffer.get());
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);
223 return GetValueStaticHelper(full_key_name, value_name, REG_MULTI_SZ, value);
226 HRESULT RegKey::GetValue(const wchar_t* full_key_name,
227 const wchar_t* value_name,
230 ASSERT(full_key_name != NULL);
231 ASSERT(value != NULL);
232 ASSERT(byte_count != NULL);
234 return GetValueStaticHelper(full_key_name, value_name,
235 REG_BINARY, value, byte_count);
238 HRESULT RegKey::DeleteSubKey(const wchar_t* key_name) {
239 ASSERT(key_name != NULL);
240 ASSERT(h_key_ != NULL);
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)) {
251 HRESULT RegKey::DeleteValue(const wchar_t* value_name) {
252 ASSERT(h_key_ != NULL);
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)) {
263 HRESULT RegKey::Close() {
265 if (h_key_ != NULL) {
266 LONG res = ::RegCloseKey(h_key_);
267 hr = HRESULT_FROM_WIN32(res);
273 HRESULT RegKey::Create(HKEY parent_key,
274 const wchar_t* key_name,
278 LPSECURITY_ATTRIBUTES lpSecAttr,
279 LPDWORD lpdwDisposition) {
280 ASSERT(key_name != NULL);
281 ASSERT(parent_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);
289 if (lpdwDisposition) {
290 *lpdwDisposition = dw;
293 // we have to close the currently opened key
294 // before replacing it with the new one
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);
310 LONG res = ::RegOpenKeyEx(parent_key, key_name, 0, sam_desired, &h_key);
311 HRESULT hr = HRESULT_FROM_WIN32(res);
313 // we have to close the currently opened key
314 // before replacing it with the new one
316 // close the currently opened key if any
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);
329 std::wstring key_name(full_key_name);
330 HKEY h_key = GetRootKeyInfo(&key_name);
336 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ);
341 AdjustCurrentProcessPrivilege(SE_BACKUP_NAME, true);
342 LONG res = ::RegSaveKey(key.h_key_, file_name, NULL);
343 AdjustCurrentProcessPrivilege(SE_BACKUP_NAME, false);
345 return HRESULT_FROM_WIN32(res);
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);
354 std::wstring key_name(full_key_name);
355 HKEY h_key = GetRootKeyInfo(&key_name);
361 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_WRITE);
366 AdjustCurrentProcessPrivilege(SE_RESTORE_NAME, true);
367 LONG res = ::RegRestoreKey(key.h_key_, file_name, REG_FORCE_RESTORE);
368 AdjustCurrentProcessPrivilege(SE_RESTORE_NAME, false);
370 return HRESULT_FROM_WIN32(res);
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);
378 HRESULT hr = key.Open(h_key_, key_name, KEY_READ);
384 HRESULT RegKey::FlushKey(const wchar_t* full_key_name) {
385 ASSERT(full_key_name != NULL);
387 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
389 std::wstring key_name(full_key_name);
390 HKEY h_key = GetRootKeyInfo(&key_name);
393 LONG res = ::RegFlushKey(h_key);
394 hr = HRESULT_FROM_WIN32(res);
400 HRESULT RegKey::SetValueStaticHelper(const wchar_t* full_key_name,
401 const wchar_t* value_name,
405 ASSERT(full_key_name != NULL);
407 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
409 std::wstring key_name(full_key_name);
410 HKEY h_key = GetRootKeyInfo(&key_name);
414 hr = key.Create(h_key, key_name.c_str());
418 hr = key.SetValue(value_name, *(static_cast<DWORD*>(value)));
421 hr = key.SetValue(value_name, *(static_cast<DWORD64*>(value)));
424 hr = key.SetValue(value_name, static_cast<const wchar_t*>(value));
427 hr = key.SetValue(value_name, static_cast<const uint8*>(value),
431 hr = key.SetValue(value_name, static_cast<const uint8*>(value),
436 hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
439 // close the key after writing
440 HRESULT temp_hr = key.Close();
450 HRESULT RegKey::GetValueStaticHelper(const wchar_t* full_key_name,
451 const wchar_t* value_name,
455 ASSERT(full_key_name != NULL);
457 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
459 std::wstring key_name(full_key_name);
460 HKEY h_key = GetRootKeyInfo(&key_name);
464 hr = key.Open(h_key, key_name.c_str(), KEY_READ);
468 hr = key.GetValue(value_name, reinterpret_cast<DWORD*>(value));
471 hr = key.GetValue(value_name, reinterpret_cast<DWORD64*>(value));
474 hr = key.GetValue(value_name, reinterpret_cast<wchar_t**>(value));
477 hr = key.GetValue(value_name, reinterpret_cast<
478 std::vector<std::wstring>*>(value));
481 hr = key.GetValue(value_name, reinterpret_cast<uint8**>(value),
486 hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
489 // close the key after writing
490 HRESULT temp_hr = key.Close();
500 HRESULT RegKey::GetValueHelper(const wchar_t* value_name,
503 DWORD* byte_count) const {
504 ASSERT(byte_count != NULL);
505 ASSERT(value != NULL);
506 ASSERT(type != NULL);
508 // init return buffer
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);
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);
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);
533 HRESULT RegKey::GetValue(const wchar_t* value_name, DWORD* value) const {
534 ASSERT(value != NULL);
537 DWORD byte_count = sizeof(DWORD);
538 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,
540 HRESULT hr = HRESULT_FROM_WIN32(res);
541 ASSERT((hr != S_OK) || (type == REG_DWORD));
542 ASSERT((hr != S_OK) || (byte_count == sizeof(DWORD)));
547 HRESULT RegKey::GetValue(const wchar_t* value_name, DWORD64* value) const {
548 ASSERT(value != NULL);
551 DWORD byte_count = sizeof(DWORD64);
552 LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,
554 HRESULT hr = HRESULT_FROM_WIN32(res);
555 ASSERT((hr != S_OK) || (type == REG_QWORD));
556 ASSERT((hr != S_OK) || (byte_count == sizeof(DWORD64)));
561 HRESULT RegKey::GetValue(const wchar_t* value_name, wchar_t** value) const {
562 ASSERT(value != NULL);
564 DWORD byte_count = 0;
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);
573 // allocate room for the string and a terminating \0
574 *value = new wchar_t[(byte_count / sizeof(wchar_t)) + 1];
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);
586 ASSERT((hr != S_OK) || (type == REG_SZ) ||
587 (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
596 // get a string value
597 HRESULT RegKey::GetValue(const wchar_t* value_name, std::wstring* value) const {
598 ASSERT(value != NULL);
600 DWORD byte_count = 0;
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);
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()));
620 ASSERT((hr != S_OK) || (type == REG_SZ) ||
621 (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
627 // convert REG_MULTI_SZ bytes to string array
628 HRESULT RegKey::MultiSZBytesToStringArray(const uint8* buffer,
630 std::vector<std::wstring>* value) {
631 ASSERT(buffer != NULL);
632 ASSERT(value != NULL);
634 const wchar_t* data = reinterpret_cast<const wchar_t*>(buffer);
635 DWORD data_len = byte_count / sizeof(wchar_t);
638 // must be terminated by two null characters
639 if (data[data_len - 1] != 0 || data[data_len - 2] != 0) {
643 // put null-terminated strings into arrays
645 std::wstring str(data);
646 value->push_back(str);
647 data += str.length() + 1;
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);
658 DWORD byte_count = 0;
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));
667 hr = MultiSZBytesToStringArray(buffer, byte_count, value);
674 HRESULT RegKey::GetValue(const wchar_t* value_name,
676 DWORD* byte_count) const {
677 ASSERT(byte_count != NULL);
678 ASSERT(value != NULL);
681 HRESULT hr = GetValueHelper(value_name, &type, value, byte_count);
682 ASSERT((hr != S_OK) || (type == REG_MULTI_SZ) || (type == REG_BINARY));
687 HRESULT RegKey::GetValue(const wchar_t* value_name,
691 ASSERT(type != NULL);
692 ASSERT(byte_count != NULL);
693 ASSERT(value != NULL);
695 return GetValueHelper(value_name, type, value, byte_count);
699 HRESULT RegKey::SetValue(const wchar_t* value_name, DWORD value) const {
700 ASSERT(h_key_ != NULL);
702 LONG res = ::RegSetValueEx(h_key_, value_name, NULL, REG_DWORD,
703 reinterpret_cast<const uint8*>(&value),
705 return HRESULT_FROM_WIN32(res);
709 HRESULT RegKey::SetValue(const wchar_t* value_name, DWORD64 value) const {
710 ASSERT(h_key_ != NULL);
712 LONG res = ::RegSetValueEx(h_key_, value_name, NULL, REG_QWORD,
713 reinterpret_cast<const uint8*>(&value),
715 return HRESULT_FROM_WIN32(res);
719 HRESULT RegKey::SetValue(const wchar_t* value_name,
720 const wchar_t* value) const {
721 ASSERT(value != NULL);
722 ASSERT(h_key_ != NULL);
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);
731 HRESULT RegKey::SetValue(const wchar_t* value_name,
733 DWORD byte_count) const {
734 ASSERT(h_key_ != NULL);
736 // special case - if 'value' is NULL make sure byte_count is zero
741 LONG res = ::RegSetValueEx(h_key_, value_name, NULL,
742 REG_BINARY, value, byte_count);
743 return HRESULT_FROM_WIN32(res);
747 HRESULT RegKey::SetValue(const wchar_t* value_name,
751 ASSERT(value != NULL);
752 ASSERT(h_key_ != NULL);
754 LONG res = ::RegSetValueEx(h_key_, value_name, NULL, type, value, byte_count);
755 return HRESULT_FROM_WIN32(res);
758 bool RegKey::HasKey(const wchar_t* full_key_name) {
759 ASSERT(full_key_name != NULL);
762 std::wstring key_name(full_key_name);
763 HKEY h_key = GetRootKeyInfo(&key_name);
767 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ);
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);
778 bool has_value = false;
780 std::wstring key_name(full_key_name);
781 HKEY h_key = GetRootKeyInfo(&key_name);
785 if (key.Open(h_key, key_name.c_str(), KEY_READ) == S_OK) {
786 has_value = key.HasValue(value_name);
793 HRESULT RegKey::GetValueType(const wchar_t* full_key_name,
794 const wchar_t* value_name,
796 ASSERT(full_key_name != NULL);
797 ASSERT(value_type != NULL);
799 *value_type = REG_NONE;
801 std::wstring key_name(full_key_name);
802 HKEY h_key = GetRootKeyInfo(&key_name);
805 HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ);
807 LONG res = ::SHQueryValueEx(key.h_key_, value_name, NULL, value_type,
809 if (res != ERROR_SUCCESS) {
810 hr = HRESULT_FROM_WIN32(res);
817 HRESULT RegKey::DeleteKey(const wchar_t* full_key_name) {
818 ASSERT(full_key_name != NULL);
820 return DeleteKey(full_key_name, true);
823 HRESULT RegKey::DeleteKey(const wchar_t* full_key_name, bool recursively) {
824 ASSERT(full_key_name != NULL);
826 // need to open the parent key first
828 std::wstring key_name(full_key_name);
829 HKEY h_key = GetRootKeyInfo(&key_name);
831 // get the parent key
832 std::wstring parent_key(GetParentKeyInfo(&key_name));
835 HRESULT hr = key.Open(h_key, parent_key.c_str());
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)) {
849 HRESULT RegKey::DeleteValue(const wchar_t* full_key_name,
850 const wchar_t* value_name) {
851 ASSERT(full_key_name != NULL);
853 HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
855 std::wstring key_name(full_key_name);
856 HKEY h_key = GetRootKeyInfo(&key_name);
860 hr = key.Open(h_key, key_name.c_str());
862 hr = key.DeleteValue(value_name);
869 HRESULT RegKey::RecurseDeleteSubKey(const wchar_t* key_name) {
870 ASSERT(key_name != NULL);
873 HRESULT hr = key.Open(h_key_, key_name);
876 // enumerate all subkeys of this key and recursivelly delete them
878 wchar_t key_name_buf[kMaxKeyNameChars] = {0};
879 DWORD key_name_buf_size = kMaxKeyNameChars;
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);
885 // restore the buffer size
886 key_name_buf_size = kMaxKeyNameChars;
893 // the key has no more children keys
894 // delete the key and all of its values
895 hr = DeleteSubKey(key_name);
901 HKEY RegKey::GetRootKeyInfo(std::wstring* full_key_name) {
902 ASSERT(full_key_name != NULL);
906 size_t index = full_key_name->find(L'\\');
907 std::wstring root_key;
910 root_key = *full_key_name;
911 *full_key_name = L"";
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);
918 for (std::wstring::iterator iter = root_key.begin();
919 iter != root_key.end(); ++iter) {
920 *iter = toupper(*iter);
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")) {
932 } else if (!root_key.compare(L"HKCR") ||
933 !root_key.compare(L"HKEY_CLASSES_ROOT")) {
934 h_key = HKEY_CLASSES_ROOT;
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);
947 HKEY root_key = GetRootKeyInfo(&key);
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) {
964 return (root_key == HKEY_USERS) ? found_subkey : true;
967 std::wstring RegKey::GetParentKeyInfo(std::wstring* key_name) {
968 ASSERT(key_name != NULL);
970 // get the parent key
971 size_t index = key_name->rfind(L'\\');
972 std::wstring parent_key;
976 parent_key = key_name->substr(0, index);
977 *key_name = key_name->substr(index + 1, key_name->length() - index - 1);
983 // get the number of values for this key
984 uint32 RegKey::GetValueCount() {
985 DWORD num_values = 0;
987 LONG res = ::RegQueryInfoKey(
988 h_key_, // key handle
989 NULL, // buffer for class name
990 NULL, // size of class string
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
1001 ASSERT(res == ERROR_SUCCESS);
1005 // Enumerators for the value_names for this key
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,
1012 ASSERT(value_name != NULL);
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);
1020 if (res == ERROR_SUCCESS) {
1021 value_name->assign(value_name_buf);
1024 return HRESULT_FROM_WIN32(res);
1027 uint32 RegKey::GetSubkeyCount() {
1028 // number of values for key
1029 DWORD num_subkeys = 0;
1031 LONG res = ::RegQueryInfoKey(
1032 h_key_, // key handle
1033 NULL, // buffer for class name
1034 NULL, // size of class string
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
1045 ASSERT(res == ERROR_SUCCESS);
1049 HRESULT RegKey::GetSubkeyNameAt(int index, std::wstring* key_name) {
1050 ASSERT(key_name != NULL);
1052 LONG res = ERROR_SUCCESS;
1053 wchar_t key_name_buf[kMaxKeyNameChars] = {0};
1054 DWORD key_name_buf_size = kMaxKeyNameChars;
1056 res = ::RegEnumKeyEx(h_key_, index, key_name_buf, &key_name_buf_size,
1057 NULL, NULL, NULL, NULL);
1059 if (res == ERROR_SUCCESS) {
1060 key_name->assign(key_name_buf);
1063 return HRESULT_FROM_WIN32(res);
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);
1070 bool is_empty = true;
1072 // Get the root HKEY
1073 std::wstring key_name(full_key_name);
1074 HKEY h_key = GetRootKeyInfo(&key_name);
1076 // Open the key to check
1077 if (h_key != NULL) {
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;
1089 bool AdjustCurrentProcessPrivilege(const TCHAR* privilege, bool to_enable) {
1090 ASSERT(privilege != NULL);
1094 if (::OpenProcessToken(::GetCurrentProcess(),
1095 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) {
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)) {
1106 LOG_GLE(LS_ERROR) << "AdjustTokenPrivileges failed";
1109 LOG_GLE(LS_ERROR) << "LookupPrivilegeValue failed";
1113 LOG_GLE(LS_ERROR) << "OpenProcessToken(GetCurrentProcess) failed";
1119 } // namespace talk_base