blob: fbf2dcffac4cc028ad770fd063e5874f230021a1 [file] [log] [blame]
// Copyright 2003-2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================
//
// reg_key.h
//
// Registry configuration wrappers class
//
// Offers static functions for convenient
// fast access for individual values
//
// Also provides a wrapper class for efficient
// batch operations on values of a given registry key.
#ifndef OMAHA_COMMON_REG_KEY_H_
#define OMAHA_COMMON_REG_KEY_H_
#include <windows.h>
#include <vector>
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
#include "omaha/common/debug.h"
#include "omaha/common/logging.h"
#include "omaha/common/scoped_any.h"
#include "omaha/common/static_assert.h"
#include "omaha/common/store_watcher.h"
namespace omaha {
// maximum sizes registry key and value names
#define kMaxKeyNameChars (255 + 1)
#define kMaxValueNameChars (16383 + 1)
class RegKey {
public:
RegKey();
virtual ~RegKey();
// create a reg key
HRESULT Create(HKEY hKeyParent, const TCHAR * key_name,
TCHAR * reg_class = REG_NONE, DWORD options = REG_OPTION_NON_VOLATILE,
REGSAM sam_desired = KEY_ALL_ACCESS,
LPSECURITY_ATTRIBUTES lp_sec_attr = NULL,
LPDWORD lp_disposition = NULL);
// create a reg key, given the full key name, including the HKEY root
// (say for example, "HKLM\\Software")
HRESULT Create(const TCHAR * full_key_name,
TCHAR * reg_class = REG_NONE, DWORD options = REG_OPTION_NON_VOLATILE,
REGSAM sam_desired = KEY_ALL_ACCESS,
LPSECURITY_ATTRIBUTES lp_sec_attr = NULL,
LPDWORD lp_disposition = NULL);
// static helper function that create a set of reg keys,
// given an array of full key names including the HKEY root
// (say for example, "HKLM\\Software")
static HRESULT CreateKeys(const TCHAR* keys_to_create[],
DWORD number_of_keys,
TCHAR* reg_class = REG_NONE,
DWORD options = REG_OPTION_NON_VOLATILE,
LPSECURITY_ATTRIBUTES lp_sec_attr = NULL);
// Static method to create a single key.
static HRESULT CreateKey(const TCHAR * full_key_name,
TCHAR * reg_class = REG_NONE,
DWORD options = REG_OPTION_NON_VOLATILE,
LPSECURITY_ATTRIBUTES lp_sec_attr = NULL);
// open an existing reg key
HRESULT Open(HKEY hKeyParent,
const TCHAR * key_name,
REGSAM sam_desired = KEY_ALL_ACCESS);
// open an existing reg key, given the full key name, including the HKEY root
// (say for example, "HKLM\\Software")
HRESULT Open(const TCHAR * full_key_name,
REGSAM sam_desired = KEY_ALL_ACCESS);
// close this reg key
virtual HRESULT Close();
// check if the key has a specified value
bool HasValue(const TCHAR * value_name);
// get the number of values for this key
uint32 GetValueCount();
// 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
// If you modify the key while enumerating, the indexes will be out of order.
// Since the index order is not guaranteed, you need to reset your counting
// loop.
// type refers to REG_DWORD, REG_QWORD, etc..
// 'type' can be NULL if not interested in the value type
HRESULT GetValueNameAt(int index, CString * value_name, DWORD *type);
// check if the current key has the specified subkey
bool HasSubkey(const TCHAR * key_name) const;
// get the number of subkeys for this key
uint32 GetSubkeyCount();
// Called to get the key name for the given key index
// Use GetSubkeyCount() to get the total count for this key
// Returns failure if no key at the specified index
// If you modify the key while enumerating, the indexes will be out of order.
// Since the index order is not guaranteed, you need to reset your counting
// loop.
HRESULT GetSubkeyNameAt(int index, CString * key_name);
// SETTERS
// set an int32 value - use when reading multiple values from a key
HRESULT SetValue(const TCHAR * value_name, DWORD value) const;
// set an int64 value
HRESULT SetValue(const TCHAR * value_name, DWORD64 value) const;
// set a string value
HRESULT SetValue(const TCHAR * value_name, const TCHAR * value) const;
// set binary data
HRESULT SetValue(const TCHAR * value_name,
const byte * value,
DWORD byte_count) const;
// set raw data, including type
HRESULT SetValue(const TCHAR * value_name,
const byte * value,
DWORD byte_count,
DWORD type) const;
// GETTERS
// get an int32 value
HRESULT GetValue(const TCHAR * value_name, DWORD * value) const;
// get an int64 value
//
// Note: if you are using time64 you should
// likely use GetLimitedTimeValue (util.h) instead of this method.
HRESULT GetValue(const TCHAR * value_name, DWORD64 * value) const;
// get a string value - the caller must free the return buffer
HRESULT GetValue(const TCHAR * value_name, TCHAR * * value) const;
// get a CString value
HRESULT GetValue(const TCHAR* value_name, OUT CString* value) const;
// get a vector<CString> value from REG_MULTI_SZ type
HRESULT GetValue(const TCHAR * value_name,
std::vector<CString> * value) const;
// get binary data - the caller must free the return buffer
HRESULT GetValue(const TCHAR * value_name,
byte * * value,
DWORD * byte_count) const;
// get raw data, including type - the caller must free the return buffer
HRESULT GetValue(const TCHAR * value_name,
byte * * value,
DWORD * byte_count,
DWORD *type) const;
// RENAMERS
// Rename a named value.
HRESULT RenameValue(const TCHAR * old_value_name,
const TCHAR * new_value_name) const;
// STATIC VERSIONS
// flush
static HRESULT FlushKey(const TCHAR * full_key_name);
// Check if a key exists.
static bool HasKey(const TCHAR * full_key_name);
// Check if a key exists in the native (i.e. non-redirected) registry.
static bool HasNativeKey(const TCHAR * full_key_name);
// check if the key has a specified value
static bool HasValue(const TCHAR * full_key_name, const TCHAR * value_name);
// SETTERS
// STATIC int32 set
static HRESULT SetValue(const TCHAR * full_key_name,
const TCHAR * value_name,
DWORD value);
// STATIC int64 set
static HRESULT SetValue(const TCHAR * full_key_name,
const TCHAR * value_name,
DWORD64 value);
// STATIC float set
static HRESULT SetValue(const TCHAR * full_key_name,
const TCHAR * value_name,
float value);
// STATIC double set
static HRESULT SetValue(const TCHAR * full_key_name,
const TCHAR * value_name,
double value);
// STATIC string set
static HRESULT SetValue(const TCHAR * full_key_name,
const TCHAR * value_name,
const TCHAR * value);
// STATIC binary data set
static HRESULT SetValue(const TCHAR * full_key_name,
const TCHAR * value_name,
const byte * value,
DWORD byte_count);
// STATIC array of strings set
static HRESULT SetValueMultiSZ(const TCHAR * full_key_name,
const TCHAR * value_name,
const byte * value,
DWORD byte_count);
// STATIC expandable string set
static HRESULT SetValueExpandSZ(const TCHAR * full_key_name,
const TCHAR * value_name,
const TCHAR * value);
// GETTERS
// STATIC int32 get
static HRESULT GetValue(const TCHAR * full_key_name,
const TCHAR * value_name,
DWORD * value);
// STATIC int64 get
//
// Note: if you are using time64 you should
// likely use GetLimitedTimeValue (util.h) instead of this method.
static HRESULT GetValue(const TCHAR * full_key_name,
const TCHAR * value_name,
DWORD64 * value);
// STATIC float get
static HRESULT GetValue(const TCHAR * full_key_name,
const TCHAR * value_name,
float * value);
// STATIC double get
static HRESULT GetValue(const TCHAR * full_key_name,
const TCHAR * value_name,
double * value);
// STATIC string get (STR and CString versions) - the caller must free
// the return buffer
static HRESULT GetValue(const TCHAR * full_key_name,
const TCHAR * value_name,
TCHAR * * value);
static HRESULT GetValue(const TCHAR * full_key_name,
const TCHAR * value_name,
CString * value);
// STATIC REG_MULTI_SZ get
static HRESULT GetValue(const TCHAR * full_key_name,
const TCHAR * value_name,
std::vector<CString> * value);
// STATIC get binary data - the caller must free the return buffer
static HRESULT GetValue(const TCHAR * full_key_name,
const TCHAR * value_name,
byte * * value,
DWORD * byte_count);
// Try reg keys successively if there is a failure in getting a value.
//
// Typically used when there is a user value and a default value if the
// user has none.
template<typename T>
static HRESULT GetValue(const TCHAR * full_key_names[],
int key_names_length,
const TCHAR * value_name,
T* value);
// RENAMERS
// Rename a named value.
static HRESULT RenameValue(const TCHAR * full_key_name,
const TCHAR * old_value_name,
const TCHAR * new_value_name);
// COPIERS
// The full_to_key must exist for CopyValue to succeed.
static HRESULT CopyValue(const TCHAR * full_from_key_name,
const TCHAR * from_value_name,
const TCHAR * full_to_key_name,
const TCHAR * to_value_name);
static HRESULT CopyValue(const TCHAR * full_from_key_name,
const TCHAR * full_to_key_name,
const TCHAR * value_name);
// Get type of a registry value
static HRESULT GetValueType(const TCHAR* full_key_name,
const TCHAR* value_name,
DWORD* value_type);
// delete a subkey of the current key (with no subkeys)
HRESULT DeleteSubKey(const TCHAR * key_name);
// recursively delete a sub key of the current key (and all its subkeys)
HRESULT RecurseDeleteSubKey(const TCHAR * key_name);
// STATIC version of delete key - handles nested keys also
// delete a key and all its sub-keys recursively
// Returns S_FALSE if key didn't exist, S_OK if deletion was successful,
// and failure otherwise.
static HRESULT DeleteKey(const TCHAR* full_key_name);
// STATIC version of delete key
// delete a key recursively or non-recursively
// Returns S_FALSE if key didn't exist, S_OK if deletion was successful,
// and failure otherwise.
static HRESULT DeleteKey(const TCHAR* full_key_name, bool recursive);
// delete the specified value
HRESULT DeleteValue(const TCHAR * value_name) const;
// STATIC version of delete value
// Returns S_FALSE if key didn't exist, S_OK if deletion was successful,
// and failure otherwise.
static HRESULT DeleteValue(const TCHAR * full_key_name,
const TCHAR * value_name);
// Peek inside (use a RegKey as a smart wrapper around a registry handle)
HKEY Key() { return h_key_; }
// Used to help test the private functionality
friend class RegKeyTestClass;
// helper function to get the HKEY and the root key from a string
// representation modifies the argument in place and returns the key name
// e.g. HKLM\\Software\\Google\... returns HKLM, "Software\\Google\..."
// Necessary for the static versions that use the full name of the reg key
static HKEY GetRootKeyInfo(CString * full_key_name);
// Returns true if this key name is 'safe' for deletion (doesn't specify
// a key root)
static bool SafeKeyNameForDeletion(const wchar_t *key_name);
// save the key and all of its subkeys and values to a file
static HRESULT Save(const TCHAR* full_key_name, const TCHAR* file_name);
// restore the key and all of its subkeys and values which are saved into
// a file
static HRESULT Restore(const TCHAR* full_key_name, const TCHAR* file_name);
// Is the key empty: having no sub-keys and values
static bool IsKeyEmpty(const TCHAR* full_key_name);
private:
// Helper function to check if a key exists, using the sam flags specified.
// Note: KEY_READ must be included in sam_flags.
static bool HasKeyHelper(const TCHAR * full_key_name, DWORD sam_flags);
// helper function to get the parent key name and the subkey from a string
// representation modifies the argument in place and returns the key name
// e.g. Software\\Google\\Foo_Bar returns "Software\\Google", "Foo_Bar"
// Necessary for the static versions that use the full name of the reg key
static CString GetParentKeyInfo(CString * key_name);
// helper function to get any value from the registry
// used when the size of the data is unknown
HRESULT GetValueHelper(const TCHAR * value_name,
DWORD * type,
byte * * value,
DWORD * byte_count) const;
// common SET Helper for the static case
static HRESULT SetValueStaticHelper(const TCHAR * full_key_name,
const TCHAR * value_name,
DWORD type,
LPVOID value,
DWORD byte_count = 0);
// common GET Helper for the static case
static HRESULT GetValueStaticHelper(const TCHAR * full_key_name,
const TCHAR * value_name,
DWORD type,
LPVOID value,
DWORD * byte_count = NULL);
// convert REG_MULTI_SZ bytes to string array
static HRESULT MultiSZBytesToStringArray(const byte * buffer,
DWORD byte_count,
std::vector<CString> * value);
// set a string or expandable string value
HRESULT SetStringValue(const TCHAR * value_name,
const TCHAR * value,
DWORD type) const;
// the HKEY for the current key
HKEY h_key_;
DISALLOW_EVIL_CONSTRUCTORS(RegKey);
};
// Provides all the functionality of RegKey plus
// an event to watch for changes to the registry key.
class RegKeyWithChangeEvent : public RegKey {
public:
RegKeyWithChangeEvent() {}
// close this reg key and the event
virtual HRESULT Close();
// Called to create/reset the event that gets signaled
// any time the registry key changes. Access the created
// event using change_event().
//
// See the documentation for RegNotifyChangeKeyValue
// for values for notify_filter.
HRESULT SetupEvent(bool watch_subtree, DWORD notify_filter);
// Indicates if any changes (that are being monitored) have occured
bool HasChangeOccurred() const;
// Get the event that is signaled on registry changes.
// Note:
// * This event will remain constant until Close() is called.
// * One should call SetupEvent to set-up the event.
// * The event is only signaled on the next change and remains signaled.
// Do not call ::ResetEvent(). Call SetupEvent() to reset
// the event and wait for more changes.
HANDLE change_event() const {
return get(change_event_);
}
private:
scoped_handle change_event_;
DISALLOW_EVIL_CONSTRUCTORS(RegKeyWithChangeEvent);
};
// Does the common things necessary for watching
// registry key changes. If there are file change or other watchers,
// there could be a common interface for the three methods to decouple
// the code that is doing the watching from the code that owns the store.
class RegKeyWatcher : public StoreWatcher {
public:
// reg_key: the full string for the reg key
// watch_subtree: watch all subkey changes or
// only immediate child values
// notify_filter: See the documentation for RegNotifyChangeKeyValue
// allow_creation: Should the key be created if it doesn't exist?
RegKeyWatcher(const TCHAR* reg_key, bool watch_subtree,
DWORD notify_filter, bool allow_creation);
virtual ~RegKeyWatcher() {}
// Called to create/reset the event that gets signaled
// any time the registry key changes. Access the created
// event using change_event().
virtual HRESULT EnsureEventSetup();
// Get the event that is signaled on registry changes.
virtual HANDLE change_event() const;
private:
// Used to do the SetupEvent method
scoped_ptr<RegKeyWithChangeEvent> reg_key_with_change_event_;
CString reg_key_string_;
bool watch_subtree_;
bool allow_creation_;
DWORD notify_filter_;
DISALLOW_EVIL_CONSTRUCTORS(RegKeyWatcher);
};
inline RegKey::RegKey() { h_key_ = NULL; }
inline RegKey::~RegKey() { Close(); }
inline bool RegKey::HasValue(const TCHAR* value_name) {
return (ERROR_SUCCESS == ::RegQueryValueEx(h_key_,
value_name,
NULL, NULL,
NULL,
NULL));
}
// SETTERS static versions
inline HRESULT RegKey::SetValue(const TCHAR* full_key_name,
const TCHAR* value_name,
DWORD value) {
ASSERT1(full_key_name);
return SetValueStaticHelper(full_key_name, value_name, REG_DWORD, &value);
}
inline HRESULT RegKey::SetValue(const TCHAR* full_key_name,
const TCHAR* value_name,
DWORD64 value) {
ASSERT1(full_key_name);
return SetValueStaticHelper(full_key_name, value_name, REG_QWORD, &value);
}
inline HRESULT RegKey::SetValue(const TCHAR* full_key_name,
const TCHAR* value_name,
float value) {
ASSERT1(full_key_name);
return SetValueStaticHelper(full_key_name,
value_name,
REG_BINARY,
&value,
sizeof(value));
}
inline HRESULT RegKey::SetValue(const TCHAR* full_key_name,
const TCHAR* value_name,
double value) {
ASSERT1(full_key_name);
return SetValueStaticHelper(full_key_name,
value_name,
REG_BINARY,
&value,
sizeof(value));
}
inline HRESULT RegKey::SetValue(const TCHAR* full_key_name,
const TCHAR* value_name,
const TCHAR* value) {
ASSERT1(full_key_name);
ASSERT1(value);
return SetValueStaticHelper(full_key_name,
value_name,
REG_SZ,
const_cast<TCHAR*>(value));
}
inline HRESULT RegKey::SetValue(const TCHAR* full_key_name,
const TCHAR* value_name,
const byte* value,
DWORD byte_count) {
ASSERT1(full_key_name);
return SetValueStaticHelper(full_key_name, value_name, REG_BINARY,
const_cast<byte*>(value), byte_count);
}
inline HRESULT RegKey::SetValueMultiSZ(const TCHAR* full_key_name,
const TCHAR* value_name,
const byte* value,
DWORD byte_count) {
ASSERT1(full_key_name);
return SetValueStaticHelper(full_key_name, value_name, REG_MULTI_SZ,
const_cast<byte*>(value), byte_count);
}
inline HRESULT RegKey::SetValueExpandSZ(const TCHAR* full_key_name,
const TCHAR* value_name,
const TCHAR* value) {
ASSERT1(full_key_name);
ASSERT1(value);
return SetValueStaticHelper(full_key_name,
value_name,
REG_EXPAND_SZ,
const_cast<TCHAR*>(value));
}
// GETTERS static versions
inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,
const TCHAR* value_name,
DWORD* value) {
ASSERT1(full_key_name);
ASSERT1(value);
return GetValueStaticHelper(full_key_name, value_name, REG_DWORD, value);
}
inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,
const TCHAR* value_name,
DWORD64* value) {
ASSERT1(full_key_name);
ASSERT1(value);
return GetValueStaticHelper(full_key_name, value_name, REG_QWORD, value);
}
inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,
const TCHAR* value_name,
float* value) {
ASSERT1(value);
ASSERT1(value_name);
ASSERT1(full_key_name);
DWORD byte_count = 0;
byte* buffer = NULL;
HRESULT hr = GetValueStaticHelper(full_key_name,
value_name,
REG_BINARY,
&buffer,
&byte_count);
scoped_array<byte> free_buffer(buffer);
if (SUCCEEDED(hr)) {
if (byte_count == sizeof(*value)) {
::CopyMemory(value, buffer, sizeof(*value));
} else {
UTIL_LOG(LEVEL_ERROR, (_T("[RegKey::GetValue]")
_T("[size mismatches for float value][%s\\%s]"),
full_key_name, value_name));
return HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
}
}
return hr;
}
inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,
const TCHAR* value_name,
double* value) {
ASSERT1(value);
ASSERT1(value_name);
ASSERT1(full_key_name);
DWORD byte_count = 0;
byte* buffer = NULL;
HRESULT hr = GetValueStaticHelper(full_key_name,
value_name,
REG_BINARY,
&buffer,
&byte_count);
scoped_array<byte> free_buffer(buffer);
if (SUCCEEDED(hr)) {
if (byte_count == sizeof(*value)) {
::CopyMemory(value, buffer, sizeof(*value));
} else {
UTIL_LOG(LEVEL_ERROR, (_T("[RegKey::GetValue]")
_T("[size mismatches for double value][%s\\%s]"),
full_key_name, value_name));
return HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH);
}
}
return hr;
}
inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,
const TCHAR* value_name,
TCHAR** value) {
ASSERT1(full_key_name);
ASSERT1(value);
return GetValueStaticHelper(full_key_name, value_name, REG_SZ, value);
}
inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,
const TCHAR* value_name,
CString* value) {
ASSERT1(full_key_name);
ASSERT1(value);
TCHAR* buffer = NULL;
HRESULT hr = RegKey::GetValue(full_key_name, value_name, &buffer);
value->SetString(buffer);
delete [] buffer;
return hr;
}
inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,
const TCHAR* value_name,
std::vector<CString>* value) {
ASSERT1(full_key_name);
ASSERT1(value);
return GetValueStaticHelper(full_key_name, value_name, REG_MULTI_SZ, value);
}
inline HRESULT RegKey::GetValue(const TCHAR* full_key_name,
const TCHAR* value_name,
byte** value,
DWORD* byte_count) {
ASSERT1(full_key_name);
ASSERT1(value);
ASSERT1(byte_count);
return GetValueStaticHelper(full_key_name,
value_name,
REG_BINARY,
value,
byte_count);
}
template<typename T>
HRESULT RegKey::GetValue(const TCHAR* full_key_names[],
int key_names_length,
const TCHAR* value_name,
T* value) {
HRESULT hr = S_OK;
for (int i = 0; i < key_names_length; ++i) {
hr = GetValue(full_key_names[i], value_name, value);
if (SUCCEEDED(hr)) {
return hr;
}
}
return hr;
}
// Rename a named value.
inline HRESULT RegKey::RenameValue(const TCHAR * full_key_name,
const TCHAR * old_value_name,
const TCHAR * new_value_name) {
ASSERT1(full_key_name);
RegKey reg_key;
HRESULT hr = reg_key.Open(full_key_name);
if (FAILED(hr)) {
return hr;
}
return reg_key.RenameValue(old_value_name, new_value_name);
}
inline HRESULT RegKey::CopyValue(const TCHAR * full_from_key_name,
const TCHAR * full_to_key_name,
const TCHAR * value_name) {
return CopyValue(full_from_key_name,
value_name,
full_to_key_name,
value_name);
}
// DELETE
inline HRESULT RegKey::DeleteSubKey(const TCHAR* key_name) {
ASSERT1(key_name);
ASSERT1(h_key_);
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;
}
inline HRESULT RegKey::DeleteValue(const TCHAR* value_name) const {
ASSERT1(value_name);
ASSERT1(h_key_);
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;
}
} // namespace omaha
#endif // OMAHA_COMMON_REG_KEY_H_