//********************************************************* // // Copyright (c) Microsoft. All rights reserved. // This code is licensed under the MIT License. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A // PARTICULAR PURPOSE AND NONINFRINGEMENT. // //********************************************************* //! @file //! Helpers for reading and writing values to/from the registry. #ifndef __WIL_REGISTRY_INCLUDED #define __WIL_REGISTRY_INCLUDED #ifdef _KERNEL_MODE #error This header is not supported in kernel-mode. #endif #include #include // new(std::nothrow) #include "registry_helpers.h" #include "resource.h" // wil registry does not require the use of the STL or C++ exceptions (see _nothrow functions) // wil registry natively supports std::vector and std::wstring when preferring those types // wil registry uses the __WIL_WINREG_STL define to enable support for wil::shared_* types (defined in resource.h) namespace wil { //! Functions and classes that support reading and writing values to/from the registry. namespace reg { #if defined(WIL_ENABLE_EXCEPTIONS) /** * @brief Opens a new HKEY to the specified path - see RegOpenKeyExW * @param key An open or well-known registry key * @param subKey The name of the registry subkey to be opened. * If `nullptr`, then `key` is used without modification. * @param access The requested access desired for the opened key * @return A wil::unique_hkey containing the resulting opened HKEY * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline ::wil::unique_hkey open_unique_key(HKEY key, _In_opt_ PCWSTR subKey, ::wil::reg::key_access access = ::wil::reg::key_access::read) { const reg_view_details::reg_view regview{key}; ::wil::unique_hkey return_value; regview.open_key(subKey, &return_value, access); return return_value; } /** * @brief Creates a new HKEY to the specified path - see RegCreateKeyExW * @param key An open or well-known registry key * @param subKey The name of a subkey that this function opens or creates. * Note: this cannot be null (see the above referenced API documentation) * @param access The requested access desired for the opened key * @return A wil::unique_hkey or wil::shared_hkey containing the resulting opened HKEY * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline ::wil::unique_hkey create_unique_key(HKEY key, PCWSTR subKey, ::wil::reg::key_access access = ::wil::reg::key_access::read) { const reg_view_details::reg_view regview{key}; ::wil::unique_hkey return_value; regview.create_key(subKey, &return_value, access); return return_value; } #if defined(__WIL_WINREG_STL) || defined(WIL_DOXYGEN) /** * @brief Opens a new HKEY to the specified path - see RegOpenKeyExW * @param key An open or well-known registry key * @param subKey The name of the registry subkey to be opened. * If `nullptr`, then `key` is used without modification. * @param access The requested access desired for the opened key * @return A wil::shared_hkey containing the resulting opened HKEY * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline ::wil::shared_hkey open_shared_key(HKEY key, _In_opt_ PCWSTR subKey, ::wil::reg::key_access access = ::wil::reg::key_access::read) { const reg_view_details::reg_view regview{key}; ::wil::shared_hkey return_value; regview.open_key(subKey, &return_value, access); return return_value; } /** * @brief Creates a new HKEY to the specified path - see RegCreateKeyExW * @param key An open or well-known registry key * @param subKey The name of a subkey that this function opens or creates. * Note: this cannot be null (see the above referenced API documentation) * @param access The requested access desired for the opened key * @return A wil::shared_hkey or wil::shared_hkey containing the resulting opened HKEY * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline ::wil::shared_hkey create_shared_key(HKEY key, PCWSTR subKey, ::wil::reg::key_access access = ::wil::reg::key_access::read) { const reg_view_details::reg_view regview{key}; ::wil::shared_hkey return_value; regview.create_key(subKey, &return_value, access); return return_value; } #endif // #if defined(__WIL_WINREG_STL) #endif // #if defined(WIL_ENABLE_EXCEPTIONS) /** * @brief Opens a new HKEY to the specified path - see RegOpenKeyExW * @param key An open or well-known registry key * @param subKey The name of the registry subkey to be opened. * If `nullptr`, then `key` is used without modification. * @param[out] hkey A reference to a wil::unique_hkey to receive the opened HKEY * @param access The requested access desired for the opened key * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT open_unique_key_nothrow( HKEY key, _In_opt_ PCWSTR subKey, ::wil::unique_hkey& hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) WI_NOEXCEPT { const reg_view_details::reg_view_nothrow regview{key}; return regview.open_key(subKey, hkey.put(), access); } /** * @brief Creates a new HKEY to the specified path - see RegCreateKeyExW * @param key An open or well-known registry key * @param subKey The name of a subkey that this function opens or creates. * Note: this cannot be null (see the above referenced API documentation) * @param[out] hkey A reference to a wil::unique_hkey to receive the opened HKEY * @param access The requested access desired for the opened key * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT create_unique_key_nothrow( HKEY key, PCWSTR subKey, ::wil::unique_hkey& hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) WI_NOEXCEPT { const reg_view_details::reg_view_nothrow regview{key}; return regview.create_key(subKey, hkey.put(), access); } #if defined(__WIL_WINREG_STL) || defined(WIL_DOXYGEN) /** * @brief Opens a new HKEY to the specified path - see RegOpenKeyExW * @param key An open or well-known registry key * @param subKey The name of the registry subkey to be opened. * If `nullptr`, then `key` is used without modification. * @param[out] hkey A reference to a wil::shared_hkey to receive the opened HKEY * @param access The requested access desired for the opened key * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT open_shared_key_nothrow( HKEY key, _In_opt_ PCWSTR subKey, ::wil::shared_hkey& hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) WI_NOEXCEPT { const reg_view_details::reg_view_nothrow regview{key}; return regview.open_key(subKey, hkey.put(), access); } /** * @brief Creates a new HKEY to the specified path - see RegCreateKeyExW * @param key An open or well-known registry key * @param subKey The name of a subkey that this function opens or creates. * Note: this cannot be null (see the above referenced API documentation) * @param[out] hkey A reference to a wil::shared_hkey to receive the opened HKEY * @param access The requested access desired for the opened key * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT create_shared_key_nothrow( HKEY key, PCWSTR subKey, ::wil::shared_hkey& hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) WI_NOEXCEPT { const reg_view_details::reg_view_nothrow regview{key}; return regview.create_key(subKey, hkey.put(), access); } #endif // #define __WIL_WINREG_STL // // wil::key_iterator and wil::value_iterator objects enable enumerating registry keys and values. // // Examples of usage when std::wstring is included: // // for (const auto& key_data : wil::make_range(wil::reg::key_iterator{hkey}, wil::reg::key_iterator{})) // { // key_data.name; // the std::wstring of the enumerated key // } // // for (const auto& value_data : wil::make_range(wil::reg::value_iterator{hkey}, wil::reg::value_iterator{})) // { // value_data.name; // the std::wstring of the enumerated value // value_data.type; // the REG_ type of the enumerated value // } // // When std::wstring is not included, wil::unique_process_heap_string can be used instead: // // for (const auto& key_data : wil::make_range(wil::reg::key_heap_string_iterator{hkey}, wil::reg::key_heap_string_iterator{})) // { // key_data.name.get(); // the PCWSTR of the enumerated key // } // // for (const auto& value_data : wil::make_range(wil::reg::value_heap_string_iterator{hkey}, wil::reg::value_heap_string_iterator{})) // { // value_data.name.get(); // the PCWSTR of the enumerated value // value_data.type; // the REG_ type of the enumerated value // } // // When not using exceptions, can manually walk the iterator using wil::unique_process_heap_string: // // auto iterate_keys = wil::reg::key_heap_string_nothrow_iterator{hkey}; // for (const auto& key_data : wil::make_range(iterate_keys, wil::reg::key_heap_string_nothrow_iterator{})) // { // key_data.name.get(); // the PCWSTR of the enumerated key // } // if (FAILED(iterate_keys.last_error())) // { // // the HRESULT last_error() returns the registry error that prevented enumeration // } // // auto iterate_values = wil::reg::value_heap_string_nothrow_iterator{hkey}; // for (const auto& value_data : wil::make_range(iterate_values, wil::reg::value_heap_string_nothrow_iterator{})) // { // value_data.name.get(); // the PCWSTR of the enumerated value // value_data.type; // the REG_ type of the enumerated value // } // if (FAILED(iterate_values.last_error())) // { // // the HRESULT last_error() returns the registry error that prevented enumeration // } // #if defined(WIL_ENABLE_EXCEPTIONS) #if defined(_STRING_) || defined(WIL_DOXYGEN) using key_iterator = ::wil::reg::iterator_t<::wil::reg::key_iterator_data<::std::wstring>>; using value_iterator = ::wil::reg::iterator_t<::wil::reg::value_iterator_data<::std::wstring>>; #endif #if defined(__WIL_OLEAUTO_H_) || defined(WIL_DOXYGEN) using key_bstr_iterator = ::wil::reg::iterator_t<::wil::reg::key_iterator_data<::wil::unique_bstr>>; using value_bstr_iterator = ::wil::reg::iterator_t<::wil::reg::value_iterator_data<::wil::unique_bstr>>; #endif // #if defined(__WIL_OLEAUTO_H_) using key_heap_string_iterator = ::wil::reg::iterator_t<::wil::reg::key_iterator_data<::wil::unique_process_heap_string>>; using value_heap_string_iterator = ::wil::reg::iterator_t<::wil::reg::value_iterator_data<::wil::unique_process_heap_string>>; #endif // #if defined(WIL_ENABLE_EXCEPTIONS) // no-throw versions of applicable registry iterators #if defined(__WIL_OLEAUTO_H_) || defined(WIL_DOXYGEN) using key_bstr_nothrow_iterator = ::wil::reg::iterator_nothrow_t<::wil::reg::key_iterator_data<::wil::unique_bstr>>; using value_bstr_nothrow_iterator = ::wil::reg::iterator_nothrow_t<::wil::reg::value_iterator_data<::wil::unique_bstr>>; #endif // #if defined(__WIL_OLEAUTO_H_) using key_heap_string_nothrow_iterator = ::wil::reg::iterator_nothrow_t<::wil::reg::key_iterator_data<::wil::unique_process_heap_string>>; using value_heap_string_nothrow_iterator = ::wil::reg::iterator_nothrow_t<::wil::reg::value_iterator_data<::wil::unique_process_heap_string>>; /** * @brief Queries for number of sub-keys * @param key The HKEY to query for number of sub-keys * @param[out] numSubKeys A pointer to a DWORD to receive the returned count * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_child_key_count_nothrow(HKEY key, _Out_ DWORD* numSubKeys) WI_NOEXCEPT { RETURN_IF_WIN32_ERROR(RegQueryInfoKeyW( key, nullptr, // null class nullptr, // null class character count, nullptr, // null reserved numSubKeys, nullptr, // null max subkey length nullptr, // null max class length nullptr, // null value count nullptr, // null max value name length nullptr, // null max value length nullptr, // null security descriptor nullptr)); // null last write filetime return S_OK; } inline HRESULT get_child_key_count_nothrow(HKEY key, _Out_ uint32_t* numSubKeys) WI_NOEXCEPT { DWORD subKeys{}; RETURN_IF_FAILED(::wil::reg::get_child_key_count_nothrow(key, &subKeys)); *numSubKeys = subKeys; return S_OK; } /** * @brief Queries for number of values * @param key The HKEY to query for number of values * @param[out] numSubValues A pointer to a DWORD to receive the returned count * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_child_value_count_nothrow(HKEY key, _Out_ DWORD* numSubValues) WI_NOEXCEPT { RETURN_IF_WIN32_ERROR(RegQueryInfoKeyW( key, nullptr, // null class nullptr, // null class char count, nullptr, // null reserved nullptr, // null subkey count nullptr, // null max subkey length nullptr, // null max class length numSubValues, nullptr, // null max value name length nullptr, // null max value length nullptr, // null security descriptor nullptr)); // null last write filetime return S_OK; } inline HRESULT get_child_value_count_nothrow(HKEY key, _Out_ uint32_t* numSubValues) WI_NOEXCEPT { DWORD subValues{}; RETURN_IF_FAILED(::wil::reg::get_child_value_count_nothrow(key, &subValues)); *numSubValues = subValues; return S_OK; } /** * @brief Queries for the filetime when the registry key was last written * @param key The HKEY to query for number of values * @param[out] lastModified A pointer to a FILETIME to receive the last write time * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline HRESULT get_last_write_filetime_nothrow(HKEY key, _Out_ FILETIME* lastModified) WI_NOEXCEPT { RETURN_IF_WIN32_ERROR(RegQueryInfoKeyW( key, nullptr, // null class nullptr, // null class char count, nullptr, // null reserved nullptr, // null subkey count nullptr, // null max subkey length nullptr, // null max class length nullptr, // null value count nullptr, // null max value name length nullptr, // null max value length nullptr, // null security descriptor lastModified)); return S_OK; } #if defined(WIL_ENABLE_EXCEPTIONS) /** * @brief Queries for number of sub-keys * @param key The HKEY to query for number of sub-keys * @return The queried number of sub-keys if succeeded * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline uint32_t get_child_key_count(HKEY key) { uint32_t numSubKeys{}; THROW_IF_FAILED(::wil::reg::get_child_key_count_nothrow(key, &numSubKeys)); return numSubKeys; } /** * @brief Queries for number of values * @param key The HKEY to query for number of values * @return The queried number of value if succeeded * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline uint32_t get_child_value_count(HKEY key) { uint32_t numSubValues{}; THROW_IF_FAILED(::wil::reg::get_child_value_count_nothrow(key, &numSubValues)); return numSubValues; } /** * @brief Queries for the filetime when the registry key was last written * @param key The HKEY to query for number of values * @return The queried filetime if succeeded * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline FILETIME get_last_write_filetime(HKEY key) { FILETIME lastModified{}; THROW_IF_FAILED(::wil::reg::get_last_write_filetime_nothrow(key, &lastModified)); return lastModified; } #endif // #if defined(WIL_ENABLE_EXCEPTIONS) #if defined(WIL_ENABLE_EXCEPTIONS) // // template // void set_value(...) // // - Writes a value to a specified key and subkey, deducing the type from the given data // - Throws a std::exception on failure (including wil::ResultException) // // Examples of usage (the template type does not need to be explicitly specified) // wil::reg::set_value(key, L"subkey", L"dword_value_name", 0); // writes a REG_DWORD // wil::reg::set_value(key, L"subkey", L"qword_value_name", 0ull); // writes a REG_QWORD // wil::reg::set_value(key, L"subkey", L"string_value_name", L"hello"); // writes a REG_SZ // // A subkey is not required if the key is opened where this should write the value: // wil::reg::set_value(key, L"dword_value_name", 0); // writes a REG_DWORD // wil::reg::set_value(key, L"qword_value_name", 0ull); // writes a REG_QWORD // wil::reg::set_value(key, L"string_value_name", L"hello"); // writes a REG_SZ // // Example usage writing a vector of wstrings to a REG_MULTI_SZ // std::vector data { L"string1", L"string2", L"string3" }; // wil::reg::set_value(key, L"multi_string_value_name", data); // wil::reg::set_value(key, L"multi_string_value_name", data); // // Example of usage writing directly to a registry value from a raw byte vector // - notice the registry type is required, not implied // std::vector data { 0x00, 0xff, 0xee, 0xdd, 0xcc }; // wil::reg::set_value_binary(key, L"binary_value_name", REG_BINARY, data); // wil::reg::set_value_binary(key, L"binary_value_name", REG_BINARY, data); // /** * @brief Writes a value to a specified key and subkey, deducing the type from the given data. * @tparam T The type of the data being set (the registry value type is deduced from T). * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The data (of type T) to write to the specified registry value * @exception std::exception (including wil::ResultException) will be thrown on all failures */ template void set_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, const T& data) { const reg_view_details::reg_view regview{key}; regview.set_value(subkey, value_name, data); } /** * @brief Writes a value under a specified key, the registry type based off the templated type passed as data * @tparam T The type of the data being set (the registry value type is deduced from T). * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The data (of type T) to write to the specified registry value * @exception std::exception (including wil::ResultException) will be thrown on all failures */ template void set_value(HKEY key, _In_opt_ PCWSTR value_name, const T& data) { ::wil::reg::set_value(key, nullptr, value_name, data); } /** * @brief Writes a null-terminated string value under a specified key * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The null-terminated string to write to the specified registry value * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline void set_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) { const reg_view_details::reg_view regview{key}; regview.set_value(subkey, value_name, data); } /** * @brief Writes a null-terminated string value under a specified key * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The null-terminated string to write to the specified registry value * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline void set_value(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) { ::wil::reg::set_value(key, nullptr, value_name, data); } /** * @brief Writes a REG_DWORD value from a uint32_t * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The 32-bit value to write to the specified registry value * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline void set_value_dword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t data) { ::wil::reg::set_value(key, subkey, value_name, data); } /** * @brief Writes a REG_DWORD value from a uint32_t * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The 32-bit value to write to the specified registry value * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline void set_value_dword(HKEY key, _In_opt_ PCWSTR value_name, uint32_t data) { ::wil::reg::set_value(key, nullptr, value_name, data); } /** * @brief Writes a REG_QWORD value from a uint64_t * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The 64-bit value to write to the specified registry value * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline void set_value_qword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint64_t data) { ::wil::reg::set_value(key, subkey, value_name, data); } /** * @brief Writes a REG_QWORD value from a uint64_t * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The 64-bit value to write to the specified registry value * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline void set_value_qword(HKEY key, _In_opt_ PCWSTR value_name, uint64_t data) { ::wil::reg::set_value(key, nullptr, value_name, data); } /** * @brief Writes a REG_SZ value from a null-terminated string * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The null-terminated string value to write to the specified registry value * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline void set_value_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) { ::wil::reg::set_value(key, subkey, value_name, data); } /** * @brief Writes a REG_SZ value from a null-terminated string * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The null-terminated string value to write to the specified registry value * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline void set_value_string(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) { ::wil::reg::set_value(key, nullptr, value_name, data); } /** * @brief Writes a REG_EXPAND_SZ value from a null-terminated string * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The null-terminated, unexpanded string value to write to the specified registry value. For example, `%PATH%`. * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline void set_value_expanded_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) { const reg_view_details::reg_view regview{key}; regview.set_value(subkey, value_name, data, REG_EXPAND_SZ); } /** * @brief Writes a REG_EXPAND_SZ value from a null-terminated string * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The null-terminated, unexpanded string value to write to the specified registry value. For example, `%PATH%`. * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline void set_value_expanded_string(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) { ::wil::reg::set_value_expanded_string(key, nullptr, value_name, data); } #if (defined(_VECTOR_) && defined(_STRING_)) || defined(WIL_DOXYGEN) /** * @brief The generic set_value template function to write a REG_MULTI_SZ value from a std::vector * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data A std::vector to write to the specified registry value. * Each string will be marshaled to a contiguous null-terminator-delimited multi-sz string * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline void set_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, const ::std::vector<::std::wstring>& data) { const auto multiStringWcharVector(reg_view_details::get_multistring_from_wstrings(::std::begin(data), ::std::end(data))); const reg_view_details::reg_view regview{key}; regview.set_value(subkey, value_name, multiStringWcharVector, REG_MULTI_SZ); } /** * @brief The generic set_value template function to write a REG_MULTI_SZ value from a std::vector * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data A std::vector to write to the specified registry value. * Each string will be marshaled to a contiguous null-terminator-delimited multi-sz string. * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline void set_value(HKEY key, _In_opt_ PCWSTR value_name, const ::std::vector<::std::wstring>& data) { ::wil::reg::set_value(key, nullptr, value_name, data); } /** * @brief Writes a REG_MULTI_SZ value from a std::vector * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data A std::vector to write to the specified registry value. * Each string will be marshaled to a contiguous null-terminator-delimited multi-sz string * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline void set_value_multistring(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, const ::std::vector<::std::wstring>& data) { ::wil::reg::set_value(key, subkey, value_name, data); } /** * @brief Writes a REG_MULTI_SZ value from a std::vector * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data A std::vector to write to the specified registry value. * Each string will be marshaled to a contiguous null-terminator-delimited multi-sz string. * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline void set_value_multistring(HKEY key, _In_opt_ PCWSTR value_name, const ::std::vector<::std::wstring>& data) { ::wil::reg::set_value(key, nullptr, value_name, data); } #endif // #if defined(_VECTOR_) && defined(_STRING_) #if defined(_VECTOR_) || defined(WIL_DOXYGEN) /** * @brief Writes a registry value of the specified type from a `std::vector`/`std::vector` * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param type The registry type for the specified registry value - see RegSetKeyValueW * @param data A `std::vector`/`std::vector` to write to the specified registry value. * The vector contents will be directly marshaled to the specified value. * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline void set_value_binary(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t type, const ::std::vector& data) { const reg_view_details::reg_view regview{key}; regview.set_value(subkey, value_name, data, type); } /** * @brief Writes a registry value of the specified type from a `std::vector`/`std::vector` * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param type The registry type for the specified registry value - see RegSetKeyValueW * @param data A `std::vector`/`std::vector` to write to the specified registry value. * The vector contents will be directly marshaled to the specified value. * @exception std::exception (including wil::ResultException) will be thrown on all failures */ inline void set_value_binary(HKEY key, _In_opt_ PCWSTR value_name, uint32_t type, const ::std::vector& data) { ::wil::reg::set_value_binary(key, nullptr, value_name, type, data); } #endif // #if defined(_VECTOR_) #endif // #if defined(WIL_ENABLE_EXCEPTIONS) // // template // HRESULT set_value_nothrow(...) // // - Writes a value under a specified key // - The type of registry value is determined by the template type T of data given // - Returns an HRESULT error code indicating success or failure (does not throw C++ exceptions) // // Examples of usage (the template type does not need to be explicitly specified) // hr = wil::reg::set_value_nothrow(key, L"subkey", L"dword_value_name", 0); // writes a REG_DWORD // hr = wil::reg::set_value_nothrow(key, L"subkey", L"qword_value_name", 0ull); // writes a REG_QWORD // hr = wil::reg::set_value_nothrow(key, L"subkey", L"string_value_name", L"hello"); // writes a REG_SZ // // A subkey is not required if the key is opened where this should write the value: // hr = wil::reg::set_value_nothrow(key, L"dword_value_name", 0); // writes a REG_DWORD // hr = wil::reg::set_value_nothrow(key, L"qword_value_name", 0ull); // writes a REG_QWORD // hr = wil::reg::set_value_nothrow(key, L"string_value_name", L"hello"); // writes a REG_SZ // // Example of usage writing a REG_MULTI_SZ // std::vector multisz_data { L"string1", L"string2", L"string3" }; // hr = wil::reg::set_value_nothrow(key, L"multi_string_value_name", multisz_data); // // Values can be written directly from a vector of bytes - the registry type must be specified; e.g.: // std::vector data { 0x00, 0xff, 0xee, 0xdd, 0xcc }; // hr = wil::reg::set_value_binary_nothrow(key, L"binary_value_name", REG_BINARY, data); // /** * @brief Writes a value to a specified key and subkey, deducing the type from the given data. * @tparam T The type of the data being set (the registry value type is deduced from T). * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The data (of type T) to write to the specified registry value * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ template HRESULT set_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, const T& data) WI_NOEXCEPT { const reg_view_details::reg_view_nothrow regview{key}; return regview.set_value(subkey, value_name, data); } /** * @brief Writes a value under a specified key, the registry type based off the templated type passed as data * @tparam T The type of the data being set (the registry value type is deduced from T). * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The data (of type T) to write to the specified registry value * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ template HRESULT set_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, const T& data) WI_NOEXCEPT { return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); } /** * @brief Writes a null-terminated string value under a specified key * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The null-terminated string to write to the specified registry value * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT set_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT { const reg_view_details::reg_view_nothrow regview{key}; return regview.set_value(subkey, value_name, data); } /** * @brief Writes a null-terminated string value under a specified key * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The null-terminated string to write to the specified registry value * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT set_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT { return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); } /** * @brief Writes a REG_DWORD value from a uint32_t * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The 32-bit value to write to the specified registry value * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT set_value_dword_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t data) WI_NOEXCEPT { return ::wil::reg::set_value_nothrow(key, subkey, value_name, data); } /** * @brief Writes a REG_DWORD value from a uint32_t * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The 32-bit value to write to the specified registry value * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT set_value_dword_nothrow(HKEY key, _In_opt_ PCWSTR value_name, uint32_t data) WI_NOEXCEPT { return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); } /** * @brief Writes a REG_QWORD value from a uint64_t * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The 64-bit value to write to the specified registry value * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT set_value_qword_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint64_t data) WI_NOEXCEPT { return ::wil::reg::set_value_nothrow(key, subkey, value_name, data); } /** * @brief Writes a REG_QWORD value from a uint64_t * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The 64-bit value to write to the specified registry value * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT set_value_qword_nothrow(HKEY key, _In_opt_ PCWSTR value_name, uint64_t data) WI_NOEXCEPT { return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); } /** * @brief Writes a REG_SZ value from a null-terminated string * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The null-terminated string value to write to the specified registry value * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT set_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT { return ::wil::reg::set_value_nothrow(key, subkey, value_name, data); } /** * @brief Writes a REG_SZ value from a null-terminated string * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The null-terminated string value to write to the specified registry value * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT set_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT { return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); } /** * @brief Writes a REG_EXPAND_SZ value from a null-terminated string * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The null-terminated string value to write to the specified registry value * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT set_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT { const reg_view_details::reg_view_nothrow regview{key}; return regview.set_value(subkey, value_name, data, REG_EXPAND_SZ); } /** * @brief Writes a REG_EXPAND_SZ value from a null-terminated string * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param data The null-terminated string value to write to the specified registry value * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT set_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT { return ::wil::reg::set_value_expanded_string_nothrow(key, nullptr, value_name, data); } #if defined(__WIL_OBJBASE_H_) || defined(WIL_DOXYGEN) /** * @brief Writes raw bytes into a registry value under a specified key of the specified type * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param type The registry type for the specified registry value to write to - see RegSetValue * @param value A ::wil::unique_cotaskmem_array_ptr holding the bytes to write into the specified registry value * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT set_value_binary_nothrow( HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t type, const ::wil::unique_cotaskmem_array_ptr& value) WI_NOEXCEPT { const reg_view_details::reg_view_nothrow regview{key}; RETURN_IF_FAILED(regview.set_value<::wil::unique_cotaskmem_array_ptr>(subkey, value_name, value, type)); return S_OK; } /** * @brief Writes raw bytes into a registry value under a specified key of the specified type * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to write to the unnamed default registry value. * @param type The registry type for the specified registry value to write to - see RegSetValue * @param value A ::wil::unique_cotaskmem_array_ptr holding the bytes to write into the specified registry value * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT set_value_binary_nothrow( HKEY key, _In_opt_ PCWSTR value_name, uint32_t type, const ::wil::unique_cotaskmem_array_ptr& value) WI_NOEXCEPT { return ::wil::reg::set_value_binary_nothrow(key, nullptr, value_name, type, value); } #endif #if defined(WIL_ENABLE_EXCEPTIONS) // // template // T get_value(...) // // - Reads a value under a specified key. // - Requires a type T to be specified. // - Throws a std::exception on failure (including wil::ResultException), including registry value not found. // If you don't want an exception when the value does not exist, use try_get_value(...) // // Examples of usage (ensure the code handles a possible std::exception that will be thrown on all errors) // uint32_t dword_value = wil::reg::get_value(key, L"subkey", L"dword_value_name"); // uint64_t qword_value = wil::reg::get_value(key, L"subkey", L"qword_value_name); // std::wstring string_value = wil::reg::get_value(key, L"subkey", L"string_value_name"); // // A subkey is not required if the key is opened where this should write the value: // uint32_t dword_value = wil::reg::get_value(key, L"dword_value_name"); // uint64_t qword_value = wil::reg::get_value(key, L"qword_value_name); // std::wstring string_value = wil::reg::get_value(key, L"string_value_name"); // // The template type does not need to be specified if using functions written for a targeted type // uint32_t dword_value = wil::reg::get_value_dword(key, L"dword_value_name"); // uint64_t qword_value = wil::reg::get_value_qword(key, L"qword_value_name"); // std::wstring string_value = wil::reg::get_value_string(key, L"string_value_name"); // // Values with REG_EXPAND_SZ can be read into each of the string types; e.g.: // std::wstring expanded_string_value = wil::reg::get_value_expanded_string(key, L"string_value_name_with_environment_variables"); // // Values can be read directly into a vector of bytes - the registry type must be specified; e.g.: // std::vector data = wil::reg::get_value_binary(key, L"binary_value_name", REG_BINARY); // // Multi-string values can be read into a vector; e.g.: // std::vector multi_string_value = wil::reg::get_value_multistring(key, L"multi_string_value_name"); // for (const auto& sub_string_value : multi_string_value) // { // // can read each string parsed from the multi-string // PCWSTR string_value = sub_string_value.c_str(); // } // // Reading REG_SZ and REG_EXPAND_SZ types are done through the below templated get_value_string and get_value_expanded_string functions // Where the template type is the type to receive the string value // The default template type is std::wstring, available if the caller has included the STL header // // Reading a bstr can be stored in a wil::shared_bstr or wil::unique_bstr - wil::shared_bstr has a c'tor taking a wil::unique_bstr // wil::unique_bstr unique_value { wil::reg::get_value_string<::wil::unique_bstr>(key, L"string_value_name") }; // wil::shared_bstr shared_value { wil::reg::get_value_string<::wil::shared_bstr>(key, L"string_value_name") }; // // Reading a cotaskmem string can be stored in a wil::unique_cotaskmem_string or wil::shared_cotaskmem_string // wil::unique_cotaskmem_string unique_value { wil::reg::get_value_string(key, L"string_value_name") }; // wil::shared_cotaskmem_string shared_value { wil::reg::get_value_string(key, L"string_value_name") }; // // Blocking get_value_string template types that are not already specialized - this gives a much friendlier compiler error message template T get_value_string(HKEY /*key*/, _In_opt_ PCWSTR /*subkey*/, _In_opt_ PCWSTR /*value_name*/) { static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_string"); } template T get_value_string(HKEY /*key*/, _In_opt_ PCWSTR /*value_name*/) { static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_string"); } template T get_value_expanded_string(HKEY /*key*/, _In_opt_ PCWSTR /*subkey*/, _In_opt_ PCWSTR /*value_name*/) { static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_expanded_string"); } template T get_value_expanded_string(HKEY /*key*/, _In_opt_ PCWSTR /*value_name*/) { static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_expanded_string"); } /** * @brief Reads a value from a specified key and subkey, deducing registry type from the type parameter T. * @tparam T The type to read (the registry value type is deduced from T) * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value of the template type T * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template T get_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { T return_value{}; const reg_view_details::reg_view regview{key}; regview.get_value(subkey, value_name, return_value); return return_value; } /** * @brief Reads a value under a specified key, deducing registry type from the type parameter T. * @tparam T The type to read (the registry value type is deduced from T) * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value of the template type T * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template T get_value(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value(key, nullptr, value_name); } /** * @brief Reads a REG_DWORD value, returning a uint32_t * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The uint32_t value read from the registry * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ inline uint32_t get_value_dword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value(key, subkey, value_name); } /** * @brief Reads a REG_DWORD value, returning a uint32_t * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The uint32_t value read from the registry * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ inline uint32_t get_value_dword(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value(key, nullptr, value_name); } /** * @brief Reads a REG_QWORD value, returning a uint64_t * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The uint64_t value read from the registry * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ inline uint64_t get_value_qword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value(key, subkey, value_name); } /** * @brief Reads a REG_QWORD value, returning a uint64_t * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The uint64_t value read from the registry * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ inline uint64_t get_value_qword(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value(key, nullptr, value_name); } #if defined(_STRING_) || defined(WIL_DOXYGEN) /** * @brief Reads a REG_SZ value, returning a std::wstring * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A std::wstring created from the string value read from the registry * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ inline ::std::wstring get_value_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value<::std::wstring>(key, subkey, value_name); } /** * @brief Reads a REG_SZ value, returning a std::wstring * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A std::wstring created from the string value read from the registry * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ inline ::std::wstring get_value_string(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value<::std::wstring>(key, nullptr, value_name); } /** * @brief Reads a REG_SZ value, returning a std::wstring * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A std::wstring created from the string value read from the registry * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::std::wstring get_value_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value<::std::wstring>(key, subkey, value_name); } /** * @brief Reads a REG_SZ value, returning a std::wstring * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A std::wstring created from the string value read from the registry * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::std::wstring get_value_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value<::std::wstring>(key, nullptr, value_name); } /** * @brief Reads a REG_EXPAND_SZ value, returning a std::wstring * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A std::wstring created from the string value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ inline ::std::wstring get_value_expanded_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { ::std::wstring value; const reg_view_details::reg_view regview{key}; regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); return value; } /** * @brief Reads a REG_EXPAND_SZ value, returning a std::wstring * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A std::wstring created from the string value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ inline ::std::wstring get_value_expanded_string(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value_expanded_string(key, nullptr, value_name); } /** * @brief Reads a REG_EXPAND_SZ value, returning a std::wstring * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A std::wstring created from the string value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::std::wstring get_value_expanded_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value_expanded_string(key, subkey, value_name); } /** * @brief Reads a REG_EXPAND_SZ value, returning a std::wstring * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A std::wstring created from the string value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::std::wstring get_value_expanded_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value_expanded_string(key, nullptr, value_name); } #endif // #if defined(_STRING_) #if defined(__WIL_OLEAUTO_H_) || defined(WIL_DOXYGEN) /** * @brief Reads a REG_SZ value, returning a wil::unique_bstr * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A wil::unique_bstr created from the string value read from the registry * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::wil::unique_bstr get_value_string<::wil::unique_bstr>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value<::wil::unique_bstr>(key, subkey, value_name); } /** * @brief Reads a REG_SZ value, returning a wil::unique_bstr * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A wil::unique_bstr created from the string value read from the registry * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::wil::unique_bstr get_value_string<::wil::unique_bstr>(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value<::wil::unique_bstr>(key, nullptr, value_name); } /** * @brief Reads a REG_EXPAND_SZ value, returning a wil::unique_bstr * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A wil::unique_bstr created from the string value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::wil::unique_bstr get_value_expanded_string<::wil::unique_bstr>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { ::wil::unique_bstr value; const reg_view_details::reg_view regview{key}; regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); return value; } /** * @brief Reads a REG_EXPAND_SZ value, returning a wil::unique_bstr * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A wil::unique_bstr created from the string value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::wil::unique_bstr get_value_expanded_string<::wil::unique_bstr>(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value_expanded_string<::wil::unique_bstr>(key, nullptr, value_name); } #if defined(__WIL_OLEAUTO_H_STL) || defined(WIL_DOXYGEN) /** * @brief Reads a REG_SZ value, returning a wil::shared_bstr * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A wil::shared_bstr created from the string value read from the registry * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::wil::shared_bstr get_value_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value<::wil::shared_bstr>(key, subkey, value_name); } /** * @brief Reads a REG_SZ value, returning a wil::shared_bstr * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A wil::shared_bstr created from the string value read from the registry * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::wil::shared_bstr get_value_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value<::wil::shared_bstr>(key, nullptr, value_name); } /** * @brief Reads a REG_EXPAND_SZ value, returning a wil::unique_bstr * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A wil::shared_bstr created from the string value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::wil::shared_bstr get_value_expanded_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { ::wil::shared_bstr value; const reg_view_details::reg_view regview{key}; regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); return value; } /** * @brief Reads a REG_EXPAND_SZ value, returning a wil::shared_bstr * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A wil::shared_bstr created from the string value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::wil::shared_bstr get_value_expanded_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value_expanded_string<::wil::shared_bstr>(key, nullptr, value_name); } #endif // #if defined(__WIL_OLEAUTO_H_STL) #endif // #if defined(__WIL_OLEAUTO_H_) #if defined(__WIL_OBJBASE_H_) || defined(WIL_DOXYGEN) /** * @brief Reads a REG_SZ value, returning a wil::unique_cotaskmem_string * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A wil::unique_cotaskmem_string created from the string value read from the registry * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::wil::unique_cotaskmem_string get_value_string<::wil::unique_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value<::wil::unique_cotaskmem_string>(key, subkey, value_name); } /** * @brief Reads a REG_SZ value, returning a wil::unique_cotaskmem_string * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A wil::unique_cotaskmem_string created from the string value read from the registry * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::wil::unique_cotaskmem_string get_value_string<::wil::unique_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value<::wil::unique_cotaskmem_string>(key, nullptr, value_name); } /** * @brief Reads a REG_EXPAND_SZ value, returning a wil::unique_cotaskmem_string * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A wil::unique_cotaskmem_string created from the string value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::wil::unique_cotaskmem_string get_value_expanded_string<::wil::unique_cotaskmem_string>( HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { ::wil::unique_cotaskmem_string value; const reg_view_details::reg_view regview{key}; regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); return value; } /** * @brief Reads a REG_EXPAND_SZ value, returning a wil::unique_cotaskmem_string * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A wil::unique_cotaskmem_string created from the string value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::wil::unique_cotaskmem_string get_value_expanded_string<::wil::unique_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR value_name) { return wil::reg::get_value_expanded_string<::wil::unique_cotaskmem_string>(key, nullptr, value_name); } #if defined(__WIL_OBJBASE_H_STL) || defined(WIL_DOXYGEN) /** * @brief Reads a REG_SZ value, returning a wil::shared_cotaskmem_string * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A wil::shared_cotaskmem_string created from the string value read from the registry * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::wil::shared_cotaskmem_string get_value_string<::wil::shared_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value<::wil::shared_cotaskmem_string>(key, subkey, value_name); } /** * @brief Reads a REG_SZ value, returning a wil::shared_cotaskmem_string * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A wil::shared_cotaskmem_string created from the string value read from the registry * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::wil::shared_cotaskmem_string get_value_string<::wil::shared_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value<::wil::shared_cotaskmem_string>(key, nullptr, value_name); } /** * @brief Reads a REG_EXPAND_SZ value, returning a wil::shared_cotaskmem_string * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A wil::shared_cotaskmem_string created from the string value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::wil::shared_cotaskmem_string get_value_expanded_string<::wil::shared_cotaskmem_string>( HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { ::wil::shared_cotaskmem_string value; const reg_view_details::reg_view regview{key}; regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); return value; } /** * @brief Reads a REG_EXPAND_SZ value, returning a wil::shared_cotaskmem_string * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A wil::shared_cotaskmem_string created from the string value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ template <> inline ::wil::shared_cotaskmem_string get_value_expanded_string<::wil::shared_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR value_name) { return wil::reg::get_value_expanded_string<::wil::shared_cotaskmem_string>(key, nullptr, value_name); } #endif // #if defined(__WIL_OBJBASE_H_STL) #endif // defined(__WIL_OBJBASE_H_) #if defined(_VECTOR_) || defined(WIL_DOXYGEN) /** * @brief Reads a registry value of the specified type, returning a std::vector * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @param type The registry type for the specified registry value to read from - see RegGetValueW * @return A std::vector containing the bytes of the specified registry value * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ inline ::std::vector get_value_binary(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t type) { ::std::vector return_value{}; const reg_view_details::reg_view regview{key}; regview.get_value(subkey, value_name, return_value, type); return return_value; } /** * @brief Reads a registry value of the specified type, returning a std::vector * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @param type The registry type for the specified registry value to read from - see RegGetValueW * @return A std::vector containing the bytes of the specified registry value * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found */ inline ::std::vector get_value_binary(HKEY key, _In_opt_ PCWSTR value_name, uint32_t type) { return ::wil::reg::get_value_binary(key, nullptr, value_name, type); } #endif // #if defined(_VECTOR_) #if (defined(_VECTOR_) && defined(_STRING_)) || defined(WIL_DOXYGEN) /** * @brief Reads a REG_MULTI_SZ value, returning a std::vector * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A vector of strings read from the REG_MULTI_SZ. Note: embedded nulls will be read as empty strings. See remarks. * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found * * @remark Note that will return empty strings for embedded nulls - it won't stop at the first double-null character * e.g. a REG_MULTI_SZ of L"string1\0\0string2\0\0string3\0\0" * returns a vector of size 5: L"string1", empty-string, L"string2", empty-string, L"string3" */ template <> inline ::std::vector<::std::wstring> get_value<::std::vector<::std::wstring>>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { ::std::vector<::std::wstring> return_value; ::std::vector rawData{::wil::reg::get_value_binary(key, subkey, value_name, REG_MULTI_SZ)}; if (!rawData.empty()) { auto* const begin = reinterpret_cast(rawData.data()); auto* const end = begin + rawData.size() / sizeof(wchar_t); return_value = ::wil::reg::reg_view_details::get_wstring_vector_from_multistring(begin, end); } return return_value; } /** * @brief Reads a REG_MULTI_SZ value, returning a std::vector * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A vector of strings read from the REG_MULTI_SZ. Note: embedded nulls will be read as empty strings. See remarks. * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found * * @remark Note that will return empty strings for embedded nulls - it won't stop at the first double-null character * e.g. a REG_MULTI_SZ of L"string1\0\0string2\0\0string3\0\0" * returns a vector of size 5: L"string1", empty-string, L"string2", empty-string, L"string3" */ template <> inline ::std::vector<::std::wstring> get_value<::std::vector<::std::wstring>>(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value<::std::vector<::std::wstring>>(key, nullptr, value_name); } /** * @brief Reads a REG_MULTI_SZ value, returning a std::vector * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A vector of strings read from the REG_MULTI_SZ. Note: embedded nulls will be read as empty strings. See remarks. * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found * * @remark Note that will return empty strings for embedded nulls - it won't stop at the first double-null character * e.g. a REG_MULTI_SZ of L"string1\0\0string2\0\0string3\0\0" * returns a vector of size 5: L"string1", empty-string, L"string2", empty-string, L"string3" */ inline ::std::vector<::std::wstring> get_value_multistring(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value<::std::vector<::std::wstring>>(key, subkey, value_name); } /** * @brief Reads a REG_MULTI_SZ value, returning a std::vector * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return A vector of strings read from the REG_MULTI_SZ. Note: embedded nulls will be read as empty strings. See remarks. * @exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found * * @remark Note that will return empty strings for embedded nulls - it won't stop at the first double-null character * e.g. a REG_MULTI_SZ of L"string1\0\0string2\0\0string3\0\0" * returns a vector of size 5: L"string1", empty-string, L"string2", empty-string, L"string3" */ inline ::std::vector<::std::wstring> get_value_multistring(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::get_value<::std::vector<::std::wstring>>(key, nullptr, value_name); } #endif // #if defined(_VECTOR_) && defined(_STRING_) #if (defined(_OPTIONAL_) && defined(__cpp_lib_optional)) || defined(WIL_DOXYGEN) // // template // void try_get_value(...) // // - Reads a value under a specified key and subkey, deducing registry type from the type parameter T. // - throws a std::exception on failure (including wil::ResultException), except if the registry value was not found // returns a std::nullopt if the registry value is not found // // Examples using the returned std::optional // - Caller should ensure the code handles a possible std::exception that will be thrown on all errors except value not found // // std::optional opt_dword_value = wil::reg::try_get_value(key, L"dword_value_name"); // if (opt_dword_value.has_value()) // { // // opt_dword_value.value() returns the uint32_t read from the registry // } // else // { // // the registry value did not exist // } // // if the caller wants to apply a default value of 0, they can call value_or() // uint32_t opt_dword_value = wil::reg::try_get_value(key, L"dword_value_name").value_or(0); // // Examples using the returned std::optional // std::optional opt_string_value = wil::reg::try_get_value_string(key, L"string_value_name"); // if (opt_string_value.has_value()) // { // // opt_string_value.value() returns the std::wstring read from the registry // // the below avoids copying the std::wstring as value() here returns a std::wstring& // PCWSTR string_value = opt_string_value.value().c_str(); // } // else // { // // the registry value did not exist // } // // // if the caller wants to apply a default value of L"default", they can call value_or() // // note that std::optional only attempts to construct a std::wstring for L"default" if the std::optional is empty (std::nullopt) // // thus only allocating a new std::wstring for the default value when it's needed // std::optional opt_string_value = wil::reg::try_get_value_string(key, L"string_value_name").value_or(L"default"); // // Examples of usage: // std::optional opt_dword_value = wil::reg::try_get_value(key, L"subkey", L"dword_value_name"); // std::optional opt_qword_value = wil::reg::try_get_value(key, L"subkey", L"qword_value_name); // std::optional opt_string_value = wil::reg::try_get_value(key, L"subkey", L"string_value_name"); // // A subkey is not required if the key is opened where this should write the value; e.g. // std::optional opt_dword_value = wil::reg::try_get_value(key, L"dword_value_name"); // std::optional opt_qword_value = wil::reg::try_get_value(key, L"qword_value_name); // std::optional opt_string_value = wil::reg::try_get_value(key, L"string_value_name"); // // The template type does not need to be specified if using functions written for a targeted type; e.g. // std::optional opt_dword_value = wil::reg::try_get_value_dword(key, L"dword_value_name"); // std::optional opt_qword_value = wil::reg::try_get_value_qword(key, L"qword_value_name"); // std::optional opt_string_value = wil::reg::try_get_value_string(key, L"string_value_name"); // // Values with REG_EXPAND_SZ can be read into each of the string types; e.g.: // std::optional opt_expanded_string_value = wil::reg::try_get_value_expanded_string(key, L"string_value_name_with_environment_variables"); // // Values can be read directly into a vector of bytes - the registry type must be specified; e.g.: // std::optional> opt_data = wil::reg::try_get_value_binary(key, L"binary_value_name", REG_BINARY); // // Multi-string values can be read into a std::vector; e.g.: // std::optional<::std::vector<::std::wstring>> try_get_value_multistring(key, L"multi_string_value_name"); // See the definition of try_get_value_multistring before for usage guidance // // Reading REG_SZ and REG_EXPAND_SZ types are done through the below templated try_get_value_string and try_get_value_expanded_string functions // Where the template type is the type to receive the string value // The default template type is std::wstring, available if the caller has included the STL header // // Reading a bstr is returned in a std::optional - because wil::unique_bstr cannot be copied and thus is difficult to work with a std::optional // std::optional shared_value { wil::reg::try_get_value_string<::wil::shared_bstr>(key, L"string_value_name") }; // // Reading a cotaskmem string is returned in a std::optional - because wil::unique_cotaskmem_string cannot be copied and thus is difficult to work with a std::optional // std::optional opt_shared_value { wil::reg::try_get_value_string(key, L"string_value_name") }; // // Blocking try_get_value_string template types that are not already specialized - this gives a much friendlier compiler error message template ::std::optional try_get_value_string(HKEY /*key*/, _In_opt_ PCWSTR /*subkey*/, _In_opt_ PCWSTR /*value_name*/) { static_assert(sizeof(T) != sizeof(T), "Unsupported type for try_get_value_string"); } template ::std::optional try_get_value_string(HKEY /*key*/, _In_opt_ PCWSTR /*value_name*/) { static_assert(sizeof(T) != sizeof(T), "Unsupported type for try_get_value_string"); } template ::std::optional try_get_value_expanded_string(HKEY /*key*/, _In_opt_ PCWSTR /*subkey*/, _In_opt_ PCWSTR /*value_name*/) { static_assert(sizeof(T) != sizeof(T), "Unsupported type for try_get_value_expanded_string"); } template ::std::optional try_get_value_expanded_string(HKEY /*key*/, _In_opt_ PCWSTR /*value_name*/) { static_assert(sizeof(T) != sizeof(T), "Unsupported type for try_get_value_expanded_string"); } /** * @brief Attempts to read a value under a specified key and subkey, returning in a std::optional, deducing registry type from * the type parameter T. * @tparam T The type to read, which will be placed into a std::optional (the registry value type is deduced from T) * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value (of type T) read from the registry value, in a std::optional. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ template ::std::optional try_get_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { #if defined(__WIL_OLEAUTO_H_) // not allowing unique types with try_get_value: wil::unique_bstr cannot be copied and thus is difficult to work with a std::optional static_assert(!wistd::is_same_v, "try_get with wil::unique_bstr is disabled"); #endif // #if defined(__WIL_OLEAUTO_H_) #if defined(__WIL_OBJBASE_H_) // not allowing unique types with try_get_value: wil::unique_cotaskmem_string cannot be copied and thus is difficult to work with a std::optional static_assert(!wistd::is_same_v, "try_get with wil::unique_cotaskmem_string is disabled"); #endif // #if defined(__WIL_OBJBASE_H_) const reg_view_details::reg_view regview{key}; return regview.try_get_value(subkey, value_name); } /** * @brief Attempts to read a value under a specified key, returning the value in a std::optional, deducing registry type from * the type parameter T. * @tparam T The type to read, which will be placed into a std::optional (the registry value type is deduced from T) * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value (of type T) read from the registry value, in a std::optional. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ template ::std::optional try_get_value(HKEY key, _In_opt_ PCWSTR value_name) { #if defined(__WIL_OLEAUTO_H_) // not allowing unique types with try_get_value: wil::unique_bstr cannot be copied and thus is difficult to work with a std::optional static_assert(!wistd::is_same_v, "try_get with wil::unique_bstr is disabled"); #endif // #if defined(__WIL_OLEAUTO_H_) #if defined(__WIL_OBJBASE_H_) // not allowing unique types with try_get_value: wil::unique_cotaskmem_string cannot be copied and thus is difficult to work with a std::optional static_assert(!wistd::is_same_v, "try_get with wil::unique_cotaskmem_string is disabled"); #endif // #if defined(__WIL_OBJBASE_H_) return ::wil::reg::try_get_value(key, nullptr, value_name); } /** * @brief Attempts to read a REG_DWORD value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value, in a std::optional. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ inline ::std::optional try_get_value_dword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { return ::wil::reg::try_get_value(key, subkey, value_name); } /** * @brief Attempts to read a REG_DWORD value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value, in a std::optional. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ inline ::std::optional try_get_value_dword(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::try_get_value(key, nullptr, value_name); } /** * @brief Attempts to read a REG_QWORD value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value, in a std::optional. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ inline ::std::optional try_get_value_qword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { return ::wil::reg::try_get_value(key, subkey, value_name); } /** * @brief Attempts to read a REG_QWORD value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value, in a std::optional. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ inline ::std::optional try_get_value_qword(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::try_get_value(key, nullptr, value_name); } #if defined(_VECTOR_) || defined(WIL_DOXYGEN) /** * @brief Attempts to read a value under a specified key requiring the specified type, returning the raw bytes in a * std::optional * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @param type The registry type for the specified registry value to read from - see RegGetValueW * @return The raw bytes read from the registry value stored in a std::optional>. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ inline ::std::optional<::std::vector> try_get_value_binary(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t type) { const reg_view_details::reg_view regview{key}; return regview.try_get_value<::std::vector>(subkey, value_name, type); } /** * @brief Attempts to read a value under a specified key requiring the specified type, returning the raw bytes in a * std::optional * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @param type The registry type for the specified registry value to read from - see RegGetValueW * @return The raw bytes read from the registry value stored in a std::optional>. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ inline ::std::optional<::std::vector> try_get_value_binary(HKEY key, _In_opt_ PCWSTR value_name, uint32_t type) { return ::wil::reg::try_get_value_binary(key, nullptr, value_name, type); } #endif // #if defined(_VECTOR_) #if defined(_STRING_) || defined(WIL_DOXYGEN) /** * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value, in a std::optional. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ inline ::std::optional<::std::wstring> try_get_value_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { const reg_view_details::reg_view regview{key}; return regview.try_get_value<::std::wstring>(subkey, value_name); } /** * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value, in a std::optional. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ inline ::std::optional<::std::wstring> try_get_value_string(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::try_get_value_string(key, nullptr, value_name); } /** * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value, in a std::optional. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ template <> inline ::std::optional<::std::wstring> try_get_value_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { return ::wil::reg::try_get_value_string(key, subkey, value_name); } /** * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value, in a std::optional. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ template <> inline ::std::optional<::std::wstring> try_get_value_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::try_get_value_string(key, nullptr, value_name); } /** * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value of the template type std::optional, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ inline ::std::optional<::std::wstring> try_get_value_expanded_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { const reg_view_details::reg_view regview{key}; return regview.try_get_value<::std::wstring>(subkey, value_name, REG_EXPAND_SZ); } /** * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value of the template type std::optional, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ inline ::std::optional<::std::wstring> try_get_value_expanded_string(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::try_get_value_expanded_string(key, nullptr, value_name); } /** * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value of the template type std::optional, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ template <> inline ::std::optional<::std::wstring> try_get_value_expanded_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { return ::wil::reg::try_get_value_expanded_string(key, subkey, value_name); } /** * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value of the template type std::optional, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ template <> inline ::std::optional<::std::wstring> try_get_value_expanded_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::try_get_value_expanded_string(key, nullptr, value_name); } #endif // #if defined(_STRING_) #if defined(__WIL_OLEAUTO_H_STL) || defined(WIL_DOXYGEN) /** * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value of the template type std::optional. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ template <> inline ::std::optional<::wil::shared_bstr> try_get_value_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { const reg_view_details::reg_view regview{key}; return regview.try_get_value<::wil::shared_bstr>(subkey, value_name); } /** * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value of the template type std::optional. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ template <> inline ::std::optional<::wil::shared_bstr> try_get_value_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::try_get_value_string<::wil::shared_bstr>(key, nullptr, value_name); } /** * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value of the template type std::optional, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ template <> inline ::std::optional<::wil::shared_bstr> try_get_value_expanded_string<::wil::shared_bstr>( HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { const reg_view_details::reg_view regview{key}; return regview.try_get_value<::wil::shared_bstr>(subkey, value_name, REG_EXPAND_SZ); } /** * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value of the template type std::optional, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ template <> inline ::std::optional<::wil::shared_bstr> try_get_value_expanded_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::try_get_value_expanded_string<::wil::shared_bstr>(key, nullptr, value_name); } #endif // #if defined(__WIL_OLEAUTO_H_STL) #if defined(__WIL_OBJBASE_H_STL) || defined(WIL_DOXYGEN) /** * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value of the template type std::optional. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ template <> inline ::std::optional<::wil::shared_cotaskmem_string> try_get_value_string<::wil::shared_cotaskmem_string>( HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { const reg_view_details::reg_view regview{key}; return regview.try_get_value<::wil::shared_cotaskmem_string>(subkey, value_name); } /** * @brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value of the template type std::optional * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ template <> inline ::std::optional<::wil::shared_cotaskmem_string> try_get_value_string<::wil::shared_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::try_get_value_string<::wil::shared_cotaskmem_string>(key, nullptr, value_name); } /** * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value of the template type std::optional<:wil::shared_cotaskmem_string>, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ template <> inline ::std::optional<::wil::shared_cotaskmem_string> try_get_value_expanded_string<::wil::shared_cotaskmem_string>( HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { const reg_view_details::reg_view regview{key}; return regview.try_get_value<::wil::shared_cotaskmem_string>(subkey, value_name, REG_EXPAND_SZ); } /** * @brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value of the template type std::optional, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ template <> inline ::std::optional<::wil::shared_cotaskmem_string> try_get_value_expanded_string<::wil::shared_cotaskmem_string>( HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::try_get_value_expanded_string<::wil::shared_cotaskmem_string>(key, nullptr, value_name); } #endif // defined(__WIL_OBJBASE_H_STL) #if (defined(_VECTOR_) && defined(_STRING_)) || defined(WIL_DOXYGEN) /** * @brief Attempts to read a REG_MULTI_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value marshaled to a std::optional>. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ template <> inline ::std::optional<::std::vector<::std::wstring>> try_get_value<::std::vector<::std::wstring>>( HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { ::std::vector<::std::wstring> value; const auto hr = ::wil::ResultFromException([&] { value = ::wil::reg::get_value_multistring(key, subkey, value_name); }); if (SUCCEEDED(hr)) { return value; } if (!::wil::reg::is_registry_not_found(hr)) { THROW_HR(HRESULT_FROM_WIN32(hr)); } return ::std::nullopt; } /** * @brief Attempts to read a REG_MULTI_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value marshaled to a std::optional>. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ template <> inline ::std::optional<::std::vector<::std::wstring>> try_get_value<::std::vector<::std::wstring>>(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::try_get_value<::std::vector<::std::wstring>>(key, nullptr, value_name); } /** * @brief Attempts to read a REG_MULTI_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value marshaled to a std::optional>. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ inline ::std::optional<::std::vector<::std::wstring>> try_get_value_multistring(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) { return ::wil::reg::try_get_value<::std::vector<::std::wstring>>(key, subkey, value_name); } /** * @brief Attempts to read a REG_MULTI_SZ value under a specified key, returning the value in a std::optional * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be updated. * Can be nullptr to read from the unnamed default registry value. * @return The value read from the registry value marshaled to a std::optional>. * Returns std::nullopt if the value does not exist. * @exception std::exception (including wil::ResultException) will be thrown on failures except value not found */ inline ::std::optional<::std::vector<::std::wstring>> try_get_value_multistring(HKEY key, _In_opt_ PCWSTR value_name) { return ::wil::reg::try_get_value<::std::vector<::std::wstring>>(key, nullptr, value_name); } #endif // #if defined (_VECTOR_) && defined (_STRING_) #endif // #if defined (_OPTIONAL_) && defined(__cpp_lib_optional) #endif // #if defined(WIL_ENABLE_EXCEPTIONS) // // template // HRESULT get_value_nothrow(...) // // - Reads a value from under a specified key // - The required type of registry value being read from is determined by the template type T // - Returns an HRESULT error code indicating success or failure (does not throw C++ exceptions) // // Examples of usage (the template type does not need to be explicitly specified) // uint32_t dword_value{}; // hr = wil::reg::get_value_nothrow(key, L"subkey", L"dword_value_name", &dword_value); // reads a REG_DWORD // uint64_t qword_value{}; // hr = wil::reg::get_value_nothrow(key, L"subkey", L"qword_value_name", &qword_value); // reads a REG_QWORD // wil::unique_bstr string_value{}; // hr = wil::reg::get_value_nothrow(key, L"subkey", L"string_value_name", string_value); // reads a REG_SZ // // A subkey is not required if the key is opened where this should write the value: // hr = wil::reg::get_value_nothrow(key, L"dword_value_name", &dword_value); // reads a REG_DWORD // hr = wil::reg::get_value_nothrow(key, L"qword_value_name", &qword_value); // reads a REG_QWORD // hr = wil::reg::get_value_nothrow(key, L"string_value_name", string_value); // reads a REG_SZ // // Can also specify the registry type in the function name: // hr = wil::reg::get_value_dword_nothrow(key, L"dword_value_name", &dword_value); // reads a REG_DWORD // hr = wil::reg::get_value_qword_nothrow(key, L"qword_value_name", &qword_value); // reads a REG_QWORD // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", string_value); // reads a REG_SZ // // Example storing directly into a WCHAR array - note will return the required number of bytes if the supplied array is too small // WCHAR string_value[100]{}; // uint32_t requiredBytes{}; // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", string_value, &requiredBytes); // // Example of usage writing a REG_MULTI_SZ // wil::unique_cotaskmem_array_ptr string_values{}; // hr = wil::reg::get_value_multistring_nothrow(key, L"multi_string_value_name", string_values); // // Values can be written directly from a vector of bytes - the registry type must be specified; e.g.: // wil::unique_cotaskmem_array_ptr raw_value{}; // hr = wil::reg::get_value_binary_nothrow(key, L"binary_value_name", REG_BINARY, raw_value); // // Reading REG_SZ and REG_EXPAND_SZ types are done through the below templated get_value_string_nothrow and get_value_expanded_string_nothrow functions // Where the template type is the type to receive the string value // The default template type is std::wstring, available if the caller has included the STL header // // Example storing a string in a wil::unique_bstr, wil::shared_bstr, wil::unique_cotaskmem_string, or wil::shared_cotaskmem_string /// - These string types are passed by reference, not by pointer, because the wil types overload the & operator // // wil::unique_bstr bstr_value{}; // hr = wil::reg::get_value_nothrow(key, L"string_value_name", bstr_value); // // or can specify explicitly reading a string into a wil::unique_bstr type // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", bstr_value); // // wil::shared_bstr shared_bstr_value{}; // hr = wil::reg::get_value_nothrow(key, L"string_value_name", shared_bstr_value); // // or can specify explicitly reading a string into a wil::shared_bstr type // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", shared_bstr_value); // // wil::unique_cotaskmem_string string_value{}; // hr = wil::reg::get_value_nothrow(key, L"string_value_name", string_value); // // or can specify explicitly reading a string into a wil::unique_cotaskmem_string type // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", string_value); // // wil::shared_cotaskmem_string shared_string_value{}; // hr = wil::reg::get_value_nothrow(key, L"string_value_name", shared_string_value); // // or can specify explicitly reading a string into a wil::shared_cotaskmem_string type // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", shared_string_value); // /** * @brief Reads a value under a specified key, the registry type based off the templated type passed as data * @tparam T The type of the data being set (the registry value type is deduced from T). * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A pointer-to-T receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ template >* = nullptr> HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, _Out_ T* return_value) WI_NOEXCEPT { const reg_view_details::reg_view_nothrow regview{key}; return regview.get_value(subkey, value_name, *return_value); } /** * @brief Reads a value under a specified key, the registry type based off the templated type passed as data * @tparam T The type of the data being set (the registry value type is deduced from T). * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A pointer-to-T receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ template >* = nullptr> HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, _Out_ T* return_value) WI_NOEXCEPT { return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); } /** * @brief Reads a REG_SZ value under a specified key * @tparam Length The length of the WCHAR array passed as an OUT parameter * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A WCHAR array receiving the value read from the registry. * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination * @param[out] requiredBytes An optional pointer to a unsigned 32-bit value to receive the required bytes of the string in the * registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ template || wistd::is_same_v>* = nullptr> HRESULT get_value_string_nothrow( HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length], _Out_opt_ DwordType* requiredBytes) WI_NOEXCEPT { const reg_view_details::reg_view_nothrow regview{key}; return regview.get_value_char_array(subkey, value_name, return_value, REG_SZ, requiredBytes); } /** * @brief Reads a REG_SZ value under a specified key * @tparam Length The length of the WCHAR array passed as an OUT parameter * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A WCHAR array receiving the value read from the registry. * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination * @param[out] requiredBytes An optional pointer to an unsigned 32-bit value to receive the required bytes of the string to be * read * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ template || wistd::is_same_v>* = nullptr> HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length], _Out_opt_ DwordType* requiredBytes) WI_NOEXCEPT { return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value, requiredBytes); } /** * @brief Reads a REG_SZ value under a specified key * @tparam Length The length of the WCHAR array passed as an OUT parameter * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A WCHAR array receiving the value read from the registry. * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ template HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length]) WI_NOEXCEPT { constexpr uint32_t* null_out_param = nullptr; const reg_view_details::reg_view_nothrow regview{key}; return regview.get_value_char_array(subkey, value_name, return_value, REG_SZ, null_out_param); } /** * @brief Reads a REG_SZ value under a specified key * @tparam Length The length of the WCHAR array passed as an OUT parameter * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A WCHAR array receiving the value read from the registry. * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ template HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length]) WI_NOEXCEPT { return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value); } /** * @brief Reads a REG_SZ value under a specified key * @tparam Length The length of the WCHAR array passed as an OUT parameter * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A WCHAR array receiving the value read from the registry. * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ template HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length]) WI_NOEXCEPT { return ::wil::reg::get_value_string_nothrow(key, subkey, value_name, return_value); } /** * @brief Reads a REG_SZ value under a specified key * @tparam Length The length of the WCHAR array passed as an OUT parameter * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A WCHAR array receiving the value read from the registry. * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ template HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length]) WI_NOEXCEPT { return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value); } /** * @brief Reads a REG_DWORD value under a specified key * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A pointer to an unsigned 32-bit value receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ template || wistd::is_same_v>* = nullptr> HRESULT get_value_dword_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, _Out_ DwordType* return_value) WI_NOEXCEPT { return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); } /** * @brief Reads a REG_DWORD value under a specified key * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A pointer to an unsigned 32-bit value receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ template || wistd::is_same_v>* = nullptr> HRESULT get_value_dword_nothrow(HKEY key, _In_opt_ PCWSTR value_name, _Out_ DwordType* return_value) WI_NOEXCEPT { return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); } /** * @brief Reads a REG_QWORD value under a specified key * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A uint64_t receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ template || wistd::is_same_v>* = nullptr> HRESULT get_value_qword_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, _Out_ QwordType* return_value) WI_NOEXCEPT { return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); } /** * @brief Reads a REG_QWORD value under a specified key * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A uint64_t receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ template || wistd::is_same_v>* = nullptr> HRESULT get_value_qword_nothrow(HKEY key, _In_opt_ PCWSTR value_name, _Out_ QwordType* return_value) WI_NOEXCEPT { return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); } #if defined(__WIL_OLEAUTO_H_) || defined(WIL_DOXYGEN) /** * @brief Reads a REG_SZ value under a specified key * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::unique_bstr receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_bstr& return_value) WI_NOEXCEPT { const reg_view_details::reg_view_nothrow regview{key}; return regview.get_value(subkey, value_name, return_value); } /** * @brief Reads a REG_SZ value under a specified key * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::unique_bstr receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_bstr& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); } /** * @brief Reads a REG_SZ value under a specified key * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::unique_bstr receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_bstr& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value.addressof()); } /** * @brief Reads a REG_SZ value under a specified key * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::unique_bstr receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_bstr& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value); } #if defined(__WIL_OLEAUTO_H_STL) || defined(WIL_DOXYGEN) /** * @brief Reads a REG_SZ value under a specified key * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::shared_bstr receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::shared_bstr& return_value) WI_NOEXCEPT { const reg_view_details::reg_view_nothrow regview{key}; return regview.get_value(subkey, value_name, return_value); } /** * @brief Reads a REG_SZ value under a specified key * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::shared_bstr receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::shared_bstr& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); } /** * @brief Reads a REG_SZ value under a specified key * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::shared_bstr receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::shared_bstr& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value.addressof()); } /** * @brief Reads a REG_SZ value under a specified key * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::shared_bstr receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::shared_bstr& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value); } #endif // #if defined(__WIL_OLEAUTO_H_STL) #endif // #if defined(__WIL_OLEAUTO_H_) #if defined(__WIL_OBJBASE_H_) || defined(WIL_DOXYGEN) /** * @brief Reads a REG_SZ value under a specified key * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_string& return_value) WI_NOEXCEPT { return_value.reset(); const reg_view_details::reg_view_nothrow regview{key}; return regview.get_value(subkey, value_name, return_value); } /** * @brief Reads a REG_SZ value under a specified key * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_string& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); } /** * @brief Reads a REG_SZ value under a specified key * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_string_nothrow( HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_string& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); } /** * @brief Reads a REG_SZ value under a specified key * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_string& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); } #if defined(__WIL_OBJBASE_H_STL) || defined(WIL_DOXYGEN) /** * @brief Reads a REG_SZ value under a specified key * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::shared_cotaskmem_string& return_value) WI_NOEXCEPT { return_value.reset(); const reg_view_details::reg_view_nothrow regview{key}; return regview.get_value(subkey, value_name, return_value); } /** * @brief Reads a REG_SZ value under a specified key * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::shared_cotaskmem_string& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); } /** * @brief Reads a REG_SZ value under a specified key * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_string_nothrow( HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::shared_cotaskmem_string& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); } /** * @brief Reads a REG_SZ value under a specified key * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::shared_cotaskmem_string& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); } #endif // #if defined(__WIL_OBJBASE_H_STL) #endif // defined(__WIL_OBJBASE_H_) #if defined(__WIL_OBJBASE_H_) || defined(WIL_DOXYGEN) /** * @brief Reads the raw bytes from a registry value under a specified key of the specified type * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param type The registry type for the specified registry value to read from - see RegGetValueW * @param[out] return_value A ::wil::unique_cotaskmem_array_ptr receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_binary_nothrow( HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t type, ::wil::unique_cotaskmem_array_ptr& return_value) WI_NOEXCEPT { // zero the vector if it already had a buffer for (auto& byte_value : return_value) { byte_value = 0x00; } const reg_view_details::reg_view_nothrow regview{key}; RETURN_IF_FAILED(regview.get_value<::wil::unique_cotaskmem_array_ptr>(subkey, value_name, return_value, type)); return S_OK; } /** * @brief Reads the raw bytes from a registry value under a specified key of the specified type * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param type The registry type for the specified registry value to read from - see RegGetValueW * @param[out] return_value A ::wil::unique_cotaskmem_array_ptr receiving the value read from the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_binary_nothrow( HKEY key, _In_opt_ PCWSTR value_name, uint32_t type, ::wil::unique_cotaskmem_array_ptr& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_binary_nothrow(key, nullptr, value_name, type, return_value); } #endif // #if defined(__WIL_OBJBASE_H_) /** * @brief Reads a REG_EXPAND_SZ value under a specified key * @tparam Length The length of the WCHAR array passed as an OUT parameter * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A WCHAR array receiving the value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination * @param[out] requiredBytes An optional pointer to a uint32_t to receive the required bytes of the string to be read * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ template || wistd::is_same_v>* = nullptr> HRESULT get_value_expanded_string_nothrow( HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length], _Out_opt_ DwordType* requiredBytes) WI_NOEXCEPT { const reg_view_details::reg_view_nothrow regview{key}; return regview.get_value_char_array(subkey, value_name, return_value, REG_EXPAND_SZ, requiredBytes); } /** * @brief Reads a REG_EXPAND_SZ value under a specified key * @tparam Length The length of the WCHAR array passed as an OUT parameter * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A WCHAR array receiving the value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination * @param[out] requiredBytes An optional pointer to a uint32_t to receive the required bytes of the string to be read * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ template || wistd::is_same_v>* = nullptr> HRESULT get_value_expanded_string_nothrow( HKEY key, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length], _Out_opt_ DwordType* requiredBytes) WI_NOEXCEPT { return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value, requiredBytes); } /** * @brief Reads a REG_EXPAND_SZ value under a specified key * @tparam Length The length of the WCHAR array passed as an OUT parameter * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A WCHAR array receiving the value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ template HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length]) WI_NOEXCEPT { constexpr uint32_t* null_out_param = nullptr; const reg_view_details::reg_view_nothrow regview{key}; return regview.get_value_char_array(subkey, value_name, return_value, REG_EXPAND_SZ, null_out_param); } /** * @brief Reads a REG_EXPAND_SZ value under a specified key * @tparam Length The length of the WCHAR array passed as an OUT parameter * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A WCHAR array receiving the value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ template HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, WCHAR (&return_value)[Length]) WI_NOEXCEPT { return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); } #if defined(__WIL_OLEAUTO_H_) || defined(WIL_DOXYGEN) /** * @brief Reads a REG_EXPAND_SZ value under a specified key * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::unique_bstr receiving the value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_bstr& return_value) WI_NOEXCEPT { const reg_view_details::reg_view_nothrow regview{key}; return regview.get_value<::wil::unique_bstr>(subkey, value_name, return_value, REG_EXPAND_SZ); } /** * @brief Reads a REG_EXPAND_SZ value under a specified key * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::unique_bstr receiving the value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_bstr& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); } #if defined(__WIL_OLEAUTO_H_STL) || defined(WIL_DOXYGEN) /** * @brief Reads a REG_EXPAND_SZ value under a specified key * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::shared_bstr receiving the value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::shared_bstr& return_value) WI_NOEXCEPT { const reg_view_details::reg_view_nothrow regview{key}; return regview.get_value<::wil::shared_bstr>(subkey, value_name, return_value, REG_EXPAND_SZ); } /** * @brief Reads a REG_EXPAND_SZ value under a specified key * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::shared_bstr receiving the value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::shared_bstr& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); } #endif // #if defined(__WIL_OLEAUTO_H_STL) #endif // #if defined(__WIL_OLEAUTO_H_) #if defined(__WIL_OBJBASE_H_) || defined(WIL_DOXYGEN) /** * @brief Reads a REG_EXPAND_SZ value under a specified key * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_expanded_string_nothrow( HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_string& return_value) WI_NOEXCEPT { const reg_view_details::reg_view_nothrow regview{key}; return regview.get_value<::wil::unique_cotaskmem_string>(subkey, value_name, return_value, REG_EXPAND_SZ); } /** * @brief Reads a REG_EXPAND_SZ value under a specified key * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_string& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); } #if defined(__WIL_OBJBASE_H_STL) || defined(WIL_DOXYGEN) /** * @brief Reads a REG_EXPAND_SZ value under a specified key * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_expanded_string_nothrow( HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::shared_cotaskmem_string& return_value) WI_NOEXCEPT { const reg_view_details::reg_view_nothrow regview{key}; return regview.get_value<::wil::shared_cotaskmem_string>(subkey, value_name, return_value, REG_EXPAND_SZ); } /** * @brief Reads a REG_EXPAND_SZ value under a specified key * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry, * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::shared_cotaskmem_string& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); } #endif // #if defined(__WIL_OBJBASE_H_STL) #endif // defined(__WIL_OBJBASE_H_) #if defined(__WIL_OBJBASE_H_) || defined(WIL_DOXYGEN) /** * @brief Reads a REG_MULTI_SZ value under a specified key * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> receiving the value read from * the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_nothrow( HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string>& return_value) WI_NOEXCEPT { ::wil::unique_cotaskmem_array_ptr rawData; RETURN_IF_FAILED(::wil::reg::get_value_binary_nothrow(key, subkey, value_name, REG_MULTI_SZ, rawData)); if (!rawData.empty()) { auto* const begin = reinterpret_cast(rawData.data()); auto* const end = begin + rawData.size() / sizeof(wchar_t); ::wil::reg::reg_view_details::get_cotaskmemstring_array_from_multistring_nothrow(begin, end, return_value); } return S_OK; } /** * @brief Reads a REG_MULTI_SZ value under a specified key * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> receiving the value read from * the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_nothrow( HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string>& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); } /** * @brief Reads a REG_MULTI_SZ value under a specified key * @param key An open or well-known registry key * @param subkey The name of the subkey to append to `key`. * If `nullptr`, then `key` is used without modification. * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> receiving the value read from * the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_multistring_nothrow( HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string>& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); } /** * @brief Reads a REG_MULTI_SZ value under a specified key * @param key An open or well-known registry key * @param value_name The name of the registry value whose data is to be read. * Can be nullptr to read from the unnamed default registry value. * @param[out] return_value A ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> receiving the value read from * the registry * @return HRESULT error code indicating success or failure (does not throw C++ exceptions) */ inline HRESULT get_value_multistring_nothrow( HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string>& return_value) WI_NOEXCEPT { return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); } #endif // #if defined(__WIL_OBJBASE_H_) } // namespace reg // unique_registry_watcher/unique_registry_watcher_nothrow/unique_registry_watcher_failfast // These classes make it easy to execute a provided function when a // registry key changes (optionally recursively). Specify the key // either as a root key + path, or an open registry handle as wil::unique_hkey // or a raw HKEY value (that will be duplicated). // // Example use with exceptions base error handling: // auto watcher = wil::make_registry_watcher(HKEY_CURRENT_USER, L"Software\\MyApp", true, wil::RegistryChangeKind changeKind[] // { // if (changeKind == RegistryChangeKind::Delete) // { // watcher.reset(); // } // // invalidate cached registry data here // }); // // Example use with error code base error handling: // auto watcher = wil::make_registry_watcher_nothrow(HKEY_CURRENT_USER, L"Software\\MyApp", true, wil::RegistryChangeKind[] // { // // invalidate cached registry data here // }); // RETURN_IF_NULL_ALLOC(watcher); enum class RegistryChangeKind { Modify = 0, Delete = 1, }; /// @cond namespace details { struct registry_watcher_state { registry_watcher_state(unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) : m_callback(wistd::move(callback)), m_keyToWatch(wistd::move(keyToWatch)), m_isRecursive(isRecursive) { } wistd::function m_callback; unique_hkey m_keyToWatch; unique_event_nothrow m_eventHandle; // While not strictly needed since this is ref counted the thread pool wait // should be last to ensure that the other members are valid // when it is destructed as it will reference them. unique_threadpool_wait m_threadPoolWait; bool m_isRecursive; volatile long m_refCount = 1; srwlock m_lock; // Returns true if the ref-count can be increased from a non zero value, // false it was zero implying that the object is in or on the way to the destructor. // In this case ReleaseFromCallback() should not be called. bool TryAddRef() { return ::InterlockedIncrement(&m_refCount) > 1; } void Release() { auto lock = m_lock.lock_exclusive(); if (0 == ::InterlockedDecrement(&m_refCount)) { lock.reset(); // leave the lock before deleting it. delete this; } } void ReleaseFromCallback(bool rearm) { auto lock = m_lock.lock_exclusive(); if (0 == ::InterlockedDecrement(&m_refCount)) { // Destroy the thread pool wait now to avoid the wait that would occur in the // destructor. That wait would cause a deadlock since we are doing this from the callback. ::CloseThreadpoolWait(m_threadPoolWait.release()); lock.reset(); // leave the lock before deleting it. delete this; // Sleep(1); // Enable for testing to find use after free bugs. } else if (rearm) { ::SetThreadpoolWait(m_threadPoolWait.get(), m_eventHandle.get(), nullptr); } } }; inline void delete_registry_watcher_state(_In_opt_ registry_watcher_state* watcherStorage) { watcherStorage->Release(); } typedef resource_policy registry_watcher_state_resource_policy; } // namespace details /// @endcond template class registry_watcher_t : public storage_t { public: // forward all base class constructors... template explicit registry_watcher_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) { } // HRESULT or void error handling... typedef typename err_policy::result result; // Exception-based constructors registry_watcher_t(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function&& callback) { static_assert(wistd::is_same::value, "this constructor requires exceptions; use the create method"); create(rootKey, subKey, isRecursive, wistd::move(callback)); } registry_watcher_t(unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) { static_assert(wistd::is_same::value, "this constructor requires exceptions; use the create method"); create(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); } // Pass a root key, sub key pair or use an empty string to use rootKey as the key to watch. result create(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function&& callback) { // Most use will want to create the key, consider adding an option for open as a future design change. unique_hkey keyToWatch; HRESULT hr = HRESULT_FROM_WIN32(RegCreateKeyExW(rootKey, subKey, 0, nullptr, 0, KEY_NOTIFY, nullptr, &keyToWatch, nullptr)); if (FAILED(hr)) { return err_policy::HResult(hr); } return err_policy::HResult(create_common(wistd::move(keyToWatch), isRecursive, wistd::move(callback))); } result create(unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) { return err_policy::HResult(create_common(wistd::move(keyToWatch), isRecursive, wistd::move(callback))); } private: // Factored into a standalone function to support Clang which does not support conversion of stateless lambdas // to __stdcall static void __stdcall callback(PTP_CALLBACK_INSTANCE, void* context, TP_WAIT*, TP_WAIT_RESULT) { #ifndef __WIL_REGISTRY_CHANGE_CALLBACK_TEST #define __WIL_REGISTRY_CHANGE_CALLBACK_TEST #endif __WIL_REGISTRY_CHANGE_CALLBACK_TEST const auto watcherState = static_cast(context); if (watcherState->TryAddRef()) { // using auto reset event so don't need to manually reset. // failure here is a programming error. const LSTATUS error = RegNotifyChangeKeyValue( watcherState->m_keyToWatch.get(), watcherState->m_isRecursive, REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_THREAD_AGNOSTIC, watcherState->m_eventHandle.get(), TRUE); // Call the client before re-arming to ensure that multiple callbacks don't // run concurrently. switch (error) { case ERROR_SUCCESS: case ERROR_ACCESS_DENIED: // Normal modification: send RegistryChangeKind::Modify and re-arm. watcherState->m_callback(RegistryChangeKind::Modify); watcherState->ReleaseFromCallback(true); break; case ERROR_KEY_DELETED: // Key deleted, send RegistryChangeKind::Delete, do not re-arm. watcherState->m_callback(RegistryChangeKind::Delete); watcherState->ReleaseFromCallback(false); break; case ERROR_HANDLE_REVOKED: // Handle revoked. This can occur if the user session ends before // the watcher shuts-down. Disarm silently since there is generally no way to respond. watcherState->ReleaseFromCallback(false); break; default: FAIL_FAST_HR(HRESULT_FROM_WIN32(error)); } } } // This function exists to avoid template expansion of this code based on err_policy. HRESULT create_common(unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) { wistd::unique_ptr watcherState( new (std::nothrow) details::registry_watcher_state(wistd::move(keyToWatch), isRecursive, wistd::move(callback))); RETURN_IF_NULL_ALLOC(watcherState); RETURN_IF_FAILED(watcherState->m_eventHandle.create()); RETURN_IF_WIN32_ERROR(RegNotifyChangeKeyValue( watcherState->m_keyToWatch.get(), watcherState->m_isRecursive, REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_THREAD_AGNOSTIC, watcherState->m_eventHandle.get(), TRUE)); watcherState->m_threadPoolWait.reset(CreateThreadpoolWait(®istry_watcher_t::callback, watcherState.get(), nullptr)); RETURN_LAST_ERROR_IF(!watcherState->m_threadPoolWait); storage_t::reset(watcherState.release()); // no more failures after this, pass ownership SetThreadpoolWait(storage_t::get()->m_threadPoolWait.get(), storage_t::get()->m_eventHandle.get(), nullptr); return S_OK; } }; typedef unique_any_t, err_returncode_policy>> unique_registry_watcher_nothrow; typedef unique_any_t, err_failfast_policy>> unique_registry_watcher_failfast; inline unique_registry_watcher_nothrow make_registry_watcher_nothrow( HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function&& callback) WI_NOEXCEPT { unique_registry_watcher_nothrow watcher; watcher.create(rootKey, subKey, isRecursive, wistd::move(callback)); return watcher; // caller must test for success using if (watcher) } inline unique_registry_watcher_nothrow make_registry_watcher_nothrow( unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) WI_NOEXCEPT { unique_registry_watcher_nothrow watcher; watcher.create(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); return watcher; // caller must test for success using if (watcher) } inline unique_registry_watcher_failfast make_registry_watcher_failfast( HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function&& callback) { return unique_registry_watcher_failfast(rootKey, subKey, isRecursive, wistd::move(callback)); } inline unique_registry_watcher_failfast make_registry_watcher_failfast( unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) { return unique_registry_watcher_failfast(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); } #ifdef WIL_ENABLE_EXCEPTIONS typedef unique_any_t, err_exception_policy>> unique_registry_watcher; inline unique_registry_watcher make_registry_watcher( HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function&& callback) { return unique_registry_watcher(rootKey, subKey, isRecursive, wistd::move(callback)); } inline unique_registry_watcher make_registry_watcher(unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) { return unique_registry_watcher(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); } #endif // WIL_ENABLE_EXCEPTIONS } // namespace wil #endif