diff options
Diffstat (limited to 'src/openvic-simulation/dataloader/Vic2PathSearch_Windows.hpp')
-rw-r--r-- | src/openvic-simulation/dataloader/Vic2PathSearch_Windows.hpp | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/src/openvic-simulation/dataloader/Vic2PathSearch_Windows.hpp b/src/openvic-simulation/dataloader/Vic2PathSearch_Windows.hpp new file mode 100644 index 0000000..37991b6 --- /dev/null +++ b/src/openvic-simulation/dataloader/Vic2PathSearch_Windows.hpp @@ -0,0 +1,170 @@ +#pragma once + +#include <concepts> +#pragma comment(lib, "advapi32.lib") + +#include <string> +#include <string_view> + +#include <Windows.h> + +namespace OpenVic::Windows { + inline std::wstring convert(std::string_view as) { + // deal with trivial case of empty string + if (as.empty()) { + return std::wstring(); + } + + // determine required length of new string + size_t length = ::MultiByteToWideChar(CP_UTF8, 0, as.data(), (int)as.length(), 0, 0); + + // construct new string of required length + std::wstring ret(length, L'\0'); + + // convert old string to new string + ::MultiByteToWideChar(CP_UTF8, 0, as.data(), (int)as.length(), &ret[0], (int)ret.length()); + + // return new string ( compiler should optimize this away ) + return ret; + } + + inline std::string convert(std::wstring_view as) { + // deal with trivial case of empty string + if (as.empty()) { + return std::string(); + } + + // determine required length of new string + size_t length = ::WideCharToMultiByte(CP_UTF8, 0, as.data(), (int)as.length(), 0, 0, NULL, NULL); + + // construct new string of required length + std::string ret(length, '\0'); + + // convert old string to new string + ::WideCharToMultiByte(CP_UTF8, 0, as.data(), (int)as.length(), &ret[0], (int)ret.length(), NULL, NULL); + + // return new string ( compiler should optimize this away ) + return ret; + } + + template<typename T, typename... U> + concept any_of = (std::same_as<T, U> || ...); + + template<typename T> + concept either_char_type = any_of<T, char, wchar_t>; + + template<typename T> + concept has_data = requires(T t) { + { t.data() } -> std::convertible_to<const typename T::value_type*>; + }; + + class RegistryKey { + public: + RegistryKey(HKEY key_handle) : _key_handle(key_handle) {} + + template<either_char_type CHAR_T, either_char_type CHAR_T2> + RegistryKey( + HKEY parent_key_handle, std::basic_string_view<CHAR_T> child_key_name, std::basic_string_view<CHAR_T2> value_name + ) { + open_key(parent_key_handle, child_key_name); + query_key(value_name); + } + + ~RegistryKey() { + close_key(); + } + + bool is_open() const { + return _key_handle != nullptr; + } + + std::wstring_view value() const { + return _value; + } + + template<either_char_type CHAR_T> + LSTATUS open_key(HKEY parent_key_handle, std::basic_string_view<CHAR_T> key_path) { + if (is_open()) { + close_key(); + } + if constexpr (std::is_same_v<CHAR_T, char>) { + return RegOpenKeyExW(parent_key_handle, convert(key_path).data(), REG_NONE, KEY_READ, &_key_handle); + } else { + return RegOpenKeyExW(parent_key_handle, key_path.data(), REG_NONE, KEY_READ, &_key_handle); + } + } + + bool is_predefined() const { + return (_key_handle == HKEY_CURRENT_USER) || (_key_handle == HKEY_LOCAL_MACHINE) || + (_key_handle == HKEY_CLASSES_ROOT) || (_key_handle == HKEY_CURRENT_CONFIG) || + (_key_handle == HKEY_CURRENT_USER_LOCAL_SETTINGS) || (_key_handle == HKEY_PERFORMANCE_DATA) || + (_key_handle == HKEY_PERFORMANCE_NLSTEXT) || (_key_handle == HKEY_PERFORMANCE_TEXT) || + (_key_handle == HKEY_USERS); + } + + LSTATUS close_key() { + if (!is_open() || is_predefined()) { + return ERROR_SUCCESS; + } + auto result = RegCloseKey(_key_handle); + _key_handle = nullptr; + return result; + } + + template<either_char_type CHAR_T> + LSTATUS query_key(std::basic_string_view<CHAR_T> value_name) { + DWORD data_size; + DWORD type; + + const auto& wide_value = [&value_name]() -> has_data auto { + if constexpr (std::is_same_v<CHAR_T, char>) { + return convert(value_name); + } else { + return value_name; + } + }(); + + auto result = RegQueryValueExW(_key_handle, wide_value.data(), NULL, &type, NULL, &data_size); + if (result != ERROR_SUCCESS || type != REG_SZ) { + close_key(); + return result; + } + _value = std::wstring(data_size / sizeof(wchar_t), L'\0'); + result = RegQueryValueExW( + _key_handle, wide_value.data(), NULL, NULL, reinterpret_cast<LPBYTE>(_value.data()), &data_size + ); + close_key(); + + std::size_t first_null = _value.find_first_of(L'\0'); + if (first_null != std::string::npos) { + _value.resize(first_null); + } + + return result; + } + + private: + HKEY _key_handle = nullptr; + std::wstring _value; + }; + + template<either_char_type RCHAR_T, either_char_type CHAR_T, either_char_type CHAR_T2> + std::basic_string<RCHAR_T> ReadRegValue( + HKEY root, std::basic_string_view<CHAR_T> key, std::basic_string_view<CHAR_T2> name + ) { + RegistryKey registry_key(root, key, name); + if constexpr (std::is_same_v<RCHAR_T, char>) { + return convert(registry_key.value()); + } else { + return registry_key.value(); + } + } + + template<either_char_type RCHAR_T, either_char_type CHAR_T, either_char_type CHAR_T2> + std::basic_string<RCHAR_T> ReadRegValue(HKEY root, const CHAR_T* key, const CHAR_T2* name) { + auto key_sv = std::basic_string_view(key); + auto name_sv = std::basic_string_view(name); + + return ReadRegValue<RCHAR_T>(root, key_sv, name_sv); + } +} |