-
Notifications
You must be signed in to change notification settings - Fork 236
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 thekey
parameter -
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_hkey
for*_unique_key
functions. -
wil::shared_hkey
for*_shared_key
variants. - HRESULT for
*_key_nothrow
variants. Uses_Out_
pointers to returnwil::unique_hkey
orwil::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_FOUND throws 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 thekey
parameter.- May be
nullptr
or the empty string (L""
) to read the value specified bykey
itself. - 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
nullptr
or 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. -
HRESULT
for*_nothrow
functions. Uses_Out_
pointers to return result.
Errors are propagated as follows:
-
get_value_*
functions throw on all errors. -
try_get_value_*
functions returnstd::nullopt
if the value does not exist and throw on all other errors. -
*_nothrow
functions return all errors asHRESULT
s.
You can use any of the following types as StringT
for the *_string
and *_expanded_string
functions:
std::wstring
wil::unique_cotaskmem_string
wil::shared_cotaskmem_string
wil::unique_bstr
wil::shared_bstr
For the try_get_
functions, only these types are available (the unique_
types are disabled):
std::wstring
wil::shared_cotaskmem_string
wil::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_VALUE
access right (wil::reg::key_access::readwrite
if using the WIL helpers). -
_In_opt_ PCWSTR subkey
- the path of a registry key relative to the key specified by thekey
parameter.- May be
nullptr
or the empty string (L""
) to read the value specified bykey
itself. - 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
nullptr
or 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 (whereT
is the type indicated by the API in the table above).
See the documentation for RegSetKeyValue.
-
void
for all throwing functions. Throws on any error. -
HRESULT
for all*_nothrow
variants. Never throws; all errors propagated asHRESULT
s.
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)
- returnstrue
iffhr
signals the destination buffer is too small. -
bool wil::reg::is_hresult_not_found(HRESULT hr)
- returnstrue
iffhr
signals 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;
}