// Copyright (C) 2021 TiltedPhoques SRL. // For licensing information see LICENSE at the root of this distribution. #include #include #include #include "TargetConfig.h" #include "launcher.h" #include "utils/ComUtils.h" #include "utils/Registry.h" namespace oobe { using namespace TiltedPhoques; namespace { constexpr wchar_t kBethesdaRegistryPath[] = LR"(Software\Wow6432Node\Bethesda Softworks\)" SHORT_NAME; constexpr wchar_t kTiltedRegistryPath[] = LR"(Software\TiltedPhoques\TiltedEvolution\)" SHORT_NAME; std::wstring SuggestTitlePath() { return Registry::ReadString(HKEY_LOCAL_MACHINE, kBethesdaRegistryPath, L"installed path"); } std::optional OpenPathSelectionDialog2(const std::wstring& aPathSuggestion) { // in case some other stuff already tried to unregister the global instance ComScope _; ComPtr pFileDialog; auto hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL, IID_IFileOpenDialog, reinterpret_cast(pFileDialog.GetAddressOf())); if (FAILED(hr)) return std::nullopt; pFileDialog->SetTitle(L"Select the game executable (" TARGET_NAME L".exe)"); static constinit COMDLG_FILTERSPEC rgSpec[] = {{L"Executables", TARGET_NAME L".exe"}}; pFileDialog->SetFileTypes(1, &rgSpec[0]); // pre select suggested folder & exe if (!aPathSuggestion.empty()) { ComPtr pItem; if (SUCCEEDED(SHCreateItemFromParsingName(aPathSuggestion.c_str(), nullptr, IID_PPV_ARGS(&pItem)))) { pFileDialog->SetFolder(pItem.Get()); pFileDialog->SetFileName(TARGET_NAME L".exe"); } } hr = pFileDialog->Show(nullptr); if (FAILED(hr)) return std::nullopt; ComPtr pItem; hr = pFileDialog->GetResult(pItem.GetAddressOf()); if (SUCCEEDED(hr)) { PWSTR filePath; hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &filePath); if (SUCCEEDED(hr)) { auto rval = filePath; CoTaskMemFree(filePath); return rval; } } return std::nullopt; } } // namespace bool SelectInstall(bool aForceSelect) { // separate, so a custom executable can be chosen for TP auto titlePath = Registry::ReadString(HKEY_CURRENT_USER, kTiltedRegistryPath, L"TitlePath"); auto exePath = Registry::ReadString(HKEY_CURRENT_USER, kTiltedRegistryPath, L"TitleExe"); bool result = true; if (!std::filesystem::exists(titlePath) || !std::filesystem::exists(exePath) || aForceSelect) { constexpr int kSelectionAttempts = 3; for (int i = 0; i < kSelectionAttempts; i++) { if (auto path = OpenPathSelectionDialog2(SuggestTitlePath())) { size_t pos = path->find_last_of(L'\\'); if (pos == std::string::npos) return false; titlePath = path->substr(0, pos); exePath = (*path); // game is installed into our directory, or otherwise. if (titlePath == TiltedPhoques::GetPath()) { continue; } // if this fails, we try again result = Registry::WriteString(HKEY_CURRENT_USER, kTiltedRegistryPath, L"TitlePath", titlePath) && Registry::WriteString(HKEY_CURRENT_USER, kTiltedRegistryPath, L"TitleExe", exePath); if (result) break; } else break; } } if (result) { auto* apContext = launcher::GetLaunchContext(); apContext->gamePath = titlePath; apContext->exePath = exePath; } return result; } } // namespace oobe