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
|
|
@ -178,7 +178,9 @@ set(UNLEASHED_RECOMP_INSTALL_CXX_SOURCES
|
|||
set(UNLEASHED_RECOMP_USER_CXX_SOURCES
|
||||
"user/achievement_data.cpp"
|
||||
"user/achievement_manager.cpp"
|
||||
"user/config.cpp"
|
||||
"user/config.cpp"
|
||||
"user/registry.cpp"
|
||||
"user/paths.cpp"
|
||||
)
|
||||
|
||||
set(UNLEASHED_RECOMP_MOD_CXX_SOURCES
|
||||
|
|
@ -296,7 +298,10 @@ else()
|
|||
endif()
|
||||
|
||||
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()
|
||||
|
||||
if (UNLEASHED_RECOMP_D3D12)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <ui/game_window.h>
|
||||
#include <user/config.h>
|
||||
#include <user/paths.h>
|
||||
#include <user/registry.h>
|
||||
|
||||
void App::Restart(std::vector<std::string> restartArgs)
|
||||
{
|
||||
|
|
@ -33,6 +34,7 @@ PPC_FUNC(sub_824EB490)
|
|||
App::s_isInit = true;
|
||||
App::s_isMissingDLC = !Installer::checkAllDLC(GetGamePath());
|
||||
App::s_language = Config::Language;
|
||||
Registry::Save();
|
||||
|
||||
__imp__sub_824EB490(ctx, base);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
typedef returnType _##procName(__VA_ARGS__); \
|
||||
_##procName* procName = (_##procName*)PROC_ADDRESS(libraryName, #procName);
|
||||
|
||||
#define STR(x) #x
|
||||
|
||||
template<typename T>
|
||||
inline T RoundUp(const T& in_rValue, uint32_t in_round)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,9 +12,12 @@
|
|||
#include <hid/hid.h>
|
||||
#include <user/config.h>
|
||||
#include <user/paths.h>
|
||||
#include <user/registry.h>
|
||||
#include <kernel/xdbf.h>
|
||||
#include <install/installer.h>
|
||||
#include <os/logger.h>
|
||||
#include <os/process.h>
|
||||
#include <os/registry.h>
|
||||
#include <ui/installer_wizard.h>
|
||||
#include <mod/mod_loader.h>
|
||||
|
||||
|
|
@ -144,6 +147,9 @@ int main(int argc, char *argv[])
|
|||
timeBeginPeriod(1);
|
||||
#endif
|
||||
|
||||
if (!os::registry::Init())
|
||||
LOGN_WARNING("OS doesn't support registry");
|
||||
|
||||
os::logger::Init();
|
||||
|
||||
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)
|
||||
{
|
||||
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 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 = {});
|
||||
}
|
||||
|
|
|
|||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
inline std::filesystem::path GetUserPath()
|
||||
{
|
||||
if (std::filesystem::exists(GAME_INSTALL_DIRECTORY "/portable.txt"))
|
||||
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;
|
||||
}
|
||||
bool CheckPortable();
|
||||
std::filesystem::path BuildUserPath();
|
||||
const std::filesystem::path& GetUserPath();
|
||||
|
||||
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