summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/webrtc/base/win32regkey.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/webrtc/base/win32regkey.cc')
-rw-r--r--chromium/third_party/webrtc/base/win32regkey.cc1102
1 files changed, 1102 insertions, 0 deletions
diff --git a/chromium/third_party/webrtc/base/win32regkey.cc b/chromium/third_party/webrtc/base/win32regkey.cc
new file mode 100644
index 00000000000..1ed0d4ea291
--- /dev/null
+++ b/chromium/third_party/webrtc/base/win32regkey.cc
@@ -0,0 +1,1102 @@
+/*
+ * Copyright 2003 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+// Registry configuration wrapers class implementation
+//
+// Change made by S. Ganesh - ganesh@google.com:
+// Use SHQueryValueEx instead of RegQueryValueEx throughout.
+// A call to the SHLWAPI function is essentially a call to the standard
+// function but with post-processing:
+// * to fix REG_SZ or REG_EXPAND_SZ data that is not properly null-terminated;
+// * to expand REG_EXPAND_SZ data.
+
+#include "webrtc/base/win32regkey.h"
+
+#include <shlwapi.h>
+
+#include "webrtc/base/common.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/base/scoped_ptr.h"
+
+namespace rtc {
+
+RegKey::RegKey() {
+ h_key_ = NULL;
+}
+
+RegKey::~RegKey() {
+ Close();
+}
+
+HRESULT RegKey::Create(HKEY parent_key, const wchar_t* key_name) {
+ return Create(parent_key,
+ key_name,
+ REG_NONE,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ NULL);
+}
+
+HRESULT RegKey::Open(HKEY parent_key, const wchar_t* key_name) {
+ return Open(parent_key, key_name, KEY_ALL_ACCESS);
+}
+
+bool RegKey::HasValue(const TCHAR* value_name) const {
+ return (ERROR_SUCCESS == ::RegQueryValueEx(h_key_, value_name, NULL,
+ NULL, NULL, NULL));
+}
+
+HRESULT RegKey::SetValue(const wchar_t* full_key_name,
+ const wchar_t* value_name,
+ DWORD value) {
+ ASSERT(full_key_name != NULL);
+
+ return SetValueStaticHelper(full_key_name, value_name, REG_DWORD, &value);
+}
+
+HRESULT RegKey::SetValue(const wchar_t* full_key_name,
+ const wchar_t* value_name,
+ DWORD64 value) {
+ ASSERT(full_key_name != NULL);
+
+ return SetValueStaticHelper(full_key_name, value_name, REG_QWORD, &value);
+}
+
+HRESULT RegKey::SetValue(const wchar_t* full_key_name,
+ const wchar_t* value_name,
+ float value) {
+ ASSERT(full_key_name != NULL);
+
+ return SetValueStaticHelper(full_key_name, value_name,
+ REG_BINARY, &value, sizeof(value));
+}
+
+HRESULT RegKey::SetValue(const wchar_t* full_key_name,
+ const wchar_t* value_name,
+ double value) {
+ ASSERT(full_key_name != NULL);
+
+ return SetValueStaticHelper(full_key_name, value_name,
+ REG_BINARY, &value, sizeof(value));
+}
+
+HRESULT RegKey::SetValue(const wchar_t* full_key_name,
+ const wchar_t* value_name,
+ const TCHAR* value) {
+ ASSERT(full_key_name != NULL);
+ ASSERT(value != NULL);
+
+ return SetValueStaticHelper(full_key_name, value_name,
+ REG_SZ, const_cast<wchar_t*>(value));
+}
+
+HRESULT RegKey::SetValue(const wchar_t* full_key_name,
+ const wchar_t* value_name,
+ const uint8* value,
+ DWORD byte_count) {
+ ASSERT(full_key_name != NULL);
+
+ return SetValueStaticHelper(full_key_name, value_name, REG_BINARY,
+ const_cast<uint8*>(value), byte_count);
+}
+
+HRESULT RegKey::SetValueMultiSZ(const wchar_t* full_key_name,
+ const wchar_t* value_name,
+ const uint8* value,
+ DWORD byte_count) {
+ ASSERT(full_key_name != NULL);
+
+ return SetValueStaticHelper(full_key_name, value_name, REG_MULTI_SZ,
+ const_cast<uint8*>(value), byte_count);
+}
+
+HRESULT RegKey::GetValue(const wchar_t* full_key_name,
+ const wchar_t* value_name,
+ DWORD* value) {
+ ASSERT(full_key_name != NULL);
+ ASSERT(value != NULL);
+
+ return GetValueStaticHelper(full_key_name, value_name, REG_DWORD, value);
+}
+
+HRESULT RegKey::GetValue(const wchar_t* full_key_name,
+ const wchar_t* value_name,
+ DWORD64* value) {
+ ASSERT(full_key_name != NULL);
+ ASSERT(value != NULL);
+
+ return GetValueStaticHelper(full_key_name, value_name, REG_QWORD, value);
+}
+
+HRESULT RegKey::GetValue(const wchar_t* full_key_name,
+ const wchar_t* value_name,
+ float* value) {
+ ASSERT(value != NULL);
+ ASSERT(full_key_name != NULL);
+
+ DWORD byte_count = 0;
+ scoped_ptr<byte[]> buffer;
+ HRESULT hr = GetValueStaticHelper(full_key_name, value_name,
+ REG_BINARY, buffer.accept(), &byte_count);
+ if (SUCCEEDED(hr)) {
+ ASSERT(byte_count == sizeof(*value));
+ if (byte_count == sizeof(*value)) {
+ *value = *reinterpret_cast<float*>(buffer.get());
+ }
+ }
+ return hr;
+}
+
+HRESULT RegKey::GetValue(const wchar_t* full_key_name,
+ const wchar_t* value_name,
+ double* value) {
+ ASSERT(value != NULL);
+ ASSERT(full_key_name != NULL);
+
+ DWORD byte_count = 0;
+ scoped_ptr<byte[]> buffer;
+ HRESULT hr = GetValueStaticHelper(full_key_name, value_name,
+ REG_BINARY, buffer.accept(), &byte_count);
+ if (SUCCEEDED(hr)) {
+ ASSERT(byte_count == sizeof(*value));
+ if (byte_count == sizeof(*value)) {
+ *value = *reinterpret_cast<double*>(buffer.get());
+ }
+ }
+ return hr;
+}
+
+HRESULT RegKey::GetValue(const wchar_t* full_key_name,
+ const wchar_t* value_name,
+ wchar_t** value) {
+ ASSERT(full_key_name != NULL);
+ ASSERT(value != NULL);
+
+ return GetValueStaticHelper(full_key_name, value_name, REG_SZ, value);
+}
+
+HRESULT RegKey::GetValue(const wchar_t* full_key_name,
+ const wchar_t* value_name,
+ std::wstring* value) {
+ ASSERT(full_key_name != NULL);
+ ASSERT(value != NULL);
+
+ scoped_ptr<wchar_t[]> buffer;
+ HRESULT hr = RegKey::GetValue(full_key_name, value_name, buffer.accept());
+ if (SUCCEEDED(hr)) {
+ value->assign(buffer.get());
+ }
+ return hr;
+}
+
+HRESULT RegKey::GetValue(const wchar_t* full_key_name,
+ const wchar_t* value_name,
+ std::vector<std::wstring>* value) {
+ ASSERT(full_key_name != NULL);
+ ASSERT(value != NULL);
+
+ return GetValueStaticHelper(full_key_name, value_name, REG_MULTI_SZ, value);
+}
+
+HRESULT RegKey::GetValue(const wchar_t* full_key_name,
+ const wchar_t* value_name,
+ uint8** value,
+ DWORD* byte_count) {
+ ASSERT(full_key_name != NULL);
+ ASSERT(value != NULL);
+ ASSERT(byte_count != NULL);
+
+ return GetValueStaticHelper(full_key_name, value_name,
+ REG_BINARY, value, byte_count);
+}
+
+HRESULT RegKey::DeleteSubKey(const wchar_t* key_name) {
+ ASSERT(key_name != NULL);
+ ASSERT(h_key_ != NULL);
+
+ LONG res = ::RegDeleteKey(h_key_, key_name);
+ HRESULT hr = HRESULT_FROM_WIN32(res);
+ if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
+ hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {
+ hr = S_FALSE;
+ }
+ return hr;
+}
+
+HRESULT RegKey::DeleteValue(const wchar_t* value_name) {
+ ASSERT(h_key_ != NULL);
+
+ LONG res = ::RegDeleteValue(h_key_, value_name);
+ HRESULT hr = HRESULT_FROM_WIN32(res);
+ if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
+ hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {
+ hr = S_FALSE;
+ }
+ return hr;
+}
+
+HRESULT RegKey::Close() {
+ HRESULT hr = S_OK;
+ if (h_key_ != NULL) {
+ LONG res = ::RegCloseKey(h_key_);
+ hr = HRESULT_FROM_WIN32(res);
+ h_key_ = NULL;
+ }
+ return hr;
+}
+
+HRESULT RegKey::Create(HKEY parent_key,
+ const wchar_t* key_name,
+ wchar_t* lpszClass,
+ DWORD options,
+ REGSAM sam_desired,
+ LPSECURITY_ATTRIBUTES lpSecAttr,
+ LPDWORD lpdwDisposition) {
+ ASSERT(key_name != NULL);
+ ASSERT(parent_key != NULL);
+
+ DWORD dw = 0;
+ HKEY h_key = NULL;
+ LONG res = ::RegCreateKeyEx(parent_key, key_name, 0, lpszClass, options,
+ sam_desired, lpSecAttr, &h_key, &dw);
+ HRESULT hr = HRESULT_FROM_WIN32(res);
+
+ if (lpdwDisposition) {
+ *lpdwDisposition = dw;
+ }
+
+ // we have to close the currently opened key
+ // before replacing it with the new one
+ if (hr == S_OK) {
+ hr = Close();
+ ASSERT(hr == S_OK);
+ h_key_ = h_key;
+ }
+ return hr;
+}
+
+HRESULT RegKey::Open(HKEY parent_key,
+ const wchar_t* key_name,
+ REGSAM sam_desired) {
+ ASSERT(key_name != NULL);
+ ASSERT(parent_key != NULL);
+
+ HKEY h_key = NULL;
+ LONG res = ::RegOpenKeyEx(parent_key, key_name, 0, sam_desired, &h_key);
+ HRESULT hr = HRESULT_FROM_WIN32(res);
+
+ // we have to close the currently opened key
+ // before replacing it with the new one
+ if (hr == S_OK) {
+ // close the currently opened key if any
+ hr = Close();
+ ASSERT(hr == S_OK);
+ h_key_ = h_key;
+ }
+ return hr;
+}
+
+// save the key and all of its subkeys and values to a file
+HRESULT RegKey::Save(const wchar_t* full_key_name, const wchar_t* file_name) {
+ ASSERT(full_key_name != NULL);
+ ASSERT(file_name != NULL);
+
+ std::wstring key_name(full_key_name);
+ HKEY h_key = GetRootKeyInfo(&key_name);
+ if (!h_key) {
+ return E_FAIL;
+ }
+
+ RegKey key;
+ HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ AdjustCurrentProcessPrivilege(SE_BACKUP_NAME, true);
+ LONG res = ::RegSaveKey(key.h_key_, file_name, NULL);
+ AdjustCurrentProcessPrivilege(SE_BACKUP_NAME, false);
+
+ return HRESULT_FROM_WIN32(res);
+}
+
+// restore the key and all of its subkeys and values which are saved into a file
+HRESULT RegKey::Restore(const wchar_t* full_key_name,
+ const wchar_t* file_name) {
+ ASSERT(full_key_name != NULL);
+ ASSERT(file_name != NULL);
+
+ std::wstring key_name(full_key_name);
+ HKEY h_key = GetRootKeyInfo(&key_name);
+ if (!h_key) {
+ return E_FAIL;
+ }
+
+ RegKey key;
+ HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_WRITE);
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ AdjustCurrentProcessPrivilege(SE_RESTORE_NAME, true);
+ LONG res = ::RegRestoreKey(key.h_key_, file_name, REG_FORCE_RESTORE);
+ AdjustCurrentProcessPrivilege(SE_RESTORE_NAME, false);
+
+ return HRESULT_FROM_WIN32(res);
+}
+
+// check if the current key has the specified subkey
+bool RegKey::HasSubkey(const wchar_t* key_name) const {
+ ASSERT(key_name != NULL);
+
+ RegKey key;
+ HRESULT hr = key.Open(h_key_, key_name, KEY_READ);
+ key.Close();
+ return hr == S_OK;
+}
+
+// static flush key
+HRESULT RegKey::FlushKey(const wchar_t* full_key_name) {
+ ASSERT(full_key_name != NULL);
+
+ HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
+ // get the root HKEY
+ std::wstring key_name(full_key_name);
+ HKEY h_key = GetRootKeyInfo(&key_name);
+
+ if (h_key != NULL) {
+ LONG res = ::RegFlushKey(h_key);
+ hr = HRESULT_FROM_WIN32(res);
+ }
+ return hr;
+}
+
+// static SET helper
+HRESULT RegKey::SetValueStaticHelper(const wchar_t* full_key_name,
+ const wchar_t* value_name,
+ DWORD type,
+ LPVOID value,
+ DWORD byte_count) {
+ ASSERT(full_key_name != NULL);
+
+ HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
+ // get the root HKEY
+ std::wstring key_name(full_key_name);
+ HKEY h_key = GetRootKeyInfo(&key_name);
+
+ if (h_key != NULL) {
+ RegKey key;
+ hr = key.Create(h_key, key_name.c_str());
+ if (hr == S_OK) {
+ switch (type) {
+ case REG_DWORD:
+ hr = key.SetValue(value_name, *(static_cast<DWORD*>(value)));
+ break;
+ case REG_QWORD:
+ hr = key.SetValue(value_name, *(static_cast<DWORD64*>(value)));
+ break;
+ case REG_SZ:
+ hr = key.SetValue(value_name, static_cast<const wchar_t*>(value));
+ break;
+ case REG_BINARY:
+ hr = key.SetValue(value_name, static_cast<const uint8*>(value),
+ byte_count);
+ break;
+ case REG_MULTI_SZ:
+ hr = key.SetValue(value_name, static_cast<const uint8*>(value),
+ byte_count, type);
+ break;
+ default:
+ ASSERT(false);
+ hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
+ break;
+ }
+ // close the key after writing
+ HRESULT temp_hr = key.Close();
+ if (hr == S_OK) {
+ hr = temp_hr;
+ }
+ }
+ }
+ return hr;
+}
+
+// static GET helper
+HRESULT RegKey::GetValueStaticHelper(const wchar_t* full_key_name,
+ const wchar_t* value_name,
+ DWORD type,
+ LPVOID value,
+ DWORD* byte_count) {
+ ASSERT(full_key_name != NULL);
+
+ HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
+ // get the root HKEY
+ std::wstring key_name(full_key_name);
+ HKEY h_key = GetRootKeyInfo(&key_name);
+
+ if (h_key != NULL) {
+ RegKey key;
+ hr = key.Open(h_key, key_name.c_str(), KEY_READ);
+ if (hr == S_OK) {
+ switch (type) {
+ case REG_DWORD:
+ hr = key.GetValue(value_name, reinterpret_cast<DWORD*>(value));
+ break;
+ case REG_QWORD:
+ hr = key.GetValue(value_name, reinterpret_cast<DWORD64*>(value));
+ break;
+ case REG_SZ:
+ hr = key.GetValue(value_name, reinterpret_cast<wchar_t**>(value));
+ break;
+ case REG_MULTI_SZ:
+ hr = key.GetValue(value_name, reinterpret_cast<
+ std::vector<std::wstring>*>(value));
+ break;
+ case REG_BINARY:
+ hr = key.GetValue(value_name, reinterpret_cast<uint8**>(value),
+ byte_count);
+ break;
+ default:
+ ASSERT(false);
+ hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
+ break;
+ }
+ // close the key after writing
+ HRESULT temp_hr = key.Close();
+ if (hr == S_OK) {
+ hr = temp_hr;
+ }
+ }
+ }
+ return hr;
+}
+
+// GET helper
+HRESULT RegKey::GetValueHelper(const wchar_t* value_name,
+ DWORD* type,
+ uint8** value,
+ DWORD* byte_count) const {
+ ASSERT(byte_count != NULL);
+ ASSERT(value != NULL);
+ ASSERT(type != NULL);
+
+ // init return buffer
+ *value = NULL;
+
+ // get the size of the return data buffer
+ LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, type, NULL, byte_count);
+ HRESULT hr = HRESULT_FROM_WIN32(res);
+
+ if (hr == S_OK) {
+ // if the value length is 0, nothing to do
+ if (*byte_count != 0) {
+ // allocate the buffer
+ *value = new byte[*byte_count];
+ ASSERT(*value != NULL);
+
+ // make the call again to get the data
+ res = ::SHQueryValueEx(h_key_, value_name, NULL,
+ type, *value, byte_count);
+ hr = HRESULT_FROM_WIN32(res);
+ ASSERT(hr == S_OK);
+ }
+ }
+ return hr;
+}
+
+// Int32 Get
+HRESULT RegKey::GetValue(const wchar_t* value_name, DWORD* value) const {
+ ASSERT(value != NULL);
+
+ DWORD type = 0;
+ DWORD byte_count = sizeof(DWORD);
+ LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,
+ value, &byte_count);
+ HRESULT hr = HRESULT_FROM_WIN32(res);
+ ASSERT((hr != S_OK) || (type == REG_DWORD));
+ ASSERT((hr != S_OK) || (byte_count == sizeof(DWORD)));
+ return hr;
+}
+
+// Int64 Get
+HRESULT RegKey::GetValue(const wchar_t* value_name, DWORD64* value) const {
+ ASSERT(value != NULL);
+
+ DWORD type = 0;
+ DWORD byte_count = sizeof(DWORD64);
+ LONG res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,
+ value, &byte_count);
+ HRESULT hr = HRESULT_FROM_WIN32(res);
+ ASSERT((hr != S_OK) || (type == REG_QWORD));
+ ASSERT((hr != S_OK) || (byte_count == sizeof(DWORD64)));
+ return hr;
+}
+
+// String Get
+HRESULT RegKey::GetValue(const wchar_t* value_name, wchar_t** value) const {
+ ASSERT(value != NULL);
+
+ DWORD byte_count = 0;
+ DWORD type = 0;
+
+ // first get the size of the string buffer
+ LONG res = ::SHQueryValueEx(h_key_, value_name, NULL,
+ &type, NULL, &byte_count);
+ HRESULT hr = HRESULT_FROM_WIN32(res);
+
+ if (hr == S_OK) {
+ // allocate room for the string and a terminating \0
+ *value = new wchar_t[(byte_count / sizeof(wchar_t)) + 1];
+
+ if ((*value) != NULL) {
+ if (byte_count != 0) {
+ // make the call again
+ res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,
+ *value, &byte_count);
+ hr = HRESULT_FROM_WIN32(res);
+ } else {
+ (*value)[0] = L'\0';
+ }
+
+ ASSERT((hr != S_OK) || (type == REG_SZ) ||
+ (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
+ } else {
+ hr = E_OUTOFMEMORY;
+ }
+ }
+
+ return hr;
+}
+
+// get a string value
+HRESULT RegKey::GetValue(const wchar_t* value_name, std::wstring* value) const {
+ ASSERT(value != NULL);
+
+ DWORD byte_count = 0;
+ DWORD type = 0;
+
+ // first get the size of the string buffer
+ LONG res = ::SHQueryValueEx(h_key_, value_name, NULL,
+ &type, NULL, &byte_count);
+ HRESULT hr = HRESULT_FROM_WIN32(res);
+
+ if (hr == S_OK) {
+ if (byte_count != 0) {
+ // Allocate some memory and make the call again
+ value->resize(byte_count / sizeof(wchar_t) + 1);
+ res = ::SHQueryValueEx(h_key_, value_name, NULL, &type,
+ &value->at(0), &byte_count);
+ hr = HRESULT_FROM_WIN32(res);
+ value->resize(wcslen(value->data()));
+ } else {
+ value->clear();
+ }
+
+ ASSERT((hr != S_OK) || (type == REG_SZ) ||
+ (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
+ }
+
+ return hr;
+}
+
+// convert REG_MULTI_SZ bytes to string array
+HRESULT RegKey::MultiSZBytesToStringArray(const uint8* buffer,
+ DWORD byte_count,
+ std::vector<std::wstring>* value) {
+ ASSERT(buffer != NULL);
+ ASSERT(value != NULL);
+
+ const wchar_t* data = reinterpret_cast<const wchar_t*>(buffer);
+ DWORD data_len = byte_count / sizeof(wchar_t);
+ value->clear();
+ if (data_len > 1) {
+ // must be terminated by two null characters
+ if (data[data_len - 1] != 0 || data[data_len - 2] != 0) {
+ return E_INVALIDARG;
+ }
+
+ // put null-terminated strings into arrays
+ while (*data) {
+ std::wstring str(data);
+ value->push_back(str);
+ data += str.length() + 1;
+ }
+ }
+ return S_OK;
+}
+
+// get a std::vector<std::wstring> value from REG_MULTI_SZ type
+HRESULT RegKey::GetValue(const wchar_t* value_name,
+ std::vector<std::wstring>* value) const {
+ ASSERT(value != NULL);
+
+ DWORD byte_count = 0;
+ DWORD type = 0;
+ uint8* buffer = 0;
+
+ // first get the size of the buffer
+ HRESULT hr = GetValueHelper(value_name, &type, &buffer, &byte_count);
+ ASSERT((hr != S_OK) || (type == REG_MULTI_SZ));
+
+ if (SUCCEEDED(hr)) {
+ hr = MultiSZBytesToStringArray(buffer, byte_count, value);
+ }
+
+ return hr;
+}
+
+// Binary data Get
+HRESULT RegKey::GetValue(const wchar_t* value_name,
+ uint8** value,
+ DWORD* byte_count) const {
+ ASSERT(byte_count != NULL);
+ ASSERT(value != NULL);
+
+ DWORD type = 0;
+ HRESULT hr = GetValueHelper(value_name, &type, value, byte_count);
+ ASSERT((hr != S_OK) || (type == REG_MULTI_SZ) || (type == REG_BINARY));
+ return hr;
+}
+
+// Raw data get
+HRESULT RegKey::GetValue(const wchar_t* value_name,
+ uint8** value,
+ DWORD* byte_count,
+ DWORD*type) const {
+ ASSERT(type != NULL);
+ ASSERT(byte_count != NULL);
+ ASSERT(value != NULL);
+
+ return GetValueHelper(value_name, type, value, byte_count);
+}
+
+// Int32 set
+HRESULT RegKey::SetValue(const wchar_t* value_name, DWORD value) const {
+ ASSERT(h_key_ != NULL);
+
+ LONG res = ::RegSetValueEx(h_key_, value_name, NULL, REG_DWORD,
+ reinterpret_cast<const uint8*>(&value),
+ sizeof(DWORD));
+ return HRESULT_FROM_WIN32(res);
+}
+
+// Int64 set
+HRESULT RegKey::SetValue(const wchar_t* value_name, DWORD64 value) const {
+ ASSERT(h_key_ != NULL);
+
+ LONG res = ::RegSetValueEx(h_key_, value_name, NULL, REG_QWORD,
+ reinterpret_cast<const uint8*>(&value),
+ sizeof(DWORD64));
+ return HRESULT_FROM_WIN32(res);
+}
+
+// String set
+HRESULT RegKey::SetValue(const wchar_t* value_name,
+ const wchar_t* value) const {
+ ASSERT(value != NULL);
+ ASSERT(h_key_ != NULL);
+
+ LONG res = ::RegSetValueEx(h_key_, value_name, NULL, REG_SZ,
+ reinterpret_cast<const uint8*>(value),
+ (lstrlen(value) + 1) * sizeof(wchar_t));
+ return HRESULT_FROM_WIN32(res);
+}
+
+// Binary data set
+HRESULT RegKey::SetValue(const wchar_t* value_name,
+ const uint8* value,
+ DWORD byte_count) const {
+ ASSERT(h_key_ != NULL);
+
+ // special case - if 'value' is NULL make sure byte_count is zero
+ if (value == NULL) {
+ byte_count = 0;
+ }
+
+ LONG res = ::RegSetValueEx(h_key_, value_name, NULL,
+ REG_BINARY, value, byte_count);
+ return HRESULT_FROM_WIN32(res);
+}
+
+// Raw data set
+HRESULT RegKey::SetValue(const wchar_t* value_name,
+ const uint8* value,
+ DWORD byte_count,
+ DWORD type) const {
+ ASSERT(value != NULL);
+ ASSERT(h_key_ != NULL);
+
+ LONG res = ::RegSetValueEx(h_key_, value_name, NULL, type, value, byte_count);
+ return HRESULT_FROM_WIN32(res);
+}
+
+bool RegKey::HasKey(const wchar_t* full_key_name) {
+ ASSERT(full_key_name != NULL);
+
+ // get the root HKEY
+ std::wstring key_name(full_key_name);
+ HKEY h_key = GetRootKeyInfo(&key_name);
+
+ if (h_key != NULL) {
+ RegKey key;
+ HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ);
+ key.Close();
+ return S_OK == hr;
+ }
+ return false;
+}
+
+// static version of HasValue
+bool RegKey::HasValue(const wchar_t* full_key_name, const wchar_t* value_name) {
+ ASSERT(full_key_name != NULL);
+
+ bool has_value = false;
+ // get the root HKEY
+ std::wstring key_name(full_key_name);
+ HKEY h_key = GetRootKeyInfo(&key_name);
+
+ if (h_key != NULL) {
+ RegKey key;
+ if (key.Open(h_key, key_name.c_str(), KEY_READ) == S_OK) {
+ has_value = key.HasValue(value_name);
+ key.Close();
+ }
+ }
+ return has_value;
+}
+
+HRESULT RegKey::GetValueType(const wchar_t* full_key_name,
+ const wchar_t* value_name,
+ DWORD* value_type) {
+ ASSERT(full_key_name != NULL);
+ ASSERT(value_type != NULL);
+
+ *value_type = REG_NONE;
+
+ std::wstring key_name(full_key_name);
+ HKEY h_key = GetRootKeyInfo(&key_name);
+
+ RegKey key;
+ HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ);
+ if (SUCCEEDED(hr)) {
+ LONG res = ::SHQueryValueEx(key.h_key_, value_name, NULL, value_type,
+ NULL, NULL);
+ if (res != ERROR_SUCCESS) {
+ hr = HRESULT_FROM_WIN32(res);
+ }
+ }
+
+ return hr;
+}
+
+HRESULT RegKey::DeleteKey(const wchar_t* full_key_name) {
+ ASSERT(full_key_name != NULL);
+
+ return DeleteKey(full_key_name, true);
+}
+
+HRESULT RegKey::DeleteKey(const wchar_t* full_key_name, bool recursively) {
+ ASSERT(full_key_name != NULL);
+
+ // need to open the parent key first
+ // get the root HKEY
+ std::wstring key_name(full_key_name);
+ HKEY h_key = GetRootKeyInfo(&key_name);
+
+ // get the parent key
+ std::wstring parent_key(GetParentKeyInfo(&key_name));
+
+ RegKey key;
+ HRESULT hr = key.Open(h_key, parent_key.c_str());
+
+ if (hr == S_OK) {
+ hr = recursively ? key.RecurseDeleteSubKey(key_name.c_str())
+ : key.DeleteSubKey(key_name.c_str());
+ } else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
+ hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)) {
+ hr = S_FALSE;
+ }
+
+ key.Close();
+ return hr;
+}
+
+HRESULT RegKey::DeleteValue(const wchar_t* full_key_name,
+ const wchar_t* value_name) {
+ ASSERT(full_key_name != NULL);
+
+ HRESULT hr = HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
+ // get the root HKEY
+ std::wstring key_name(full_key_name);
+ HKEY h_key = GetRootKeyInfo(&key_name);
+
+ if (h_key != NULL) {
+ RegKey key;
+ hr = key.Open(h_key, key_name.c_str());
+ if (hr == S_OK) {
+ hr = key.DeleteValue(value_name);
+ key.Close();
+ }
+ }
+ return hr;
+}
+
+HRESULT RegKey::RecurseDeleteSubKey(const wchar_t* key_name) {
+ ASSERT(key_name != NULL);
+
+ RegKey key;
+ HRESULT hr = key.Open(h_key_, key_name);
+
+ if (hr == S_OK) {
+ // enumerate all subkeys of this key and recursivelly delete them
+ FILETIME time = {0};
+ wchar_t key_name_buf[kMaxKeyNameChars] = {0};
+ DWORD key_name_buf_size = kMaxKeyNameChars;
+ while (hr == S_OK &&
+ ::RegEnumKeyEx(key.h_key_, 0, key_name_buf, &key_name_buf_size,
+ NULL, NULL, NULL, &time) == ERROR_SUCCESS) {
+ hr = key.RecurseDeleteSubKey(key_name_buf);
+
+ // restore the buffer size
+ key_name_buf_size = kMaxKeyNameChars;
+ }
+ // close the top key
+ key.Close();
+ }
+
+ if (hr == S_OK) {
+ // the key has no more children keys
+ // delete the key and all of its values
+ hr = DeleteSubKey(key_name);
+ }
+
+ return hr;
+}
+
+HKEY RegKey::GetRootKeyInfo(std::wstring* full_key_name) {
+ ASSERT(full_key_name != NULL);
+
+ HKEY h_key = NULL;
+ // get the root HKEY
+ size_t index = full_key_name->find(L'\\');
+ std::wstring root_key;
+
+ if (index == -1) {
+ root_key = *full_key_name;
+ *full_key_name = L"";
+ } else {
+ root_key = full_key_name->substr(0, index);
+ *full_key_name = full_key_name->substr(index + 1,
+ full_key_name->length() - index - 1);
+ }
+
+ for (std::wstring::iterator iter = root_key.begin();
+ iter != root_key.end(); ++iter) {
+ *iter = toupper(*iter);
+ }
+
+ if (!root_key.compare(L"HKLM") ||
+ !root_key.compare(L"HKEY_LOCAL_MACHINE")) {
+ h_key = HKEY_LOCAL_MACHINE;
+ } else if (!root_key.compare(L"HKCU") ||
+ !root_key.compare(L"HKEY_CURRENT_USER")) {
+ h_key = HKEY_CURRENT_USER;
+ } else if (!root_key.compare(L"HKU") ||
+ !root_key.compare(L"HKEY_USERS")) {
+ h_key = HKEY_USERS;
+ } else if (!root_key.compare(L"HKCR") ||
+ !root_key.compare(L"HKEY_CLASSES_ROOT")) {
+ h_key = HKEY_CLASSES_ROOT;
+ }
+
+ return h_key;
+}
+
+
+// Returns true if this key name is 'safe' for deletion
+// (doesn't specify a key root)
+bool RegKey::SafeKeyNameForDeletion(const wchar_t* key_name) {
+ ASSERT(key_name != NULL);
+ std::wstring key(key_name);
+
+ HKEY root_key = GetRootKeyInfo(&key);
+
+ if (!root_key) {
+ key = key_name;
+ }
+ if (key.empty()) {
+ return false;
+ }
+ bool found_subkey = false, backslash_found = false;
+ for (size_t i = 0 ; i < key.length() ; ++i) {
+ if (key[i] == L'\\') {
+ backslash_found = true;
+ } else if (backslash_found) {
+ found_subkey = true;
+ break;
+ }
+ }
+ return (root_key == HKEY_USERS) ? found_subkey : true;
+}
+
+std::wstring RegKey::GetParentKeyInfo(std::wstring* key_name) {
+ ASSERT(key_name != NULL);
+
+ // get the parent key
+ size_t index = key_name->rfind(L'\\');
+ std::wstring parent_key;
+ if (index == -1) {
+ parent_key = L"";
+ } else {
+ parent_key = key_name->substr(0, index);
+ *key_name = key_name->substr(index + 1, key_name->length() - index - 1);
+ }
+
+ return parent_key;
+}
+
+// get the number of values for this key
+uint32 RegKey::GetValueCount() {
+ DWORD num_values = 0;
+
+ if (ERROR_SUCCESS != ::RegQueryInfoKey(
+ h_key_, // key handle
+ NULL, // buffer for class name
+ NULL, // size of class string
+ NULL, // reserved
+ NULL, // number of subkeys
+ NULL, // longest subkey size
+ NULL, // longest class string
+ &num_values, // number of values for this key
+ NULL, // longest value name
+ NULL, // longest value data
+ NULL, // security descriptor
+ NULL)) { // last write time
+ ASSERT(false);
+ }
+ return num_values;
+}
+
+// Enumerators for the value_names for this key
+
+// Called to get the value name for the given value name index
+// Use GetValueCount() to get the total value_name count for this key
+// Returns failure if no key at the specified index
+HRESULT RegKey::GetValueNameAt(int index, std::wstring* value_name,
+ DWORD* type) {
+ ASSERT(value_name != NULL);
+
+ LONG res = ERROR_SUCCESS;
+ wchar_t value_name_buf[kMaxValueNameChars] = {0};
+ DWORD value_name_buf_size = kMaxValueNameChars;
+ res = ::RegEnumValue(h_key_, index, value_name_buf, &value_name_buf_size,
+ NULL, type, NULL, NULL);
+
+ if (res == ERROR_SUCCESS) {
+ value_name->assign(value_name_buf);
+ }
+
+ return HRESULT_FROM_WIN32(res);
+}
+
+uint32 RegKey::GetSubkeyCount() {
+ // number of values for key
+ DWORD num_subkeys = 0;
+
+ if (ERROR_SUCCESS != ::RegQueryInfoKey(
+ h_key_, // key handle
+ NULL, // buffer for class name
+ NULL, // size of class string
+ NULL, // reserved
+ &num_subkeys, // number of subkeys
+ NULL, // longest subkey size
+ NULL, // longest class string
+ NULL, // number of values for this key
+ NULL, // longest value name
+ NULL, // longest value data
+ NULL, // security descriptor
+ NULL)) { // last write time
+ ASSERT(false);
+ }
+ return num_subkeys;
+}
+
+HRESULT RegKey::GetSubkeyNameAt(int index, std::wstring* key_name) {
+ ASSERT(key_name != NULL);
+
+ LONG res = ERROR_SUCCESS;
+ wchar_t key_name_buf[kMaxKeyNameChars] = {0};
+ DWORD key_name_buf_size = kMaxKeyNameChars;
+
+ res = ::RegEnumKeyEx(h_key_, index, key_name_buf, &key_name_buf_size,
+ NULL, NULL, NULL, NULL);
+
+ if (res == ERROR_SUCCESS) {
+ key_name->assign(key_name_buf);
+ }
+
+ return HRESULT_FROM_WIN32(res);
+}
+
+// Is the key empty: having no sub-keys and values
+bool RegKey::IsKeyEmpty(const wchar_t* full_key_name) {
+ ASSERT(full_key_name != NULL);
+
+ bool is_empty = true;
+
+ // Get the root HKEY
+ std::wstring key_name(full_key_name);
+ HKEY h_key = GetRootKeyInfo(&key_name);
+
+ // Open the key to check
+ if (h_key != NULL) {
+ RegKey key;
+ HRESULT hr = key.Open(h_key, key_name.c_str(), KEY_READ);
+ if (SUCCEEDED(hr)) {
+ is_empty = key.GetSubkeyCount() == 0 && key.GetValueCount() == 0;
+ key.Close();
+ }
+ }
+
+ return is_empty;
+}
+
+bool AdjustCurrentProcessPrivilege(const TCHAR* privilege, bool to_enable) {
+ ASSERT(privilege != NULL);
+
+ bool ret = false;
+ HANDLE token;
+ if (::OpenProcessToken(::GetCurrentProcess(),
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) {
+ LUID luid;
+ memset(&luid, 0, sizeof(luid));
+ if (::LookupPrivilegeValue(NULL, privilege, &luid)) {
+ TOKEN_PRIVILEGES privs;
+ privs.PrivilegeCount = 1;
+ privs.Privileges[0].Luid = luid;
+ privs.Privileges[0].Attributes = to_enable ? SE_PRIVILEGE_ENABLED : 0;
+ if (::AdjustTokenPrivileges(token, FALSE, &privs, 0, NULL, 0)) {
+ ret = true;
+ } else {
+ LOG_GLE(LS_ERROR) << "AdjustTokenPrivileges failed";
+ }
+ } else {
+ LOG_GLE(LS_ERROR) << "LookupPrivilegeValue failed";
+ }
+ CloseHandle(token);
+ } else {
+ LOG_GLE(LS_ERROR) << "OpenProcessToken(GetCurrentProcess) failed";
+ }
+
+ return ret;
+}
+
+} // namespace rtc