From 93f9cb7c0ef6bba4ef251b29899d8b80b0abe636 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Fri, 24 Aug 2018 17:32:04 +1000 Subject: [PATCH] win32/registry: add subkey iteration helpers --- win32/registry.cpp | 180 +++++++++++++++++++++++++++++++++++++++++++++ win32/registry.hpp | 28 +++++++ 2 files changed, 208 insertions(+) diff --git a/win32/registry.cpp b/win32/registry.cpp index 458895fb..235fcfd2 100644 --- a/win32/registry.cpp +++ b/win32/registry.cpp @@ -40,6 +40,13 @@ template <> constexpr DWORD restrict_to_id (void) { return RRF_RT_R /////////////////////////////////////////////////////////////////////////////// +key::key (key const &parent, char const *path, REGSAM rights) +{ + auto err = RegOpenKeyEx (parent.m_handle, path, 0, rights, &m_handle); + win32::error::try_code (err); +} + +//----------------------------------------------------------------------------- key::key (HKEY root, const char *child, REGSAM rights) { auto err = RegOpenKeyEx (root, child, 0, rights, &m_handle); @@ -55,6 +62,146 @@ key::~key () } +/////////////////////////////////////////////////////////////////////////////// +cruft::view +key::subkeys (void) +{ + DWORD size; + + auto err = RegQueryInfoKey ( + m_handle, + nullptr, + nullptr, + nullptr, + &size, + nullptr, // longest subkey size + nullptr, // longest class string + nullptr, // number of values for this key + nullptr, // longest value name + nullptr, // longest value data + nullptr, // security descriptor + nullptr // last write time + ); + error::try_code (err); + + return { + child_iterator (*this), + child_iterator (*this, size) + }; +} + + +//----------------------------------------------------------------------------- +key::child_iterator::child_iterator (key const &_parent) + : child_iterator (_parent, 0) +{ ; } + + +//----------------------------------------------------------------------------- +key::child_iterator::child_iterator (key const &_parent, int _index) + : m_parent (_parent) + , m_index (_index) +{ ; } + + +//----------------------------------------------------------------------------- +key +key::child_iterator::operator* (void) const +{ + DWORD name_size = strlen ("{00000000-0000-0000-0000-000000000000}"); + std::string name (name_size, '\0'); + + while (1) { + auto const err = RegEnumKeyEx( + m_parent.m_handle, + m_index, + name.data(), &name_size, + nullptr, + nullptr, nullptr, + nullptr + ); + + switch (err) { + case ERROR_SUCCESS: + name.resize (name_size); + return key (m_parent, name.c_str ()); + + case ERROR_MORE_DATA: + name_size *= 2; + name.resize (name_size); + continue; + + default: + error::throw_code (err); + } + } + + unreachable (); +} + + +//----------------------------------------------------------------------------- +key::child_iterator& +key::child_iterator::operator++ () +{ + ++m_index; + return *this; +} + + +//----------------------------------------------------------------------------- +bool +key::child_iterator::operator== (child_iterator const &rhs) +{ + CHECK_EQ (&m_parent, &rhs.m_parent); + return m_index == rhs.m_index; +} + + +//----------------------------------------------------------------------------- +bool +key::child_iterator::operator!= (child_iterator const &rhs) +{ + return !(*this == rhs); +} + + +/////////////////////////////////////////////////////////////////////////////// +std::string +key::name (void) const +{ + // allocate an initial buffer large enough to contain a GUID given that + // strings like these are pretty common. + DWORD size = strlen ("{00000000-0000-0000-0000-000000000000}"); + std::string value (size, '\0'); + + // keep attempting to read the name of the key. if it fails then we double + // the size of the string and try again. + while (1) { + auto res = RegQueryInfoKey ( + m_handle, + value.data (), &size, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr + ); + + switch (res) { + case ERROR_SUCCESS: + value.resize (size); + return value; + + case ERROR_MORE_DATA: + size *= 2; + continue; + + default: + win32::error::throw_code (res); + } + } + + unreachable (); +} + + /////////////////////////////////////////////////////////////////////////////// template T @@ -71,6 +218,39 @@ key::data (const char *name) const } +//----------------------------------------------------------------------------- +template <> +std::string +key::data (char const *name) const +{ + DWORD size = strlen ("{00000000-0000-0000-0000-000000000000}"); + std::string value (size, '\0'); + + while (1) { + DWORD type; + auto const err = RegGetValue( + m_handle, nullptr, name, + restrict_to_id(), &type, + value.data(), &size + ); + + switch (err) { + case ERROR_SUCCESS: + value.resize (size); + return value; + + case ERROR_MORE_DATA: + size *= 2; + value.resize (size); + continue; + + default: + error::throw_code (err); + } + } +} + + //----------------------------------------------------------------------------- std::set key::values (void) const diff --git a/win32/registry.hpp b/win32/registry.hpp index a9481c00..10d47f57 100644 --- a/win32/registry.hpp +++ b/win32/registry.hpp @@ -9,6 +9,8 @@ #ifndef __UTIL_WIN32_REGISTRY_HPP #define __UTIL_WIN32_REGISTRY_HPP +#include "../view.hpp" + #include #include @@ -17,9 +19,35 @@ namespace cruft::win32 { class key { public: + key (key const &root, const char *child, REGSAM rights = KEY_READ); key (HKEY root, const char *child, REGSAM rights = KEY_READ); ~key (); + class child_iterator { + public: + using value_type = key; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + using iterator_category = std::input_iterator_tag; + + child_iterator (key const &_parent); + child_iterator (key const &_parent, int _index); + + key operator* (void) const; + child_iterator& operator++ (); + bool operator== (child_iterator const&); + bool operator!= (child_iterator const&); + + private: + key const &m_parent; + int m_index; + }; + + cruft::view subkeys (void); + + std::string name (void) const; + template T data (const char *name = nullptr) const;