diff --git a/Source/Common/Config.cpp b/Source/Common/Config.cpp index 3281ab931..fa22dc1bd 100644 --- a/Source/Common/Config.cpp +++ b/Source/Common/Config.cpp @@ -337,8 +337,57 @@ fextl::string RecoverGuestProgramFilename(fextl::string Program, bool ExecFDInte return Program; } -ApplicationNames LoadConfig(fextl::unique_ptr ArgsLoader, bool LoadProgramConfig, char** const envp, - bool ExecFDInterp, int ProgramFDFromEnv, const PortableInformation& PortableInfo) { +ApplicationNames GetApplicationNames(fextl::vector Args, bool ExecFDInterp, int ProgramFDFromEnv) { + if (Args.empty()) { + // Early exit if we weren't passed an argument + return {}; + } + + fextl::string Program {}; + fextl::string ProgramName {}; + + Args[0] = RecoverGuestProgramFilename(std::move(Args[0]), ExecFDInterp, ProgramFDFromEnv); + Program = Args[0]; + + bool Wine = false; + for (size_t CurrentProgramNameIndex = 0; CurrentProgramNameIndex < Args.size(); ++CurrentProgramNameIndex) { + auto CurrentProgramName = FHU::Filesystem::GetFilename(Args[CurrentProgramNameIndex]); + + if (CurrentProgramName == "wine-preloader" || CurrentProgramName == "wine64-preloader") { + // Wine preloader is required to be in the format of `wine-preloader ` + // The preloader doesn't execve the executable, instead maps it directly itself + // Skip the next argument since we know it is wine (potentially with custom wine executable name) + ++CurrentProgramNameIndex; + Wine = true; + } else if (CurrentProgramName == "wine" || CurrentProgramName == "wine64") { + // Next argument, this isn't the program we want + // + // If we are running wine or wine64 then we should check the next argument for the application name instead. + // wine will change the active program name with `setprogname` or `prctl(PR_SET_NAME`. + // Since FEX needs this data far earlier than libraries we need a different check. + Wine = true; + } else { + if (Wine == true) { + // If this was path separated with '\' then we need to check that. + auto WinSeparator = CurrentProgramName.find_last_of('\\'); + if (WinSeparator != CurrentProgramName.npos) { + // Used windows separators + CurrentProgramName = CurrentProgramName.substr(WinSeparator + 1); + } + } + + ProgramName = CurrentProgramName; + + // Past any wine program names + break; + } + } + + return ApplicationNames {std::move(Program), std::move(ProgramName)}; +} + +void LoadConfig(fextl::unique_ptr ArgsLoader, fextl::string ProgramName, char** const envp, + const PortableInformation& PortableInfo) { const bool IsPortable = PortableInfo.IsPortable; FEX::Config::InitializeConfigs(PortableInfo); FEXCore::Config::Initialize(); @@ -347,53 +396,7 @@ ApplicationNames LoadConfig(fextl::unique_ptr ArgsLoa } FEXCore::Config::AddLayer(CreateMainLayer()); - auto Args = ArgsLoader->Get(); - - fextl::string Program {}; - fextl::string ProgramName {}; - if (LoadProgramConfig) { - if (Args.empty()) { - // Early exit if we weren't passed an argument - return {}; - } - - Args[0] = RecoverGuestProgramFilename(std::move(Args[0]), ExecFDInterp, ProgramFDFromEnv); - Program = Args[0]; - - bool Wine = false; - for (size_t CurrentProgramNameIndex = 0; CurrentProgramNameIndex < Args.size(); ++CurrentProgramNameIndex) { - auto CurrentProgramName = FHU::Filesystem::GetFilename(Args[CurrentProgramNameIndex]); - - if (CurrentProgramName == "wine-preloader" || CurrentProgramName == "wine64-preloader") { - // Wine preloader is required to be in the format of `wine-preloader ` - // The preloader doesn't execve the executable, instead maps it directly itself - // Skip the next argument since we know it is wine (potentially with custom wine executable name) - ++CurrentProgramNameIndex; - Wine = true; - } else if (CurrentProgramName == "wine" || CurrentProgramName == "wine64") { - // Next argument, this isn't the program we want - // - // If we are running wine or wine64 then we should check the next argument for the application name instead. - // wine will change the active program name with `setprogname` or `prctl(PR_SET_NAME`. - // Since FEX needs this data far earlier than libraries we need a different check. - Wine = true; - } else { - if (Wine == true) { - // If this was path separated with '\' then we need to check that. - auto WinSeparator = CurrentProgramName.find_last_of('\\'); - if (WinSeparator != CurrentProgramName.npos) { - // Used windows separators - CurrentProgramName = CurrentProgramName.substr(WinSeparator + 1); - } - } - - ProgramName = CurrentProgramName; - - // Past any wine program names - break; - } - } - + if (!ProgramName.empty()) { if (!IsPortable) { FEXCore::Config::AddLayer(CreateAppLayer(ProgramName, FEXCore::Config::LayerType::LAYER_GLOBAL_APP)); } @@ -411,7 +414,7 @@ ApplicationNames LoadConfig(fextl::unique_ptr ArgsLoa } } - if (ArgsLoader->GetLoadType() == FEX::ArgLoader::ArgLoader::LoadType::WITH_FEXLOADER_PARSER) { + if (ArgsLoader && ArgsLoader->GetLoadType() == FEX::ArgLoader::ArgLoader::LoadType::WITH_FEXLOADER_PARSER) { FEXCore::Config::AddLayer(std::move(ArgsLoader)); } @@ -422,13 +425,6 @@ ApplicationNames LoadConfig(fextl::unique_ptr ArgsLoa FEXCore::Config::AddLayer(CreateEnvironmentLayer(envp)); FEXCore::Config::Load(); - - - if (LoadProgramConfig) { - return ApplicationNames {std::move(Program), std::move(ProgramName)}; - } else { - return {}; - } } #ifndef _WIN32 diff --git a/Source/Common/Config.h b/Source/Common/Config.h index fe3a0308c..c6b37fab8 100644 --- a/Source/Common/Config.h +++ b/Source/Common/Config.h @@ -35,18 +35,22 @@ struct PortableInformation { }; /** - * @brief Loads the FEX and application configurations for the application that is getting ready to run. - * - * @param ArgLoader Argument loader for argument based config options - * @param LoadProgramConfig Do we want to load application specific configurations? - * @param envp The `envp` passed to main(...) * @param ExecFDInterp If FEX was executed with binfmt_misc FD argument * @param ProgramFDFromEnv The execveat FD argument passed through FEX * * @return The application name and path structure */ -ApplicationNames LoadConfig(fextl::unique_ptr ArgLoader, bool LoadProgramConfig, char** const envp, - bool ExecFDInterp, int ProgramFDFromEnv, const PortableInformation& PortableInfo); +ApplicationNames GetApplicationNames(fextl::vector Args, bool ExecFDInterp, int ProgramFDFromEnv); + +/** + * @brief Loads the FEX and application configurations for the application that is getting ready to run. + * + * @param ArgLoader Optional argument loader for argument based config options + * @param ProgramName Optional program name, if non-empty application specific configurations will be loaded + * @param envp Optional `envp` passed to main(...) + */ +void LoadConfig(fextl::unique_ptr ArgLoader = {}, fextl::string ProgramName = {}, char** const envp = nullptr, + const PortableInformation& PortableInfo = {}); const char* GetHomeDirectory(); diff --git a/Source/Tools/FEXLoader/FEXLoader.cpp b/Source/Tools/FEXLoader/FEXLoader.cpp index 08ae11861..8a0b45b6a 100644 --- a/Source/Tools/FEXLoader/FEXLoader.cpp +++ b/Source/Tools/FEXLoader/FEXLoader.cpp @@ -324,13 +324,14 @@ int main(int argc, char** argv, char** const envp) { argc, argv); auto Args = ArgsLoader->Get(); auto ParsedArgs = ArgsLoader->GetParsedArgs(); - auto Program = FEX::Config::LoadConfig(std::move(ArgsLoader), true, envp, ExecutedWithFD, FEXFD, PortableInfo); - + auto Program = FEX::Config::GetApplicationNames(Args, ExecutedWithFD, FEXFD); if (Program.ProgramPath.empty() && FEXFD == -1) { // Early exit if we weren't passed an argument return 0; } + FEX::Config::LoadConfig(std::move(ArgsLoader), Program.ProgramName, envp, PortableInfo); + // Reload the meta layer FEXCore::Config::ReloadMetaLayer(); FEXCore::Config::Set(FEXCore::Config::CONFIG_IS_INTERPRETER, IsInterpreter ? "1" : "0"); diff --git a/Source/Tools/FEXRootFSFetcher/Main.cpp b/Source/Tools/FEXRootFSFetcher/Main.cpp index 9e773ee33..9ee225a43 100644 --- a/Source/Tools/FEXRootFSFetcher/Main.cpp +++ b/Source/Tools/FEXRootFSFetcher/Main.cpp @@ -1091,7 +1091,7 @@ bool ExtractEroFS(const fextl::string& Path, const fextl::string& RootFS, const int main(int argc, char** argv, char** const envp) { auto ArgsLoader = fextl::make_unique(FEX::ArgLoader::ArgLoader::LoadType::WITHOUT_FEXLOADER_PARSER, argc, argv); - FEX::Config::LoadConfig(std::move(ArgsLoader), false, envp, false, false, FEX::Config::PortableInformation {}); + FEX::Config::LoadConfig(std::move(ArgsLoader), {}, envp); // Reload the meta layer FEXCore::Config::ReloadMetaLayer(); diff --git a/Source/Tools/FEXServer/Main.cpp b/Source/Tools/FEXServer/Main.cpp index a2a8ced9c..0d1cca004 100644 --- a/Source/Tools/FEXServer/Main.cpp +++ b/Source/Tools/FEXServer/Main.cpp @@ -117,7 +117,7 @@ int main(int argc, char** argv, char** const envp) { } auto ArgsLoader = fextl::make_unique(FEX::ArgLoader::ArgLoader::LoadType::WITHOUT_FEXLOADER_PARSER, argc, argv); - FEX::Config::LoadConfig(std::move(ArgsLoader), false, envp, false, false, FEX::Config::PortableInformation {}); + FEX::Config::LoadConfig(std::move(ArgsLoader), {}, envp); // Reload the meta layer FEXCore::Config::ReloadMetaLayer(); diff --git a/Source/Windows/ARM64EC/Module.cpp b/Source/Windows/ARM64EC/Module.cpp index 21118a4d8..7319506b9 100644 --- a/Source/Windows/ARM64EC/Module.cpp +++ b/Source/Windows/ARM64EC/Module.cpp @@ -24,12 +24,14 @@ $end_info$ #include #include +#include "Common/ArgumentLoader.h" #include "Common/Config.h" #include "Common/Exception.h" #include "Common/InvalidationTracker.h" #include "Common/TSOHandlerConfig.h" #include "Common/CPUFeatures.h" #include "Common/Logging.h" +#include "Common/Module.h" #include "Common/CRT/CRT.h" #include "DummyHandlers.h" #include "BTInterface.h" @@ -456,11 +458,7 @@ extern "C" void SyncThreadContext(CONTEXT* Context) { NTSTATUS ProcessInit() { FEX::Windows::InitCRTProcess(); - FEX::Config::InitializeConfigs(FEX::Config::PortableInformation {}); - FEXCore::Config::Initialize(); - FEXCore::Config::AddLayer(FEX::Config::CreateGlobalMainLayer()); - FEXCore::Config::AddLayer(FEX::Config::CreateMainLayer()); - FEXCore::Config::Load(); + FEX::Config::LoadConfig(nullptr, FEX::Windows::GetExecutableFilePath()); FEXCore::Config::ReloadMetaLayer(); FEX::Windows::Logging::Init(); diff --git a/Source/Windows/Common/Module.h b/Source/Windows/Common/Module.h new file mode 100644 index 000000000..de5a44252 --- /dev/null +++ b/Source/Windows/Common/Module.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +#pragma once + +#include +#include +#include + +namespace FEX::Windows { +fextl::string GetExecutableFilePath() { + std::array Buf; + UNICODE_STRING PathW {.Length = 0, .MaximumLength = Buf.size() * sizeof(WCHAR), .Buffer = Buf.data()}; + + if (LdrGetDllFullName(nullptr, &PathW)) { + return {}; + } + + STRING PathA; + RtlUnicodeStringToAnsiString(&PathA, &PathW, TRUE); + fextl::string Path(PathA.Buffer); + RtlFreeAnsiString(&PathA); + + return Path.substr(Path.find_last_of('\\') + 1); +} +} // namespace FEX::Windows diff --git a/Source/Windows/WOW64/Module.cpp b/Source/Windows/WOW64/Module.cpp index ace687946..bfb53fdb4 100644 --- a/Source/Windows/WOW64/Module.cpp +++ b/Source/Windows/WOW64/Module.cpp @@ -25,12 +25,14 @@ $end_info$ #include #include +#include "Common/ArgumentLoader.h" #include "Common/Config.h" #include "Common/Exception.h" #include "Common/TSOHandlerConfig.h" #include "Common/InvalidationTracker.h" #include "Common/CPUFeatures.h" #include "Common/Logging.h" +#include "Common/Module.h" #include "Common/CRT/CRT.h" #include "DummyHandlers.h" #include "BTInterface.h" @@ -424,11 +426,7 @@ public: void BTCpuProcessInit() { FEX::Windows::InitCRTProcess(); - FEX::Config::InitializeConfigs(FEX::Config::PortableInformation {}); - FEXCore::Config::Initialize(); - FEXCore::Config::AddLayer(FEX::Config::CreateGlobalMainLayer()); - FEXCore::Config::AddLayer(FEX::Config::CreateMainLayer()); - FEXCore::Config::Load(); + FEX::Config::LoadConfig(nullptr, FEX::Windows::GetExecutableFilePath()); FEXCore::Config::ReloadMetaLayer(); FEX::Windows::Logging::Init(); diff --git a/Source/Windows/include/winternl.h b/Source/Windows/include/winternl.h index d9dca52f9..81c938006 100644 --- a/Source/Windows/include/winternl.h +++ b/Source/Windows/include/winternl.h @@ -433,6 +433,7 @@ typedef struct _KEY_VALUE_PARTIAL_INFORMATION { NTSTATUS WINAPIV DbgPrint(LPCSTR fmt, ...); NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE); +NTSTATUS WINAPI LdrGetDllFullName(HMODULE, UNICODE_STRING*); NTSTATUS WINAPI LdrGetDllHandle(LPCWSTR, ULONG, const UNICODE_STRING*, HMODULE*); NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE, const ANSI_STRING*, ULONG, void**); NTSTATUS WINAPI NtAllocateVirtualMemoryEx(HANDLE, PVOID*, SIZE_T*, ULONG, ULONG, MEM_EXTENDED_PARAMETER*, ULONG);