Skip to content

Commit

Permalink
Game exe path command line argument (#713)
Browse files Browse the repository at this point in the history
* feat: --exePath commandline argument

ex. `SkyrimTogether.exe --exePath C:\Path\To\Game\SkyrimSE.exe`

* tweak: add explicit target exe error

* tweak: clang format

* fix: properly terminate process when no exe path given

* tweak: safer args bounds check + more explicit errors

* tweak: remove global exePath & titlePath

* tweak: clang format

* tweak: const naming
  • Loading branch information
ToeKneeRED authored Sep 11, 2024
1 parent f142880 commit ab18db9
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 5 deletions.
36 changes: 31 additions & 5 deletions Code/immersive_launcher/Launcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <BranchInfo.h>

Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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.
Expand Down
3 changes: 3 additions & 0 deletions Code/immersive_launcher/Launcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,7 @@ bool LoadProgram(LaunchContext&);
int StartUp(int argc, char** argv);

void InitClient();

bool HandleArguments(int, char**, bool&);

} // namespace launcher
82 changes: 82 additions & 0 deletions Code/immersive_launcher/oobe/PathArgument.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#include "PathArgument.h"

#include "TargetConfig.h"

#include "Utils/Error.h"
#include "utils/Registry.h"

#include <filesystem>

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<wchar_t>(HKEY_CURRENT_USER, kTiltedRegistryPath, L"TitlePath", cTitlePath) && Registry::WriteString<wchar_t>(HKEY_CURRENT_USER, kTiltedRegistryPath, L"TitleExe", cExePath);

if (!result)
{
DIE_NOW(L"Failed to write to registry")
}

return true;
}
} // namespace oobe
8 changes: 8 additions & 0 deletions Code/immersive_launcher/oobe/PathArgument.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

#include <string>

namespace oobe
{
bool PathArgument(const std::string& acPath);
}

0 comments on commit ab18db9

Please sign in to comment.