mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2025-10-30 07:11:05 +00:00
Implemented Windows registry read/write (#225)
* Implemented Windows registry read/write * Simplify registry API and handle path writes * Linux SetWorkingDirectory * Implement reading path and unicode string from windows registry * Use string_view value names for registry * Use RegGetValueW * Paths adjustments * / * Update working directory update failure message * Updated linux SetWorkingDirectory * Update flatpak define * Remove RootDirectoryPath and save registry at startup * dont save registry on exit * Slight formatting update --------- Co-authored-by: Sajid <sajidur78@gmail.com>
This commit is contained in:
parent
7b9b4245de
commit
8b345d2cbd
14 changed files with 297 additions and 38 deletions
|
|
@ -179,6 +179,8 @@ set(UNLEASHED_RECOMP_USER_CXX_SOURCES
|
||||||
"user/achievement_data.cpp"
|
"user/achievement_data.cpp"
|
||||||
"user/achievement_manager.cpp"
|
"user/achievement_manager.cpp"
|
||||||
"user/config.cpp"
|
"user/config.cpp"
|
||||||
|
"user/registry.cpp"
|
||||||
|
"user/paths.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
set(UNLEASHED_RECOMP_MOD_CXX_SOURCES
|
set(UNLEASHED_RECOMP_MOD_CXX_SOURCES
|
||||||
|
|
@ -296,7 +298,10 @@ else()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (UNLEASHED_RECOMP_FLATPAK)
|
if (UNLEASHED_RECOMP_FLATPAK)
|
||||||
target_compile_definitions(UnleashedRecomp PRIVATE "GAME_INSTALL_DIRECTORY=\"/var/data\"")
|
target_compile_definitions(UnleashedRecomp PRIVATE
|
||||||
|
"UNLEASHED_RECOMP_FLATPAK"
|
||||||
|
"GAME_INSTALL_DIRECTORY=\"/var/data\""
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (UNLEASHED_RECOMP_D3D12)
|
if (UNLEASHED_RECOMP_D3D12)
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include <ui/game_window.h>
|
#include <ui/game_window.h>
|
||||||
#include <user/config.h>
|
#include <user/config.h>
|
||||||
#include <user/paths.h>
|
#include <user/paths.h>
|
||||||
|
#include <user/registry.h>
|
||||||
|
|
||||||
void App::Restart(std::vector<std::string> restartArgs)
|
void App::Restart(std::vector<std::string> restartArgs)
|
||||||
{
|
{
|
||||||
|
|
@ -33,6 +34,7 @@ PPC_FUNC(sub_824EB490)
|
||||||
App::s_isInit = true;
|
App::s_isInit = true;
|
||||||
App::s_isMissingDLC = !Installer::checkAllDLC(GetGamePath());
|
App::s_isMissingDLC = !Installer::checkAllDLC(GetGamePath());
|
||||||
App::s_language = Config::Language;
|
App::s_language = Config::Language;
|
||||||
|
Registry::Save();
|
||||||
|
|
||||||
__imp__sub_824EB490(ctx, base);
|
__imp__sub_824EB490(ctx, base);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
typedef returnType _##procName(__VA_ARGS__); \
|
typedef returnType _##procName(__VA_ARGS__); \
|
||||||
_##procName* procName = (_##procName*)PROC_ADDRESS(libraryName, #procName);
|
_##procName* procName = (_##procName*)PROC_ADDRESS(libraryName, #procName);
|
||||||
|
|
||||||
|
#define STR(x) #x
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T RoundUp(const T& in_rValue, uint32_t in_round)
|
inline T RoundUp(const T& in_rValue, uint32_t in_round)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,12 @@
|
||||||
#include <hid/hid.h>
|
#include <hid/hid.h>
|
||||||
#include <user/config.h>
|
#include <user/config.h>
|
||||||
#include <user/paths.h>
|
#include <user/paths.h>
|
||||||
|
#include <user/registry.h>
|
||||||
#include <kernel/xdbf.h>
|
#include <kernel/xdbf.h>
|
||||||
#include <install/installer.h>
|
#include <install/installer.h>
|
||||||
#include <os/logger.h>
|
#include <os/logger.h>
|
||||||
|
#include <os/process.h>
|
||||||
|
#include <os/registry.h>
|
||||||
#include <ui/installer_wizard.h>
|
#include <ui/installer_wizard.h>
|
||||||
#include <mod/mod_loader.h>
|
#include <mod/mod_loader.h>
|
||||||
|
|
||||||
|
|
@ -144,6 +147,9 @@ int main(int argc, char *argv[])
|
||||||
timeBeginPeriod(1);
|
timeBeginPeriod(1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (!os::registry::Init())
|
||||||
|
LOGN_WARNING("OS doesn't support registry");
|
||||||
|
|
||||||
os::logger::Init();
|
os::logger::Init();
|
||||||
|
|
||||||
bool forceInstaller = false;
|
bool forceInstaller = false;
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,11 @@ std::filesystem::path os::process::GetWorkingDirectory()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool os::process::SetWorkingDirectory(const std::filesystem::path& path)
|
||||||
|
{
|
||||||
|
return chdir(path.c_str()) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool os::process::StartProcess(const std::filesystem::path& path, const std::vector<std::string>& args, std::filesystem::path work)
|
bool os::process::StartProcess(const std::filesystem::path& path, const std::vector<std::string>& args, std::filesystem::path work)
|
||||||
{
|
{
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
|
|
|
||||||
21
UnleashedRecomp/os/linux/registry_linux.inl
Normal file
21
UnleashedRecomp/os/linux/registry_linux.inl
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
#include <os/registry.h>
|
||||||
|
|
||||||
|
// TODO: Implement
|
||||||
|
inline bool os::registry::Init()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: read from file?
|
||||||
|
template<typename T>
|
||||||
|
bool os::registry::ReadValue(const std::string_view& name, T& data)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: write to file?
|
||||||
|
template<typename T>
|
||||||
|
bool os::registry::WriteValue(const std::string_view& name, const T& data)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
@ -4,5 +4,6 @@ namespace os::process
|
||||||
{
|
{
|
||||||
std::filesystem::path GetExecutablePath();
|
std::filesystem::path GetExecutablePath();
|
||||||
std::filesystem::path GetWorkingDirectory();
|
std::filesystem::path GetWorkingDirectory();
|
||||||
|
bool SetWorkingDirectory(const std::filesystem::path& path);
|
||||||
bool StartProcess(const std::filesystem::path& path, const std::vector<std::string>& args, std::filesystem::path work = {});
|
bool StartProcess(const std::filesystem::path& path, const std::vector<std::string>& args, std::filesystem::path work = {});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
UnleashedRecomp/os/registry.h
Normal file
18
UnleashedRecomp/os/registry.h
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace os::registry
|
||||||
|
{
|
||||||
|
bool Init();
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool ReadValue(const std::string_view& name, T& data);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool WriteValue(const std::string_view& name, const T& data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
#include <os/win32/registry_win32.inl>
|
||||||
|
#elif defined(__linux__)
|
||||||
|
#include <os/linux/registry_linux.inl>
|
||||||
|
#endif
|
||||||
|
|
@ -20,6 +20,11 @@ std::filesystem::path os::process::GetWorkingDirectory()
|
||||||
return std::filesystem::path(workPath);
|
return std::filesystem::path(workPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool os::process::SetWorkingDirectory(const std::filesystem::path& path)
|
||||||
|
{
|
||||||
|
return SetCurrentDirectoryW(path.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
bool os::process::StartProcess(const std::filesystem::path& path, const std::vector<std::string>& args, std::filesystem::path work)
|
bool os::process::StartProcess(const std::filesystem::path& path, const std::vector<std::string>& args, std::filesystem::path work)
|
||||||
{
|
{
|
||||||
if (path.empty())
|
if (path.empty())
|
||||||
|
|
|
||||||
153
UnleashedRecomp/os/win32/registry_win32.inl
Normal file
153
UnleashedRecomp/os/win32/registry_win32.inl
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
#include <os/registry.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
inline const wchar_t* g_registryRoot = L"Software\\UnleashedRecomp";
|
||||||
|
|
||||||
|
inline bool os::registry::Init()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool os::registry::ReadValue(const std::string_view& name, T& data)
|
||||||
|
{
|
||||||
|
HKEY hKey;
|
||||||
|
|
||||||
|
if (RegOpenKeyExW(HKEY_CURRENT_USER, g_registryRoot, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
wchar_t wideName[128];
|
||||||
|
int wideNameSize = MultiByteToWideChar(CP_UTF8, 0, name.data(), name.size(), wideName, sizeof(wideName));
|
||||||
|
if (wideNameSize == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wideName[wideNameSize] = 0;
|
||||||
|
DWORD bufferSize = 0;
|
||||||
|
DWORD dataType = 0;
|
||||||
|
|
||||||
|
auto result = RegGetValueW(hKey, nullptr, wideName, RRF_RT_ANY, &dataType, nullptr, &bufferSize);
|
||||||
|
|
||||||
|
if (result != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = ERROR_INVALID_FUNCTION;
|
||||||
|
if constexpr (std::is_same_v<T, std::string>)
|
||||||
|
{
|
||||||
|
if (dataType == REG_SZ)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> buffer{};
|
||||||
|
buffer.reserve(bufferSize);
|
||||||
|
result = RegGetValueW(hKey, nullptr, wideName, RRF_RT_REG_SZ, nullptr, buffer.data(), &bufferSize);
|
||||||
|
|
||||||
|
if (result == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
int valueSize = WideCharToMultiByte(CP_UTF8, 0, (wchar_t*)buffer.data(), (bufferSize / sizeof(wchar_t)) - 1, nullptr, 0, nullptr, nullptr);
|
||||||
|
data.resize(valueSize);
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, (wchar_t*)buffer.data(), (bufferSize / sizeof(wchar_t)) - 1, data.data(), valueSize, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, std::filesystem::path>)
|
||||||
|
{
|
||||||
|
if (dataType == REG_SZ)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> buffer{};
|
||||||
|
buffer.reserve(bufferSize);
|
||||||
|
result = RegGetValueW(hKey, nullptr, wideName, RRF_RT_REG_SZ, nullptr, buffer.data(), &bufferSize);
|
||||||
|
|
||||||
|
if (result == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
data = reinterpret_cast<wchar_t*>(buffer.data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, uint32_t>)
|
||||||
|
{
|
||||||
|
result = RegGetValueW(hKey, nullptr, wideName, RRF_RT_DWORD, nullptr, (BYTE*)&data, &bufferSize);
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, uint64_t>)
|
||||||
|
{
|
||||||
|
result = RegGetValueW(hKey, nullptr, wideName, RRF_RT_QWORD, nullptr, (BYTE*)&data, &bufferSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static_assert(false, "Unsupported data type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
return result == ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool os::registry::WriteValue(const std::string_view& name, const T& data)
|
||||||
|
{
|
||||||
|
HKEY hKey;
|
||||||
|
|
||||||
|
if (RegCreateKeyExW(HKEY_CURRENT_USER, g_registryRoot, 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
BYTE* pData = nullptr;
|
||||||
|
DWORD dataSize = 0;
|
||||||
|
DWORD dataType = 0;
|
||||||
|
bool wideString = false;
|
||||||
|
|
||||||
|
if constexpr (std::is_same_v<T, std::string>)
|
||||||
|
{
|
||||||
|
pData = (BYTE*)data.c_str();
|
||||||
|
dataSize = data.size() + 1;
|
||||||
|
dataType = REG_SZ;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, uint32_t>)
|
||||||
|
{
|
||||||
|
pData = &data;
|
||||||
|
dataSize = sizeof(T);
|
||||||
|
dataType = REG_DWORD;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, uint64_t>)
|
||||||
|
{
|
||||||
|
pData = &data;
|
||||||
|
dataSize = sizeof(T);
|
||||||
|
dataType = REG_QWORD;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, std::filesystem::path>)
|
||||||
|
{
|
||||||
|
pData = (BYTE*)data.c_str();
|
||||||
|
dataSize = (wcslen((const wchar_t*)pData) + 1) * sizeof(wchar_t);
|
||||||
|
dataType = REG_SZ;
|
||||||
|
wideString = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static_assert(false, "Unsupported data type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
LSTATUS result = ERROR_INVALID_FUNCTION;
|
||||||
|
if (wideString)
|
||||||
|
{
|
||||||
|
wchar_t wideName[128];
|
||||||
|
int wideNameSize = MultiByteToWideChar(CP_UTF8, 0, name.data(), name.size(), wideName, sizeof(wideName));
|
||||||
|
if (wideNameSize == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wideName[wideNameSize] = 0;
|
||||||
|
result = RegSetValueExW(hKey, wideName, 0, dataType, pData, dataSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = RegSetValueExA(hKey, name.data(), 0, dataType, pData, dataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
RegCloseKey(hKey);
|
||||||
|
|
||||||
|
if (result != ERROR_SUCCESS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
52
UnleashedRecomp/user/paths.cpp
Normal file
52
UnleashedRecomp/user/paths.cpp
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
#include "paths.h"
|
||||||
|
#include <os/process.h>
|
||||||
|
|
||||||
|
std::filesystem::path g_executableRoot = os::process::GetExecutablePath().remove_filename();
|
||||||
|
std::filesystem::path g_userPath = BuildUserPath();
|
||||||
|
|
||||||
|
bool CheckPortable()
|
||||||
|
{
|
||||||
|
return std::filesystem::exists(g_executableRoot / "portable.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path BuildUserPath()
|
||||||
|
{
|
||||||
|
if (CheckPortable())
|
||||||
|
return g_executableRoot;
|
||||||
|
|
||||||
|
std::filesystem::path userPath;
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
PWSTR knownPath = NULL;
|
||||||
|
if (SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &knownPath) == S_OK)
|
||||||
|
userPath = std::filesystem::path{ knownPath } / USER_DIRECTORY;
|
||||||
|
|
||||||
|
CoTaskMemFree(knownPath);
|
||||||
|
#elif defined(__linux__)
|
||||||
|
const char* homeDir = getenv("HOME");
|
||||||
|
if (homeDir == nullptr)
|
||||||
|
{
|
||||||
|
homeDir = getpwuid(getuid())->pw_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (homeDir != nullptr)
|
||||||
|
{
|
||||||
|
// Prefer to store in the .config directory if it exists. Use the home directory otherwise.
|
||||||
|
std::filesystem::path homePath = homeDir;
|
||||||
|
std::filesystem::path configPath = homePath / ".config";
|
||||||
|
if (std::filesystem::exists(configPath))
|
||||||
|
userPath = configPath / USER_DIRECTORY;
|
||||||
|
else
|
||||||
|
userPath = homePath / ("." USER_DIRECTORY);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static_assert(false, "GetUserPath() not implemented for this platform.");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return userPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::filesystem::path& GetUserPath()
|
||||||
|
{
|
||||||
|
return g_userPath;
|
||||||
|
}
|
||||||
|
|
@ -13,42 +13,9 @@ inline std::filesystem::path GetGamePath()
|
||||||
return GAME_INSTALL_DIRECTORY;
|
return GAME_INSTALL_DIRECTORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::filesystem::path GetUserPath()
|
bool CheckPortable();
|
||||||
{
|
std::filesystem::path BuildUserPath();
|
||||||
if (std::filesystem::exists(GAME_INSTALL_DIRECTORY "/portable.txt"))
|
const std::filesystem::path& GetUserPath();
|
||||||
return GAME_INSTALL_DIRECTORY;
|
|
||||||
|
|
||||||
std::filesystem::path userPath;
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
PWSTR knownPath = NULL;
|
|
||||||
if (SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &knownPath) == S_OK)
|
|
||||||
userPath = std::filesystem::path{ knownPath } / USER_DIRECTORY;
|
|
||||||
|
|
||||||
CoTaskMemFree(knownPath);
|
|
||||||
#elif defined(__linux__)
|
|
||||||
const char *homeDir = getenv("HOME");
|
|
||||||
if (homeDir == nullptr)
|
|
||||||
{
|
|
||||||
homeDir = getpwuid(getuid())->pw_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (homeDir != nullptr)
|
|
||||||
{
|
|
||||||
// Prefer to store in the .config directory if it exists. Use the home directory otherwise.
|
|
||||||
std::filesystem::path homePath = homeDir;
|
|
||||||
std::filesystem::path configPath = homePath / ".config";
|
|
||||||
if (std::filesystem::exists(configPath))
|
|
||||||
userPath = configPath / USER_DIRECTORY;
|
|
||||||
else
|
|
||||||
userPath = homePath / ("." USER_DIRECTORY);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static_assert(false, "GetUserPath() not implemented for this platform.");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return userPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::filesystem::path GetSavePath(bool checkForMods)
|
inline std::filesystem::path GetSavePath(bool checkForMods)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
14
UnleashedRecomp/user/registry.cpp
Normal file
14
UnleashedRecomp/user/registry.cpp
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#include "registry.h"
|
||||||
|
#include <os/process.h>
|
||||||
|
#include <os/registry.h>
|
||||||
|
#include <user/config.h>
|
||||||
|
|
||||||
|
void Registry::Load()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Registry::Save()
|
||||||
|
{
|
||||||
|
os::registry::WriteValue(STR(ExecutableFilePath), os::process::GetExecutablePath());
|
||||||
|
}
|
||||||
8
UnleashedRecomp/user/registry.h
Normal file
8
UnleashedRecomp/user/registry.h
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class Registry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void Load();
|
||||||
|
static void Save();
|
||||||
|
};
|
||||||
Loading…
Add table
Reference in a new issue