Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions include/wil/registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,66 @@ namespace reg
}
#endif // #define __WIL_WINREG_STL

/**
* @brief Opens a new HKEY to the HKEY_CURRENT_USER subtree for the user the current thread is impersonating - see
* RegOpenCurrentUser
* @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)
* @remark Unlike the HKEY_CURRENT_USER constant, this reflects the impersonated user (if any) rather than the user
* the process is running as.
*/
inline HRESULT open_current_user_key_nothrow(::wil::unique_hkey& hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) WI_NOEXCEPT
{
return HRESULT_FROM_WIN32(::RegOpenCurrentUser(reg_view_details::get_access_flags(access), hkey.put()));
}

#if defined(__WIL_WINREG_STL) || defined(WIL_DOXYGEN)
/**
* @brief Opens a new HKEY to the HKEY_CURRENT_USER subtree for the user the current thread is impersonating - see
* RegOpenCurrentUser
* @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_current_user_shared_key_nothrow(::wil::shared_hkey& hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) WI_NOEXCEPT
{
return HRESULT_FROM_WIN32(::RegOpenCurrentUser(reg_view_details::get_access_flags(access), hkey.put()));
}
#endif // #if defined(__WIL_WINREG_STL)

#if defined(WIL_ENABLE_EXCEPTIONS)
/**
* @brief Opens a new HKEY to the HKEY_CURRENT_USER subtree for the user the current thread is impersonating - see
* RegOpenCurrentUser
* @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_current_user_key(::wil::reg::key_access access = ::wil::reg::key_access::read)
{
::wil::unique_hkey return_value;
THROW_IF_FAILED(::wil::reg::open_current_user_key_nothrow(return_value, access));
return return_value;
}

#if defined(__WIL_WINREG_STL) || defined(WIL_DOXYGEN)
/**
* @brief Opens a new HKEY to the HKEY_CURRENT_USER subtree for the user the current thread is impersonating - see
* RegOpenCurrentUser
* @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_current_user_shared_key(::wil::reg::key_access access = ::wil::reg::key_access::read)
{
::wil::shared_hkey return_value;
THROW_IF_FAILED(::wil::reg::open_current_user_shared_key_nothrow(return_value, access));
return return_value;
}
#endif // #if defined(__WIL_WINREG_STL)
#endif // #if defined(WIL_ENABLE_EXCEPTIONS)

//
// wil::key_iterator and wil::value_iterator objects enable enumerating registry keys and values.
//
Expand Down
57 changes: 57 additions & 0 deletions tests/RegistryTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1328,6 +1328,63 @@ using ThrowingTypesToTest = std::tuple<DwordFns, GenericDwordFns, QwordFns, Gene
#endif // defined(WIL_ENABLE_EXCEPTIONS)
} // namespace

TEST_CASE("BasicRegistryTests::open_current_user", "[registry]")
{
const auto deleteHr = HRESULT_FROM_WIN32(::RegDeleteTreeW(HKEY_CURRENT_USER, testSubkey));
if (deleteHr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
{
REQUIRE_SUCCEEDED(deleteHr);
}

SECTION("open_current_user_key_nothrow: read/write through the current user hive")
{
wil::unique_hkey current_user;
REQUIRE_SUCCEEDED(wil::reg::open_current_user_key_nothrow(current_user, wil::reg::key_access::readwrite));
REQUIRE(current_user.get() != nullptr);

// a value written under the opened current-user key is visible via HKEY_CURRENT_USER
REQUIRE_SUCCEEDED(wil::reg::set_value_dword_nothrow(current_user.get(), testSubkey, dwordValueName, test_dword_two));

DWORD result{};
REQUIRE_SUCCEEDED(wil::reg::get_value_dword_nothrow(HKEY_CURRENT_USER, testSubkey, dwordValueName, &result));
REQUIRE(result == test_dword_two);
}

SECTION("open_current_user_key_nothrow: read-only access is honored")
{
// ensure the subkey exists, with a known value, via a writable handle first
wil::unique_hkey writable;
REQUIRE_SUCCEEDED(wil::reg::open_current_user_key_nothrow(writable, wil::reg::key_access::readwrite));
REQUIRE_SUCCEEDED(wil::reg::set_value_dword_nothrow(writable.get(), testSubkey, dwordValueName, test_dword_two));

// open the current-user hive read-only and read the value back through it
wil::unique_hkey current_user;
REQUIRE_SUCCEEDED(wil::reg::open_current_user_key_nothrow(current_user, wil::reg::key_access::read));
REQUIRE(current_user.get() != nullptr);

// open the subkey read-only through the read-only current-user handle
wil::unique_hkey read_only_key;
REQUIRE_SUCCEEDED(wil::reg::open_unique_key_nothrow(current_user.get(), testSubkey, read_only_key, wil::reg::key_access::read));
DWORD result{};
REQUIRE_SUCCEEDED(wil::reg::get_value_dword_nothrow(read_only_key.get(), dwordValueName, &result));
REQUIRE(result == test_dword_two);

// writing directly through the read-only handle must be denied
REQUIRE(wil::reg::set_value_dword_nothrow(read_only_key.get(), dwordValueName, test_dword_three) == E_ACCESSDENIED);
}

#ifdef WIL_ENABLE_EXCEPTIONS
SECTION("open_current_user_key: throwing variant")
{
const wil::unique_hkey current_user{wil::reg::open_current_user_key(wil::reg::key_access::readwrite)};
REQUIRE(current_user.get() != nullptr);

wil::reg::set_value_dword(current_user.get(), testSubkey, dwordValueName, test_dword_three);
REQUIRE(wil::reg::get_value_dword(HKEY_CURRENT_USER, testSubkey, dwordValueName) == test_dword_three);
}
#endif
}

TEMPLATE_LIST_TEST_CASE("BasicRegistryTests::simple types typed nothrow gets/sets", "[registry]", NoThrowTypesToTest)
{
const auto deleteHr = HRESULT_FROM_WIN32(::RegDeleteTreeW(HKEY_CURRENT_USER, testSubkey));
Expand Down
Loading