diff --git a/Code/immersive_launcher/Launcher.cpp b/Code/immersive_launcher/Launcher.cpp index 0547a00de..185a7d9fd 100644 --- a/Code/immersive_launcher/Launcher.cpp +++ b/Code/immersive_launcher/Launcher.cpp @@ -10,10 +10,12 @@ #include "Utils/FileVersion.inl" #include "oobe/PathSelection.h" +#include "oobe/PathArgument.h" #include "oobe/SupportChecks.h" #include "steam/SteamLoader.h" #include "base/dialogues/win/TaskDialog.h" +#include "utils/Registry.h" #include @@ -64,11 +66,8 @@ void SetMaxstdio() int StartUp(int argc, char** argv) { bool askSelect = (GetAsyncKeyState(VK_SPACE) & 0x8000); - for (int i = 1; i < argc; i++) - { - if (std::strcmp(argv[i], "-r") == 0) - askSelect = true; - } + if (!HandleArguments(argc, argv, askSelect)) + return -1; // TODO(Force): Make some InitSharedResources func. g_SharedWindowIcon = LoadIconW(GetModuleHandleW(nullptr), MAKEINTRESOURCEW(102)); @@ -141,6 +140,33 @@ void InitClient() // Jump into client code. RunTiltedApp(); } + +bool HandleArguments(int aArgc, char** aArgv, bool& aAskSelect) +{ + for (int i = 1; i < aArgc; i++) + { + if (std::strcmp(aArgv[i], "-r") == 0) + aAskSelect = true; + else if (std::strcmp(aArgv[i], "--exePath") == 0) + { + if (i + 1 >= aArgc) + { + SetLastError(ERROR_BAD_PATHNAME); + Die(L"No exe path specified", true); + return false; + } + + if (!oobe::PathArgument(aArgv[i + 1])) + { + SetLastError(ERROR_BAD_ARGUMENTS); + Die(L"Failed to parse path argument", true); + return false; + } + } + } + + return true; +} } // namespace launcher // CreateProcess in suspended mode. diff --git a/Code/immersive_launcher/Launcher.h b/Code/immersive_launcher/Launcher.h index 4c1571d83..185cb3616 100644 --- a/Code/immersive_launcher/Launcher.h +++ b/Code/immersive_launcher/Launcher.h @@ -30,4 +30,7 @@ bool LoadProgram(LaunchContext&); int StartUp(int argc, char** argv); void InitClient(); + +bool HandleArguments(int, char**, bool&); + } // namespace launcher diff --git a/Code/immersive_launcher/oobe/PathArgument.cpp b/Code/immersive_launcher/oobe/PathArgument.cpp new file mode 100644 index 000000000..38daaaee6 --- /dev/null +++ b/Code/immersive_launcher/oobe/PathArgument.cpp @@ -0,0 +1,82 @@ +#include "PathArgument.h" + +#include "TargetConfig.h" + +#include "Utils/Error.h" +#include "utils/Registry.h" + +#include + +namespace oobe +{ +using namespace TiltedPhoques; + +namespace +{ +constexpr wchar_t kTiltedRegistryPath[] = LR"(Software\TiltedPhoques\TiltedEvolution\)" SHORT_NAME; + +#define DIE_NOW(err) \ + { \ + Die(err, true); \ + return false; \ + } + +bool ValidatePath(const std::wstring& acPath) +{ + const std::wstring cTitlePath = acPath.substr(0, acPath.find_last_of('\\')); + std::wstring errorText{}; + + if (acPath.find_last_of('\\') == std::string::npos || acPath.ends_with(*"\\")) + { + SetLastError(ERROR_BAD_PATHNAME); + errorText += L"Invalid path\n"; + } + + if (!acPath.ends_with(L".exe")) + { + SetLastError(ERROR_BAD_ARGUMENTS); + errorText += acPath.substr(acPath.find_last_of('\\') + 1, acPath.back()) + L" is not an executable file\n"; + } + else if (!acPath.ends_with(TARGET_NAME L".exe")) + { + SetLastError(ERROR_FILE_NOT_FOUND); + errorText += TARGET_NAME L".exe not found\n"; + } + + if (!std::filesystem::exists(acPath) || !std::filesystem::exists(cTitlePath)) + { + SetLastError(ERROR_BAD_PATHNAME); + errorText += L"Path does not exist\n"; + } + + if (!errorText.empty()) + { + errorText += L"\nPath: " + acPath; + DIE_NOW(errorText.c_str()) + } + + return true; +} +} // namespace + +bool PathArgument(const std::string& acPath) +{ + const std::wstring cExePath = std::wstring(acPath.begin(), acPath.end()); + const std::wstring cTitlePath = cExePath.substr(0, cExePath.find_last_of('\\')); + + if (!ValidatePath(cExePath)) + { + DIE_NOW(L"Failed to validate path") + } + + // Write to registry so oobe::SelectInstall can handle the rest + const bool result = Registry::WriteString(HKEY_CURRENT_USER, kTiltedRegistryPath, L"TitlePath", cTitlePath) && Registry::WriteString(HKEY_CURRENT_USER, kTiltedRegistryPath, L"TitleExe", cExePath); + + if (!result) + { + DIE_NOW(L"Failed to write to registry") + } + + return true; +} +} // namespace oobe diff --git a/Code/immersive_launcher/oobe/PathArgument.h b/Code/immersive_launcher/oobe/PathArgument.h new file mode 100644 index 000000000..8c2b8f1ba --- /dev/null +++ b/Code/immersive_launcher/oobe/PathArgument.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace oobe +{ +bool PathArgument(const std::string& acPath); +}