diff options
Diffstat (limited to 'chromium/third_party/webrtc/base/win32regkey.cc')
-rw-r--r-- | chromium/third_party/webrtc/base/win32regkey.cc | 1102 |
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 |