1 // Copyright 2012 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_WIN_REGISTRY_H_ 6 #define BASE_WIN_REGISTRY_H_ 7 8 #include <stdint.h> 9 10 #include <memory> 11 #include <optional> 12 #include <string> 13 #include <vector> 14 15 #include "base/base_export.h" 16 #include "base/functional/callback_forward.h" 17 #include "base/types/expected.h" 18 #include "base/types/strong_alias.h" 19 #include "base/win/windows_types.h" 20 21 namespace base { 22 namespace win { 23 24 // Utility class to read, write and manipulate the Windows Registry. 25 // Registry vocabulary primer: a "key" is like a folder, in which there 26 // are "values", which are <name, data> pairs, with an associated data type. 27 // 28 // Note: 29 // * ReadValue family of functions guarantee that the out-parameter 30 // is not touched in case of failure. 31 // * Functions returning LONG indicate success as ERROR_SUCCESS or an 32 // error as a (non-zero) win32 error code. 33 class BASE_EXPORT RegKey { 34 public: 35 // Called from the MessageLoop when the key changes. 36 using ChangeCallback = OnceCallback<void()>; 37 38 RegKey(); 39 explicit RegKey(HKEY key); 40 RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access); 41 RegKey(RegKey&& other) noexcept; 42 RegKey& operator=(RegKey&& other); 43 44 RegKey(const RegKey&) = delete; 45 RegKey& operator=(const RegKey&) = delete; 46 47 ~RegKey(); 48 49 // Creates a new reg key, replacing `this` with a reference to the 50 // newly-opened key. In case of error, `this` is unchanged. 51 [[nodiscard]] LONG Create(HKEY rootkey, const wchar_t* subkey, REGSAM access); 52 53 // Creates a new reg key, replacing `this` with a reference to the 54 // newly-opened key. In case of error, `this` is unchanged. 55 [[nodiscard]] LONG CreateWithDisposition(HKEY rootkey, 56 const wchar_t* subkey, 57 DWORD* disposition, 58 REGSAM access); 59 60 // Creates a subkey or opens it if it already exists. In case of error, `this` 61 // is unchanged. 62 [[nodiscard]] LONG CreateKey(const wchar_t* name, REGSAM access); 63 64 // Opens an existing reg key, replacing `this` with a reference to the 65 // newly-opened key. In case of error, `this` is unchanged. 66 [[nodiscard]] LONG Open(HKEY rootkey, const wchar_t* subkey, REGSAM access); 67 68 // Opens an existing reg key, given the relative key name. 69 [[nodiscard]] LONG OpenKey(const wchar_t* relative_key_name, REGSAM access); 70 71 // Closes this reg key. 72 void Close(); 73 74 // Replaces the handle of the registry key and takes ownership of the handle. 75 void Set(HKEY key); 76 77 // Transfers ownership away from this object. 78 HKEY Take(); 79 80 // Returns false if this key does not have the specified value, or if an error 81 // occurrs while attempting to access it. 82 bool HasValue(const wchar_t* value_name) const; 83 84 // Returns the number of values for this key, or an error code if the number 85 // cannot be determined. 86 base::expected<DWORD, LONG> GetValueCount() const; 87 88 // Determines the nth value's name. 89 LONG GetValueNameAt(DWORD index, std::wstring* name) const; 90 91 // True while the key is valid. Valid()92 bool Valid() const { return key_ != nullptr; } 93 94 // Kills a key and, by default, everything that lives below it; please be 95 // careful when using it. `recursive` = false may be used to prevent 96 // recursion, in which case the key is only deleted if it has no subkeys. 97 using RecursiveDelete = base::StrongAlias<class RecursiveDeleteTag, bool>; 98 LONG DeleteKey(const wchar_t* name, 99 RecursiveDelete recursive = RecursiveDelete(true)); 100 101 // Deletes a single value within the key. 102 LONG DeleteValue(const wchar_t* name); 103 104 // Getters: 105 106 // Reads a REG_DWORD (uint32_t) into |out_value|. If |name| is null or empty, 107 // reads the key's default value, if any. 108 LONG ReadValueDW(const wchar_t* name, DWORD* out_value) const; 109 110 // Reads a REG_QWORD (int64_t) into |out_value|. If |name| is null or empty, 111 // reads the key's default value, if any. 112 LONG ReadInt64(const wchar_t* name, int64_t* out_value) const; 113 114 // Reads a string into |out_value|. If |name| is null or empty, reads 115 // the key's default value, if any. 116 LONG ReadValue(const wchar_t* name, std::wstring* out_value) const; 117 118 // Reads a REG_MULTI_SZ registry field into a vector of strings. Clears 119 // |values| initially and adds further strings to the list. Returns 120 // ERROR_CANTREAD if type is not REG_MULTI_SZ. 121 LONG ReadValues(const wchar_t* name, std::vector<std::wstring>* values); 122 123 // Reads raw data into |data|. If |name| is null or empty, reads the key's 124 // default value, if any. 125 LONG ReadValue(const wchar_t* name, 126 void* data, 127 DWORD* dsize, 128 DWORD* dtype) const; 129 130 // Setters: 131 132 // Sets an int32_t value. 133 LONG WriteValue(const wchar_t* name, DWORD in_value); 134 135 // Sets a string value. 136 LONG WriteValue(const wchar_t* name, const wchar_t* in_value); 137 138 // Sets raw data, including type. 139 LONG WriteValue(const wchar_t* name, 140 const void* data, 141 DWORD dsize, 142 DWORD dtype); 143 144 // Starts watching the key to see if any of its values have changed. 145 // The key must have been opened with the KEY_NOTIFY access privilege. 146 // Returns true on success. 147 // To stop watching, delete this RegKey object. To continue watching the 148 // object after the callback is invoked, call StartWatching again. 149 bool StartWatching(ChangeCallback callback); 150 Handle()151 HKEY Handle() const { return key_; } 152 153 private: 154 class Watcher; 155 156 // Opens the key `subkey` under `rootkey` with the given options and 157 // access rights. `options` may be 0 or `REG_OPTION_OPEN_LINK`. Returns 158 // ERROR_SUCCESS or a Windows error code. 159 [[nodiscard]] LONG Open(HKEY rootkey, 160 const wchar_t* subkey, 161 DWORD options, 162 REGSAM access); 163 164 // Returns true if the key is a symbolic link, false if it is not, or a 165 // Windows error code in case of a failure to determine. `this` *MUST* have 166 // been opened via at least `Open(..., REG_OPTION_OPEN_LINK, 167 // REG_QUERY_VALUE);`. 168 expected<bool, LONG> IsLink() const; 169 170 // Deletes the key if it is a symbolic link. Returns ERROR_SUCCESS if the key 171 // was a link and was deleted, a Windows error code if checking the key or 172 // deleting it failed, or `nullopt` if the key exists and is not a symbolic 173 // link. 174 std::optional<LONG> DeleteIfLink(); 175 176 // Recursively deletes a key and all of its subkeys. 177 static LONG RegDelRecurse(HKEY root_key, const wchar_t* name, REGSAM access); 178 179 HKEY key_ = nullptr; // The registry key being iterated. 180 REGSAM wow64access_ = 0; 181 std::unique_ptr<Watcher> key_watcher_; 182 }; 183 184 // Iterates the entries found in a particular folder on the registry. 185 class BASE_EXPORT RegistryValueIterator { 186 public: 187 // Constructs a Registry Value Iterator with default WOW64 access. 188 RegistryValueIterator(HKEY root_key, const wchar_t* folder_key); 189 190 // Constructs a Registry Key Iterator with specific WOW64 access, one of 191 // KEY_WOW64_32KEY or KEY_WOW64_64KEY, or 0. 192 // Note: |wow64access| should be the same access used to open |root_key| 193 // previously, or a predefined key (e.g. HKEY_LOCAL_MACHINE). 194 // See http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx. 195 RegistryValueIterator(HKEY root_key, 196 const wchar_t* folder_key, 197 REGSAM wow64access); 198 199 RegistryValueIterator(const RegistryValueIterator&) = delete; 200 RegistryValueIterator& operator=(const RegistryValueIterator&) = delete; 201 202 ~RegistryValueIterator(); 203 204 DWORD ValueCount() const; 205 206 // True while the iterator is valid. 207 bool Valid() const; 208 209 // Advances to the next registry entry. 210 void operator++(); 211 212 // TODO(crbug.com/329476354): Provide a wcstring_view instead of a pointer. Name()213 const wchar_t* Name() const { return name_.c_str(); } 214 // TODO(crbug.com/329476354): Provide a wcstring_view instead of a pointer. Value()215 const wchar_t* Value() const { return value_.data(); } 216 // ValueSize() is in bytes. ValueSize()217 DWORD ValueSize() const { return value_size_; } Type()218 DWORD Type() const { return type_; } 219 Index()220 DWORD Index() const { return index_; } 221 222 private: 223 // Reads in the current values. 224 bool Read(); 225 226 void Initialize(HKEY root_key, const wchar_t* folder_key, REGSAM wow64access); 227 228 // The registry key being iterated. 229 HKEY key_; 230 231 // Current index of the iteration. 232 DWORD index_; 233 234 // Current values. 235 std::wstring name_; 236 // The vector always has a `0` at the end, after its `ValueSize() / 2u` 237 // elements (since ValueSize() is in bytes, but the vector is of 2-byte 238 // objects). This allows the value to always be read as a NUL-terminated 239 // string, even if it's holding another type of data. 240 std::vector<wchar_t> value_; 241 DWORD value_size_; 242 DWORD type_; 243 }; 244 245 class BASE_EXPORT RegistryKeyIterator { 246 public: 247 // Constructs a Registry Key Iterator with default WOW64 access. 248 RegistryKeyIterator(HKEY root_key, const wchar_t* folder_key); 249 250 // Constructs a Registry Value Iterator with specific WOW64 access, one of 251 // KEY_WOW64_32KEY or KEY_WOW64_64KEY, or 0. 252 // Note: |wow64access| should be the same access used to open |root_key| 253 // previously, or a predefined key (e.g. HKEY_LOCAL_MACHINE). 254 // See http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx. 255 RegistryKeyIterator(HKEY root_key, 256 const wchar_t* folder_key, 257 REGSAM wow64access); 258 259 RegistryKeyIterator(const RegistryKeyIterator&) = delete; 260 RegistryKeyIterator& operator=(const RegistryKeyIterator&) = delete; 261 262 ~RegistryKeyIterator(); 263 264 DWORD SubkeyCount() const; 265 266 // True while the iterator is valid. 267 bool Valid() const; 268 269 // Advances to the next entry in the folder. 270 void operator++(); 271 Name()272 const wchar_t* Name() const { return name_; } 273 Index()274 DWORD Index() const { return index_; } 275 276 private: 277 // Reads in the current values. 278 bool Read(); 279 280 void Initialize(HKEY root_key, const wchar_t* folder_key, REGSAM wow64access); 281 282 // The registry key being iterated. 283 HKEY key_; 284 285 // Current index of the iteration. 286 DWORD index_; 287 288 wchar_t name_[MAX_PATH]; 289 }; 290 291 } // namespace win 292 } // namespace base 293 294 #endif // BASE_WIN_REGISTRY_H_ 295