WinReg
Convenient high-level C++ wrapper around the Windows Registry API
Install / Use
npx skills add GiovanniDicanio/WinRegInstalls into whichever agent you are using.
README
WinReg v6.5.1
High-level C++ Wrapper Around the Low-level Windows Registry C-interface API
by Giovanni Dicanio
The Windows Registry C-interface API is very low-level and hard to use.
I developed some C++ wrappers around this low-level Win32 API, to raise the semantic level,
using C++ classes like std::wstring, std::vector, etc. instead of raw C-style buffers and
low-level mechanisms.
For example, the REG_MULTI_SZ registry type associated to double-NUL-terminated C-style strings
is handled using a much easier higher-level vector<wstring>. My C++ code does the translation
between high-level C++ STL-based stuff and the low-level Win32 C-interface API.
Moreover, Win32 error codes are translated to C++ exceptions.
However, note that if you prefer checking return codes, there are also methods that follow
this pattern (e.g. TryXxxx() methods like TryOpen(), TryGetDwordValue(), TryGetStringValue(),
etc.).
The Win32 registry value types are mapped to C++ higher-level types according the following table:
| Win32 Registry Type | C++ Type |
| -------------------- |:----------------------------:|
| REG_DWORD | DWORD |
| REG_QWORD | ULONGLONG |
| REG_SZ | std::wstring |
| REG_EXPAND_SZ | std::wstring |
| REG_MULTI_SZ | std::vector<std::wstring> |
| REG_BINARY | std::vector<BYTE> |
This code is currently developed using Visual Studio 2022 with C++17 features enabled
(/std:c++17). I have no longer tested the code with previous compilers.
The code compiles cleanly at warning level 4 (/W4) in both 32-bit and 64-bit builds.
Moreover, the code compiles cleanly also in C++20 mode (/std:c++20).
This is a header-only library, implemented in the WinReg.hpp
header file.
WinRegTest.cpp contains some demo/test code for the library: check it out for some sample usage.
The library exposes four main classes:
RegKey: a tiny efficient wrapper around raw Win32HKEYhandlesRegException: an exception class to signal error conditionsRegResult: a tiny wrapper around Windows Registry APILSTATUSerror codes, returned by someTrymethods (likeRegKey::TryOpen)RegExpected<T>: an object that contains a value of typeT(e.g. aDWORDread from the registry) on success, or an instance of aRegResult-wrapped return code on error
There are many member functions inside the RegKey class, that wrap several parts of the native
C-interface Windows Registry API, in a convenient higher-level C++ way.
For example, you can simply open a registry key and get registry values with C++ code like this:
RegKey key{ HKEY_CURRENT_USER, L"SOFTWARE\\SomeKey" };
DWORD dw = key.GetDwordValue (L"SomeDwordValue");
wstring s = key.GetStringValue(L"SomeStringValue");
You can also open a registry key using a two-step construction process:
RegKey key;
key.Open(HKEY_CURRENT_USER, L"SOFTWARE\\SomeKey");
The above code will throw an exception on error. If you prefer to check return codes, you can do
that as well, using a TryXxxx method, e.g.:
RegKey key;
RegResult result = key.TryOpen(HKEY_CURRENT_USER, L"SOFTWARE\\SomeKey");
if (! result)
{
//
// Open failed.
//
// You can invoke the RegResult::Code and RegResult::ErrorMessage methods
// for further details.
//
...
}
You can also enumerate all the values under a given key with simple C++ code like this:
auto values = key.EnumValues();
for (const auto & v : values)
{
//
// Process current value:
//
// - v.first (wstring) is the value name
// - v.second (DWORD) is the value type
//
...
}
You can simplify the above iteration code using C++17 structured bindings, as well:
auto values = key.EnumValues();
for (const auto & [valueName, valueType] : values)
{
//
// Use valueName and valueType
//
...
}
You can also check if a key contains a given value or even a subkey, invoking the
RegKey::ContainsValue and RegKey::ContainsSubKey methods, e.g.:
if (key.ContainsValue(L"Connie"))
{
// The key contains the value named "Connie"
...
}
You can also use the RegKey::TryGet...Value methods, that return RegExpected<T>
instead of throwing an exception on error:
//
// RegKey::TryGetDwordValue() returns a RegExpected<DWORD>;
// the returned RegExpected contains a DWORD on success,
// or a RegResult instance on error.
//
// 'res' is a RegExpected<DWORD> in this case:
//
const auto res = key.TryGetDwordValue(L"SomeDwordValue");
if (res.IsValid()) // or simply: if (res)
{
//
// All right: Process the returned value ...
//
// Use res.GetValue() to access the stored DWORD.
//
}
else
{
//
// The method has failed:
//
// The returned RegExpected contains a RegResult with an error code.
// Use res.GetError() to access the RegResult object.
//
}
The library also supports reading raw binary data for Registry types that are unsupported
or less documented (e.g. REG_RESOURCE_LIST, REG_FULL_RESOURCE_DESCRIPTOR, etc.),
via the RegKey::GetRawValue and RegKey::TryGetRawValue methods.
Version Note: WinReg v5.1.1 is the latest version in which the TryGetXxxValue methods return
std::optional<T> (discarding the information about the error code).
Starting from v6.0.0, the TryGetXxxxValue methods return RegExpected<T> (which keeps
the error information on failure).
Note that many methods are available in two forms: one that throws an exception of type
RegException on error (e.g. RegKey::Open), and another that returns an error status object
of type RegResult (e.g. RegKey::TryOpen) instead of throwing an exception.
In addition, as indicated above, some methods like the RegKey::TryGet...Value ones return
RegExpected instead of throwing exceptions; in case of errors, the returned RegExpected
contains a RegResult storing the error code.
You can take a look at the test code in WinRegTest.cpp for some sample usage.
The library stuff lives under the winreg namespace.
See the WinReg.hpp header for more details and documentation.
Thanks to everyone who contributed to this project with some additional features and constructive comments and suggestions.
Improvements in v6.5.1
- Upgraded IDE from Visual Studio 2019 to Visual Studio 2022.
- Use the more specific
winreg_internalname for private/internal namespace, instead of the more generaldetails(which is safer and more robust in case of clients doingusing namespace winreg;). - Fixed bugs of
RegKey::LoadKey/TryLoadKeyfailing because the handle is nulled-before-use viaClosecall. - Fixed
RegKeymove-assignment implementation (removed bogus extra condition... && (m_hKey != other.m_hKey)). - Added a comment note clarifying a potential TOCTOU race condition inherent to the Win32 registry enumeration API
and the
RegKeyenumeration methodsEnumSubKeys/EnumValues/TryEnumSubKeys/TryEnumValues.
Related Skills
node-connect
385.5kDiagnose OpenClaw Android, iOS, or macOS node pairing, QR/setup code, route, auth, and connection failures.
blender-python-addon
40.5kBlender Python add-on rules for operators, panels, properties, registration, testing, and API-safe scripting
flutter-development-guidelines-cursorrules-prompt-file
40.5kCursor rules for Flutter development with MVVM architecture, Riverpod state management, Material widgets, and Dart style guidelines.
commit-push-pr
140.7kCommit, push, and open a PR
