225 lines
6.8 KiB
C++
225 lines
6.8 KiB
C++
#include "nvprefs_common.h"
|
|
|
|
#include "nvprefs_interface.h"
|
|
|
|
#include "driver_settings.h"
|
|
#include "undo_data.h"
|
|
#include "undo_file.h"
|
|
|
|
namespace {
|
|
|
|
const auto sunshine_program_data_folder = "Sunshine";
|
|
const auto nvprefs_undo_file_name = "nvprefs_undo.json";
|
|
|
|
} // namespace
|
|
|
|
namespace nvprefs {
|
|
|
|
struct nvprefs_interface::impl {
|
|
bool loaded = false;
|
|
driver_settings_t driver_settings;
|
|
std::filesystem::path undo_folder_path;
|
|
std::filesystem::path undo_file_path;
|
|
std::optional<undo_data_t> undo_data;
|
|
std::optional<undo_file_t> undo_file;
|
|
};
|
|
|
|
nvprefs_interface::nvprefs_interface():
|
|
pimpl(new impl()) {
|
|
}
|
|
|
|
nvprefs_interface::~nvprefs_interface() {
|
|
if (owning_undo_file() && load()) {
|
|
restore_global_profile();
|
|
}
|
|
unload();
|
|
}
|
|
|
|
bool
|
|
nvprefs_interface::load() {
|
|
if (!pimpl->loaded) {
|
|
// Check %ProgramData% variable, need it for storing undo file
|
|
wchar_t program_data_env[MAX_PATH];
|
|
auto get_env_result = GetEnvironmentVariableW(L"ProgramData", program_data_env, MAX_PATH);
|
|
if (get_env_result == 0 || get_env_result >= MAX_PATH || !std::filesystem::is_directory(program_data_env)) {
|
|
error_message("Missing or malformed %ProgramData% environment variable");
|
|
return false;
|
|
}
|
|
|
|
// Prepare undo file path variables
|
|
pimpl->undo_folder_path = std::filesystem::path(program_data_env) / sunshine_program_data_folder;
|
|
pimpl->undo_file_path = pimpl->undo_folder_path / nvprefs_undo_file_name;
|
|
|
|
// Dynamically load nvapi library and load driver settings
|
|
pimpl->loaded = pimpl->driver_settings.init();
|
|
}
|
|
|
|
return pimpl->loaded;
|
|
}
|
|
|
|
void
|
|
nvprefs_interface::unload() {
|
|
if (pimpl->loaded) {
|
|
// Unload dynamically loaded nvapi library
|
|
pimpl->driver_settings.destroy();
|
|
pimpl->loaded = false;
|
|
}
|
|
}
|
|
|
|
bool
|
|
nvprefs_interface::restore_from_and_delete_undo_file_if_exists() {
|
|
if (!pimpl->loaded) return false;
|
|
|
|
// Check for undo file from previous improper termination
|
|
bool access_denied = false;
|
|
if (auto undo_file = undo_file_t::open_existing_file(pimpl->undo_file_path, access_denied)) {
|
|
// Try to restore from the undo file
|
|
info_message("Opened undo file from previous improper termination");
|
|
if (auto undo_data = undo_file->read_undo_data()) {
|
|
if (pimpl->driver_settings.restore_global_profile_to_undo(*undo_data) && pimpl->driver_settings.save_settings()) {
|
|
info_message("Restored global profile settings from undo file - deleting the file");
|
|
}
|
|
else {
|
|
error_message("Failed to restore global profile settings from undo file, deleting the file anyway");
|
|
}
|
|
}
|
|
else {
|
|
error_message("Coulnd't read undo file, deleting the file anyway");
|
|
}
|
|
|
|
if (!undo_file->delete_file()) {
|
|
error_message("Couldn't delete undo file");
|
|
return false;
|
|
}
|
|
}
|
|
else if (access_denied) {
|
|
error_message("Couldn't open undo file from previous improper termination, or confirm that there's no such file");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
nvprefs_interface::modify_application_profile() {
|
|
if (!pimpl->loaded) return false;
|
|
|
|
// Modify and save sunshine.exe application profile settings, if needed
|
|
bool modified = false;
|
|
if (!pimpl->driver_settings.check_and_modify_application_profile(modified)) {
|
|
error_message("Failed to modify application profile settings");
|
|
return false;
|
|
}
|
|
else if (modified) {
|
|
if (pimpl->driver_settings.save_settings()) {
|
|
info_message("Modified application profile settings");
|
|
}
|
|
else {
|
|
error_message("Couldn't save application profile settings");
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
info_message("No need to modify application profile settings");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
nvprefs_interface::modify_global_profile() {
|
|
if (!pimpl->loaded) return false;
|
|
|
|
// Modify but not save global profile settings, if needed
|
|
std::optional<undo_data_t> undo_data;
|
|
if (!pimpl->driver_settings.check_and_modify_global_profile(undo_data)) {
|
|
error_message("Couldn't modify global profile settings");
|
|
return false;
|
|
}
|
|
else if (!undo_data) {
|
|
info_message("No need to modify global profile settings");
|
|
return true;
|
|
}
|
|
|
|
auto make_undo_and_commit = [&]() -> bool {
|
|
// Create and lock undo file if it hasn't been done yet
|
|
if (!pimpl->undo_file) {
|
|
// Prepare Sunshine folder in ProgramData if it doesn't exist
|
|
if (!CreateDirectoryW(pimpl->undo_folder_path.c_str(), nullptr) && GetLastError() != ERROR_ALREADY_EXISTS) {
|
|
error_message("Couldn't create undo folder");
|
|
return false;
|
|
}
|
|
|
|
// Create undo file to handle improper termination of nvprefs.exe
|
|
pimpl->undo_file = undo_file_t::create_new_file(pimpl->undo_file_path);
|
|
if (!pimpl->undo_file) {
|
|
error_message("Couldn't create undo file");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
assert(undo_data);
|
|
if (pimpl->undo_data) {
|
|
// Merge undo data if settings has been modified externally since our last modification
|
|
pimpl->undo_data->merge(*undo_data);
|
|
}
|
|
else {
|
|
pimpl->undo_data = undo_data;
|
|
}
|
|
|
|
// Write undo data to undo file
|
|
if (!pimpl->undo_file->write_undo_data(*pimpl->undo_data)) {
|
|
error_message("Couldn't write to undo file - deleting the file");
|
|
if (!pimpl->undo_file->delete_file()) {
|
|
error_message("Couldn't delete undo file");
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Save global profile settings
|
|
if (!pimpl->driver_settings.save_settings()) {
|
|
error_message("Couldn't save global profile settings");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
if (!make_undo_and_commit()) {
|
|
// Revert settings modifications
|
|
pimpl->driver_settings.load_settings();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
nvprefs_interface::owning_undo_file() {
|
|
return pimpl->undo_file.has_value();
|
|
}
|
|
|
|
bool
|
|
nvprefs_interface::restore_global_profile() {
|
|
if (!pimpl->loaded || !pimpl->undo_data || !pimpl->undo_file) return false;
|
|
|
|
// Restore global profile settings with undo data
|
|
if (pimpl->driver_settings.restore_global_profile_to_undo(*pimpl->undo_data) &&
|
|
pimpl->driver_settings.save_settings()) {
|
|
// Global profile settings sucessfully restored, can delete undo file
|
|
if (!pimpl->undo_file->delete_file()) {
|
|
error_message("Couldn't delete undo file");
|
|
return false;
|
|
}
|
|
pimpl->undo_data = std::nullopt;
|
|
pimpl->undo_file = std::nullopt;
|
|
}
|
|
else {
|
|
error_message("Couldn't restore global profile settings");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
} // namespace nvprefs
|