Regarding an application written in C++ using the Windows API. I'd like to store a user setting like the window position on program exit, to the Windows registry and retrieve settings like these on the next start of the program.
I currently have 3 settings to be stored/retrieved to/from the registry.
typedef struct tagWINPOS
{
DWORD dwWindowStyle;
int iWindowX;
int iWindowY;
} winpos_t;
HKEY hKeyApp = (HKEY)INVALID_HANDLE_VALUE;
const char szWindowStyle[] = "WindowStyle";
const char szWindowX[] = "WindowX";
const char szWindowY[] = "WindowY";
Later on in the code I'm calling functions like RegSetValueEx and RegQueryValueEx always three times. Like so:
int SaveSettings( HWND hWnd )
{
winpos_t wpos;
// window dimensions from hWnd are stored to wpos, not shown
RegSetValueEx( hKeyApp, szWindowStyle, 0,
REG_DWORD,
(const BYTE*)&wpos.dwWindowStyle,
sizeof(wpos.dwWindowStyle) );
RegSetValueEx( hKeyApp, szWindowX, 0,
REG_DWORD,
(const BYTE*)&wpos.iWindowX,
sizeof(wpos.iWindowX) );
RegSetValueEx( hKeyApp, szWindowY, 0,
REG_DWORD,
(const BYTE*)&wpos.iWindowY,
sizeof(wpos.iWindowY) );
// further irrelevant code removed
}
Things start to look a bit tedious. So I was thinking to put all the parameters for one function call (say RegSetValueEx) into an std::array and then make a for loop iterating over all the array elements.
Because the Windows registry can store multiple data types, like DWORD (32-bit), QWORD (64-bit) and strings. I thought about std::variant to list all of these for this data field.
I'm started with a little test program like this:
#include <cstddef>
#include <cstdio>
#include <cstdint>
#include <tuple>
#include <variant>
typedef std::variant< int32_t, int64_t, char* > data_t;
typedef std::tuple<
data_t, // setting data
const char*, // setting name
std::size_t // size of setting [bytes]
> setting_t;
typedef std::array< setting_t, 2 > settings_t;
constexpr int reg_dword = 0;
constexpr int reg_qword = 1;
constexpr settings_t settings{
std::make_tuple( (std::in_place_index<reg_dword>, 33), "Mydata", 4 ),
std::make_tuple( (std::in_place_index<reg_qword>, 34), "Mydata2", sizeof(std::in_place_index_t<reg_qword>) ) };
int main()
{
printf( "name: %s, value %ld\n", std::get<1>( settings[0] ), std::get<0>( std::get<0>( settings[0] ) ));
getchar();
return EXIT_SUCCESS;
}
Anyway, do people consider this approach a good one to get to my goal of having to spell out a single function call of RegSetValueEx inside a for loop?
The initialization of the array has much boilerplate as well as the effort to obtain values. What is a good approach to improve the readability of this? Maybe a constexpr function like std::make_tuple but then more specific for my case?