-
Notifications
You must be signed in to change notification settings - Fork 273
Registry Helpers
WIL registry helpers are basic "free function" helpers for reading, writing, and manipulating the registry. They also include a basic registry watcher, for watching registry changes.
// read a value from an app configuration stored in the registry
const auto typeOverlay = wil::reg::get_value_dword(HKEY_CURRENT_USER_LOCAL_SETTINGS, LR"(Windows\FileExplorer)", L"ShowFileExtensions");
// write a value to an app configuration stored in the registry
wil::reg::set_value_dword(HKEY_CURRENT_USER_LOCAL_SETTINGS, LR"(Vendor\App)",
L"Setting", 1);To use WIL error handling helpers, add wil/registry.h to your C++ source file:
#include <wil/registry.h>Some of the free functions have specific requirements:
| Requires | |
|---|---|
| Getters & setters that throw | Requires exceptions |
try_get_* |
Requires exceptions & <optional>
|
std::wstring get/set |
Requires exceptions & <string>
|
// "Open" guaranteed-existing keys or "create" to potentially create if non-existent
const auto r_unique_key = wil::reg::open_unique_key(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer");
const auto rw_shared_key = wil::reg::create_shared_key(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", wil::reg::key_access::readwrite);
// nothrow version, if you don't have exceptions
wil::unique_hkey nothrow_key;
THROW_IF_FAILED(wil::reg::open_unique_key_nothrow(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", nothrow_key, wil::reg::key_access::readwrite));| Function name | Full Signature | ||
|---|---|---|---|
| Open if exists | Unique pointer | wil::reg::open_unique_key |
wil::unique_hkey wil::reg::open_unique_key(HKEY key, PCWSTR path, wil::reg::key_access access = wil::reg::key_access::read) |
wil::reg::open_unique_key_nothrow |
HRESULT wil::reg::open_unique_key_nothrow(HKEY key, PCWSTR path, _Out_ ::wil::unique_hkey& hkey, wil::reg::key_access access = wil::reg::key_access::read) nothrow |
||
| Shared pointer | wil::reg::open_shared_key |
wil::shared_hkey wil::reg::open_shared_key(HKEY key, PCWSTR path, wil::reg::key_access access = wil::reg::key_access::read) |
|
wil::reg::open_shared_key_nothrow |
HRESULT wil::reg::open_shared_key_nothrow(HKEY key, PCWSTR path, _Out_ ::wil::shared_hkey& hkey, wil::reg::key_access access = wil::reg::key_access::read) nothrow |
||
| Create if missing, open if exists | Unique pointer | wil::reg::create_unique_key |
wil::unique_hkey wil::reg::create_unique_key(HKEY key, PCWSTR path, wil::reg::key_access access = wil::reg::key_access::read) |
wil::reg::create_unique_key_nothrow |
HRESULT wil::reg::create_unique_key_nothrow(HKEY key, PCWSTR path, _Out_ wil::unique_hkey& hkey, wil::reg::key_access access = wil::reg::key_access::read) nothrow |
||
| Shared pointer | wil::reg::create_shared_key |
wil::shared_hkey wil::reg::create_shared_key(HKEY key, PCWSTR path, wil::reg::key_access access = wil::reg::key_access::read) |
|
wil::reg::create_shared_key_nothrow |
HRESULT wil::reg::create_shared_key_nothrow(HKEY key, PCWSTR path, _Out_ wil::shared_hkey& hkey, wil::reg::key_access access = wil::reg::key_access::read) nothrow |
-
HKEY key- a handle to an open or well-known registry key. -
PCWSTR path- the path of a registry key relative to the key specified by thekeyparameter -
wil::reg::key_access access- how to open the key (read/readwrite). See Registry Key Security and Access Rights.- Possible values:
-
wil::reg::key_access::read(default) - read only -
wil::reg::key_access::readwrite- read and write allowed
-
- Possible values:
See documentation for RegCreateKeyEx.
Returns:
-
wil::unique_hkeyfor*_unique_keyfunctions. -
wil::shared_hkeyfor*_shared_keyvariants. - HRESULT for
*_key_nothrowvariants. Uses_Out_pointers to returnwil::unique_hkeyorwil::shared_hkey.
Nothrow variants will never throw; any errors are propagated to the HRESULT return value. All other functions will throw for an error. For open_*, that includes when the key does not yet exist.
// Get values (or try_get if the value might not exist)
const DWORD dword = wil::reg::get_value_dword(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", L"AppsUseLightTheme");
const std::optional<std::wstring> stringOptional = wil::reg::try_get_value_string(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes", L"CurrentTheme");
// Known HKEY
const auto key = wil::reg::open_unique_key(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize");
const DWORD otherDword = wil::reg::get_value_dword(key.get(), L"AppsUseLightTheme");
// nothrow version, if you don't have exceptions
wil::unique_bstr bstr;
THROW_IF_FAILED(wil::reg::get_value_string_nothrow(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes", L"CurrentTheme", bstr));
// Templated version
const auto value = wil::reg::get_value<std::wstring>(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes", L"CurrentTheme");Each function has 2 overloads. One for accessing values of specific,
already-opened keys (e.g., you called wil::reg::open_key before) and one for
accessing subkeys of open keys:
- Access known key (just an HKEY)
(HKEY key, _In_opt_ PCWSTR value_name, /* ... */)- Example:
wil::reg::get_value_dword(myKeyFromElsewhere, L"Foo");
- Access arbitrary subkeys (HKEY + subkey string)
(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, /* ... */)- Example:
wil::reg::get_value_dword(HKEY_CURRENT_USER, L"Microsoft\\Windows\\Advanced", L"Foo");
Here are all the getters, by type (noting that each function has 2 overloads, see Function prefaces for read and write above).
| type | note | get | try_get | get (nothrow) |
|---|---|---|---|---|
|
(requires exceptions) returns the expected type throws on any error |
(requires exceptions + <optional>)returns an optional of the expected type, std::nullopt on ERROR_FILE_NOT_FOUND & ERROR_PATH_NOT_FOUNDthrows on any other error |
returns HRESULTs does not throw |
||
| DWORD | uint32_t wil::reg::get_value_dword(/*...*/) |
std::optional<uint32_t> wil::reg::try_get_value_dword(/*...*/) |
HRESULT wil::reg::get_value_dword_nothrow(/*...*/, _Out_ uint32_t*) noexcept |
|
| QWORD | (aka DWORD64) | uint64_t wil::reg::get_value_qword(/*...*/) |
std::optional<uint64_t> wil::reg::try_get_value_qword(/*...*/) |
HRESULT wil::reg::get_value_qword_nothrow(/*...*/, _Out_ uint64_t*) noexcept |
| String | (std::wstring) |
std::wstring wil::reg::get_value_string(/*...*/) |
std::optional<std::wstring> wil::reg::try_get_value_string(/*...*/) |
(see next) |
| String | (wchar_t[N]) |
- | - | HRESULT get_value_string_nothrow(/*...*/, _Out_ wchar_t[N]) noexcept |
| String | (any supported string type StringT; see Strings notes below) |
StringT wil::reg::get_value_string<StringT>(/*...*/) |
std::optional<StringT> wil::reg::try_get_value_string<StringT>(/*...*/) |
HRESULT wil::reg::get_value_string_nothrow<StringT>(/*...*/, _Inout_ StringT&) noexcept |
| Expanded string | (std::wstring) |
std::wstring wil::reg::get_value_expanded_string(/*...*/) |
std::optional<std::wstring> wil::reg::try_get_value_expanded_string(/*...*/) |
(see next) |
| Expanded string | (wchar_t[N]) |
- | - | HRESULT wil::reg::get_value_expanded_string_nothrow(/*...*/, _Out_ wchar_t[N]) noexcept |
| Expanded string | (any supported string type StringT) |
StringT wil::reg::get_value_expanded_string<StringT>(/*...*/) |
std::optional<StringT> wil::reg::try_get_value_expanded_string(/*...*/) (see Strings notes below) |
HRESULT wil::reg::get_value_expanded_string_nothrow<StringT>(/*...*/, _Inout_ StringT&) noexcept |
| Multistring | std::vector<std::wstring> wil::reg::get_value_multistring(/*...*/) |
std::optional<std::vector<std::wstring>> wil::reg::try_get_value_multistring(/*...*/) |
HRESULT wil::reg::get_value_multistring_nothrow(/*...*/, wil::unique_cotaskmem_array_ptr<wil::unique_cotaskmem_string>&) noexcept |
|
| Binary | (requires extra type parameter like REG_BINARY or REG_DWORD) |
std::vector<uint8_t> wil::reg::get_value_binary(/*...*/, uint32_t type) |
std::optional<std::vector<uint8_t>> wil::reg::get_value_binary(/*...*/, uint32_t type) |
HRESULT wil::reg::get_value_binary_nothrow(/*...*/, uint32_t type, _Inout_ wil::unique_cotaskmem_array_ptr<uint8_t>&) noexcept |
| Any | (templated function for any of the above types, except binary) | T wil::reg::get_value<T>(/*...*/) |
std::optional<T> wil::reg::try_get_value<T>(/*...*/) |
HRESULT wil::reg::get_value_nothrow(/*...*/, _Out_ T*) noexcept(note: some types are _Inout_ T&, not pointers) |
-
HKEY key- a handle to an open or well-known registry key. -
_In_opt_ PCWSTR subkey- the path of a registry key relative to the key specified by thekeyparameter.- May be
nullptror the empty string (L"") to read the value specified bykeyitself. - Note: each getter has a variant where this parameter can be left out entirely (see Function prefaces for read and write above).
- May be
-
_In_opt_ PCWSTR value_name- the name of the registry value.- May be
nullptror the empty string (L"") to read from the key's unnamed and default value, if any.
- May be
See documentation for RegGetValue.
- Specified type
T(see table) forget_value_*functions. -
std::optional<T>of specified typeT(see table) fortry_get_value_*functions. -
HRESULTfor*_nothrowfunctions. Uses_Out_pointers to return result.
Errors are propagated as follows:
-
get_value_*functions throw on all errors. -
try_get_value_*functions returnstd::nulloptif the value does not exist and throw on all other errors. -
*_nothrowfunctions return all errors asHRESULTs.
You can use any of the following types as StringT for the *_string and *_expanded_string functions:
std::wstringwil::unique_cotaskmem_stringwil::shared_cotaskmem_stringwil::unique_bstrwil::shared_bstr
For the try_get_ functions, only these types are available (the unique_ types are disabled):
std::wstringwil::shared_cotaskmem_stringwil::shared_bstr
This is because it is very difficult to access these unique values from a std::optional.
// Set values
wil::reg::set_value_dword(HKEY_CURRENT_USER, L"Software\\Microsoft\\BasicRegistryTest", L"DwordValue", 18);
wil::reg::set_value_string(HKEY_CURRENT_USER, L"Software\\Microsoft\\BasicRegistryTest", L"StringValue", L"Wowee zowee");
// Generic versions, if you don't want to specify type.
wil::reg::set_value(HKEY_CURRENT_USER, L"Software\\Microsoft\\BasicRegistryTest", L"DwordValue2", 1);
wil::reg::set_value(HKEY_CURRENT_USER, L"Software\\Microsoft\\BasicRegistryTest", L"StringValue2", L"Besto wuz here");
// Known HKEY
const auto key = wil::reg::create_unique_key(HKEY_CURRENT_USER, L"Software\\Microsoft\\BasicRegistryTest", wil::reg::key_access::readwrite);
wil::reg::set_value_dword(key.get(), L"DwordValue3", 42);
// nothrow version, if you don't have exceptions
THROW_IF_FAILED(wil::reg::set_value_string_nothrow(HKEY_CURRENT_USER, L"Software\\Microsoft\\BasicRegistryTest", L"StringValue3", L"Hi, Mom!"));Here are all the getters, by type (noting that each function has 2 overloads, see Function prefaces for read and write above).
| type | note | set | set (nothrow) |
|---|---|---|---|
|
(requires exceptions) throws on any error |
returns HRESULTs, does not throw | ||
| DWORD | void wil::reg::set_value_dword(/*...*/, uint32_t) |
HRESULT wil::reg::set_value_dword_nothrow(/*...*/, uint32_t) noexcept |
|
| QWORD | (aka DWORD64) | void wil::reg::set_value_qword(/*...*/, uint64_t) |
HRESULT wil::reg::set_value_qword_nothrow(/*...*/, uint64_t) noexcept |
| String | void wil::reg::set_value_string(/*...*/, PCWSTR) |
HRESULT wil::reg::set_value_string_nothrow(/*...*/, PCWSTR) noexcept |
|
| Expanded string | void wil::reg::set_value_expanded_string(/*...*/, PCWSTR) |
HRESULT wil::reg::set_value_expanded_string_nothrow(/*...*/, PCWSTR) noexcept |
|
| Multistring | void wil::reg::set_value_multistring(/*...*/, const std::vector<std::wstring>&) |
HRESULT wil::reg::set_value_multistring_nothrow(/*...*/, const std::vector<std::wstring>&) noexcept |
|
| Byte vector/binary blob | void wil::reg::set_value_binary(/*...*/, uint32_t type, const std::vector<uint8_t>&) |
void wil::reg::set_value_binary_nothrow(/*...*/, uint32_t type, const wil::unique_cotaskmem_array_ptr<uint8_t>&) noexcept |
|
| Any | (templated function for any of the above types, except binary) | void wil::reg::set_value<T>(/*...*/, const T&) |
HRESULT wil::reg::set_value_nothrow<T>(/*...*/, const T&) noexcept |
-
HKEY key- a handle to an open or well-known registry key. If using a manually-opened key, the key must have been opened with theKEY_SET_VALUEaccess right (wil::reg::key_access::readwriteif using the WIL helpers). -
_In_opt_ PCWSTR subkey- the path of a registry key relative to the key specified by thekeyparameter.- May be
nullptror the empty string (L"") to read the value specified bykeyitself. - Created if not previously existent.
- Note: each getter has a variant where this parameter can be left out entirely (see Function prefaces for read and write above).
- May be
-
_In_opt_ PCWSTR value_name- the name of the registry value.- May be
nullptror the empty string (L"") to write to the key's unnamed and default value. - Created if not previously existent.
- May be
-
T data- the data to write (whereTis the type indicated by the API in the table above).
See the documentation for RegSetKeyValue.
-
voidfor all throwing functions. Throws on any error. -
HRESULTfor all*_nothrowvariants. Never throws; all errors propagated asHRESULTs.
const auto key = wil::reg::create_unique_key(HKEY_CURRENT_USER, L"Software\\Microsoft\\BasicRegistryTest", wil::reg::key_access::readwrite);
// Get count of child keys and values.
const uint32_t childValCount = wil::reg::get_child_value_count(key.get());
const uint32_t childKeyCount = wil::reg::get_child_key_count(key.get());
// Get last modified date
const FILETIME lastModified = wil::reg::get_last_write_filetime(key.get());
// Simple helpers for analyzing returned HRESULTs
const bool a = wil::reg::is_registry_buffer_too_small(HRESULT_FROM_WIN32(ERROR_MORE_DATA)); // => true
const bool b = wil::reg::is_registry_not_found(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); // => true
const bool c = wil::reg::is_registry_not_found(HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)); // => true-
uint32_t wil::reg::get_child_key_count(HKEY key)- get the number of child keys of a given open key or well-known key. -
uint32_t wil::reg::get_child_value_count(HKEY key)- get the number of child values of a given open key or well-known key. -
FILETIME wil::reg::get_last_write_filetime(HKEY key)- get the last-modified date of a given open key or well-known key.
See documentation for RegQueryInfoKey. Each of these functions has a _nothrow variant.
-
bool wil::reg::is_hresult_buffer_too_small(HRESULT hr)- returnstrueiffhrsignals the destination buffer is too small. -
bool wil::reg::is_hresult_not_found(HRESULT hr)- returnstrueiffhrsignals that the desired key/value is not found.
Useful for handling get_value* HRESULTs manually. See documentation for RegGetValue's return value.
These functions enable observing changes to registry keys
#include <wil/registry.h>
auto watcher = wil::make_registry_watcher(HKEY_CURRENT_USER, LR"(Software\Microsoft\Settings)", true, [](wil::RegistryChangeKind changeType)
{
InvalidateRegistryCache()
});wil::reg::key_iterator and wil::reg::value_iterator enable enumerating the contents of a registry key.
// Inspect the sub-keys
for (const auto& key_data : wil::make_range(wil::reg::key_iterator{HKEY_CURRENT_USER_LOCAL_SETTINGS}, wil::reg::key_iterator{}))
{
key_data.name;
}
// Inspect the values under a key and their type
for (const auto& key_data : wil::make_range(wil::reg::value_iterator{HKEY_CURRENT_USER_LOCAL_SETTINGS}, wil::reg::value_iterator{}))
{
key_data.type;
key_data.name;
}