Registry.h (9722B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #pragma once 4 #include <wil/resource.h> 5 6 #include <optional> 7 #include <string> 8 #include <string_view> 9 #include <vector> 10 11 #define AICLI_REGISTRY_UTF16_FLAG 0x08000000 12 13 namespace AppInstaller::Registry 14 { 15 namespace details 16 { 17 template<DWORD> 18 constexpr bool dependent_false = false; 19 20 template <DWORD Type> 21 struct ValueTypeSpecifics 22 { 23 using value_t = void; 24 25 static value_t Convert(const std::vector<BYTE>& data) 26 { 27 static_assert(dependent_false<Type>, "No Type specific override has been supplied"); 28 } 29 }; 30 31 template <> 32 struct ValueTypeSpecifics<REG_NONE> 33 { 34 using value_t = std::vector<BYTE>; 35 static value_t Convert(const std::vector<BYTE>& data); 36 }; 37 38 template <> 39 struct ValueTypeSpecifics<REG_SZ> 40 { 41 using value_t = std::string; 42 static value_t Convert(const std::vector<BYTE>& data); 43 }; 44 45 template <> 46 struct ValueTypeSpecifics<REG_SZ | AICLI_REGISTRY_UTF16_FLAG> 47 { 48 using value_t = std::wstring; 49 static value_t Convert(const std::vector<BYTE>& data); 50 }; 51 52 template <> 53 struct ValueTypeSpecifics<REG_EXPAND_SZ> 54 { 55 using value_t = std::string; 56 static value_t Convert(const std::vector<BYTE>& data); 57 }; 58 59 template <> 60 struct ValueTypeSpecifics<REG_EXPAND_SZ | AICLI_REGISTRY_UTF16_FLAG> 61 { 62 using value_t = std::wstring; 63 static value_t Convert(const std::vector<BYTE>& data); 64 }; 65 66 template <> 67 struct ValueTypeSpecifics<REG_BINARY> 68 { 69 using value_t = std::vector<BYTE>; 70 static value_t Convert(const std::vector<BYTE>& data); 71 }; 72 73 template <> 74 struct ValueTypeSpecifics<REG_DWORD_LITTLE_ENDIAN> 75 { 76 using value_t = uint32_t; 77 static value_t Convert(const std::vector<BYTE>& data); 78 }; 79 } 80 81 struct Key; 82 struct ValueList; 83 84 // A registry value. 85 struct Value 86 { 87 friend Key; 88 friend ValueList; 89 90 // The type of data stored in the Value. 91 enum class Type : DWORD 92 { 93 None = REG_NONE, 94 String = REG_SZ, 95 UTF16Flag = AICLI_REGISTRY_UTF16_FLAG, 96 UTF16String = REG_SZ | UTF16Flag, 97 ExpandString = REG_EXPAND_SZ, 98 UTF16ExpandString = REG_EXPAND_SZ | UTF16Flag, 99 Binary = REG_BINARY, 100 DWord = REG_DWORD, 101 DWordLittleEndian = REG_DWORD_LITTLE_ENDIAN, 102 DWordBigEndian = REG_DWORD_BIG_ENDIAN, 103 MultiString = REG_MULTI_SZ, 104 QWord = REG_QWORD, 105 QWordLittleEndian = REG_QWORD_LITTLE_ENDIAN, 106 }; 107 108 Type GetType() const { return m_type; } 109 110 template <Type T> 111 typename details::ValueTypeSpecifics<static_cast<DWORD>(T)>::value_t GetValue() const 112 { 113 auto value = TryGetValue<T>(); 114 if (!value.has_value()) 115 { 116 THROW_HR(E_INVALIDARG); 117 } 118 119 return std::move(value.value()); 120 } 121 122 template <Type T> 123 typename std::optional<typename details::ValueTypeSpecifics<static_cast<DWORD>(T)>::value_t> TryGetValue() const 124 { 125 if (HasCompatibleType(T)) 126 { 127 return details::ValueTypeSpecifics<static_cast<DWORD>(T)>::Convert(m_data); 128 } 129 else 130 { 131 return std::nullopt; 132 } 133 } 134 135 private: 136 Value(DWORD type, std::vector<BYTE>&& data); 137 138 bool HasCompatibleType(Type type) const; 139 140 Type m_type; 141 std::vector<BYTE> m_data; 142 }; 143 144 // Value iteration 145 struct ValueList 146 { 147 friend Key; 148 149 struct const_iterator; 150 151 struct ValueRef 152 { 153 friend const_iterator; 154 155 // Gets the name of the value. 156 std::string Name() const; 157 158 // Gets the actual value of the value. 159 // The optional allows for the potential race with the value being removed. 160 std::optional<Value> Value() const; 161 162 private: 163 ValueRef(wil::shared_hkey key, std::wstring&& valueName); 164 165 wil::shared_hkey m_key; 166 std::wstring m_valueName; 167 }; 168 169 struct const_iterator 170 { 171 friend ValueList; 172 173 const_iterator& operator++(); 174 const_iterator operator++(int); 175 176 bool operator==(const const_iterator& other) const; 177 bool operator!=(const const_iterator& other) const; 178 179 const ValueRef& operator*() const; 180 const ValueRef* operator->() const; 181 182 private: 183 // Create an iterator 184 const_iterator(const wil::shared_hkey& key, DWORD index = 0); 185 186 // Create an iterator for end 187 const_iterator() = default; 188 189 void GetValue(); 190 191 // An empty handle represents the end iterator. 192 wil::shared_hkey m_key; 193 DWORD m_index = 0; 194 std::optional<ValueRef> m_value; 195 }; 196 197 const_iterator begin() const; 198 const_iterator end() const; 199 200 private: 201 ValueList(wil::shared_hkey key); 202 203 wil::shared_hkey m_key; 204 }; 205 206 // A registry key. 207 struct Key 208 { 209 Key() = default; 210 Key(HKEY key); 211 Key(HKEY key, std::string_view subKey, DWORD options = 0, REGSAM access = KEY_READ); 212 Key(HKEY key, const std::wstring& subKey, DWORD options = 0, REGSAM access = KEY_READ); 213 214 // --== Sub-Key iteration ==-- 215 struct const_iterator; 216 217 struct SubKeyRef 218 { 219 friend const_iterator; 220 221 // Gets the name of the subkey. 222 std::string Name() const; 223 224 // Opens the subkey. 225 Key Open() const; 226 227 operator bool() const { return m_parentKey.operator bool(); } 228 229 private: 230 // For a valid iterator 231 SubKeyRef(const wil::shared_hkey& key, REGSAM access); 232 233 // For the end iterator 234 SubKeyRef() = default; 235 236 // Enumerates the subkey of m_parentKey at the given index. 237 void Enum(DWORD index); 238 239 wil::shared_hkey m_parentKey; 240 REGSAM m_access = KEY_READ; 241 std::wstring m_subKeyName; 242 }; 243 244 struct const_iterator 245 { 246 friend Key; 247 248 const_iterator& operator++(); 249 const_iterator operator++(int); 250 251 bool operator==(const const_iterator& other) const; 252 bool operator!=(const const_iterator& other) const; 253 254 const SubKeyRef& operator*() const; 255 const SubKeyRef* operator->() const; 256 257 private: 258 // Create an iterator for begin 259 const_iterator(const wil::shared_hkey& key, REGSAM access); 260 261 // Create an iterator for end 262 const_iterator() = default; 263 264 DWORD m_index = 0; 265 SubKeyRef m_subkey; 266 }; 267 268 const_iterator begin() const; 269 const_iterator end() const; 270 271 std::optional<Value> operator[](std::string_view name) const; 272 std::optional<Value> operator[](const std::wstring& name) const; 273 274 std::optional<Key> SubKey(std::string_view name, DWORD options = 0) const; 275 std::optional<Key> SubKey(const std::wstring& name, DWORD options = 0) const; 276 277 // Set registry values. 278 void SetValue(const std::wstring& name, const std::wstring& value, DWORD type = REG_SZ) const; 279 void SetValue(const std::wstring& name, const std::vector<BYTE>& value, DWORD type = REG_BINARY) const; 280 void SetValue(const std::wstring& name, DWORD value) const; 281 282 ValueList Values() const; 283 284 operator bool() const { return m_key.operator bool(); } 285 operator HKEY() const { return m_key.get(); } 286 287 // Open a Key; will return an empty Key if the subkey does not exist. 288 static Key OpenIfExists(HKEY key, std::string_view subKey = {}, DWORD options = 0, REGSAM access = KEY_READ); 289 static Key OpenIfExists(HKEY key, const std::wstring& subKey = {}, DWORD options = 0, REGSAM access = KEY_READ); 290 291 // Creates a new Key or returns one if it already existed. 292 static Key Create(HKEY key, std::string_view subkey = {}, DWORD options = REG_OPTION_NON_VOLATILE, REGSAM access = KEY_ALL_ACCESS); 293 static Key Create(HKEY key, const std::wstring& subKey = {}, DWORD options = REG_OPTION_NON_VOLATILE, REGSAM access = KEY_ALL_ACCESS); 294 295 // Delete a key 296 static bool Delete(HKEY key, std::string_view subkey, DWORD samDesired); 297 static bool Delete(HKEY key, const std::wstring& subKey, DWORD samDesired); 298 299 private: 300 // When ignoring error, returns whether the key existed 301 bool Initialize(HKEY key, const std::wstring& subKey, DWORD options, REGSAM access, bool ignoreErrorIfDoesNotExist); 302 303 // Returns whether the key was created successfully. 304 bool CreateAndOpen(HKEY key, const std::wstring& subKey, DWORD options, REGSAM access); 305 306 wil::shared_hkey m_key; 307 REGSAM m_access = KEY_READ; 308 }; 309 }