diff options
| author | Martin Ridgers <[email protected]> | 2021-11-16 14:35:49 +0100 |
|---|---|---|
| committer | Martin Ridgers <[email protected]> | 2021-11-16 14:39:00 +0100 |
| commit | 688d88a4d92d6c316b248715a9d19ef65f3279ac (patch) | |
| tree | 12089228705408e910512182a7007ab02deea132 /zencore/thread.cpp | |
| parent | Added a ZEN_EXE_STRING_LITERAL for cross-platform path building (diff) | |
| download | zen-688d88a4d92d6c316b248715a9d19ef65f3279ac.tar.xz zen-688d88a4d92d6c316b248715a9d19ef65f3279ac.zip | |
Added a zen::CreateProc() function for spawning child processes
Diffstat (limited to 'zencore/thread.cpp')
| -rw-r--r-- | zencore/thread.cpp | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/zencore/thread.cpp b/zencore/thread.cpp index 7f8042ae0..e155d2ab2 100644 --- a/zencore/thread.cpp +++ b/zencore/thread.cpp @@ -7,6 +7,7 @@ #include <zencore/testing.h> #if ZEN_PLATFORM_WINDOWS +# include <shellapi.h> # include <zencore/windows.h> #elif ZEN_PLATFORM_LINUX # include <chrono> @@ -576,6 +577,124 @@ ProcessHandle::Wait(int TimeoutMs) ////////////////////////////////////////////////////////////////////////// #if ZEN_PLATFORM_WINDOWS +static CreateProcResult CreateProcNormal( + const std::filesystem::path& Executable, + std::string_view CommandLine, + const CreateProcOptions& Options) +{ + PROCESS_INFORMATION ProcessInfo{}; + STARTUPINFO StartupInfo{.cb = sizeof(STARTUPINFO)}; + + const bool InheritHandles = false; + void* Environment = nullptr; + LPSECURITY_ATTRIBUTES ProcessAttributes = nullptr; + LPSECURITY_ATTRIBUTES ThreadAttributes = nullptr; + + DWORD CreationFlags = 0; + if (Options.Flags & CreateProcOptions::Flag_NewConsole) + { + CreationFlags |= CREATE_NEW_CONSOLE; + } + + const wchar_t* WorkingDir = nullptr; + if (Options.WorkingDirectory != nullptr) + { + WorkingDir = Options.WorkingDirectory->c_str(); + } + + ExtendableWideStringBuilder<256> CommandLineZ; + CommandLineZ << CommandLine; + + BOOL Success = CreateProcessW(Executable.c_str(), + CommandLineZ.Data(), + ProcessAttributes, + ThreadAttributes, + InheritHandles, + CreationFlags, + Environment, + WorkingDir, + &StartupInfo, + &ProcessInfo); + + if (!Success) + { + return nullptr; + } + + CloseHandle(ProcessInfo.hThread); + return ProcessInfo.hProcess; +} + +static CreateProcResult CreateProcElevated( + const std::filesystem::path& Executable, + std::string_view CommandLine, + const CreateProcOptions& Options) +{ + ExtendableWideStringBuilder<256> CommandLineZ; + CommandLineZ << CommandLine; + + SHELLEXECUTEINFO ShellExecuteInfo; + ZeroMemory(&ShellExecuteInfo, sizeof(ShellExecuteInfo)); + ShellExecuteInfo.cbSize = sizeof(ShellExecuteInfo); + ShellExecuteInfo.fMask = SEE_MASK_UNICODE | SEE_MASK_NOCLOSEPROCESS; + ShellExecuteInfo.lpFile = Executable.c_str(); + ShellExecuteInfo.lpVerb = TEXT("runas"); + ShellExecuteInfo.nShow = SW_SHOW; + ShellExecuteInfo.lpParameters = CommandLineZ.c_str(); + + if (Options.WorkingDirectory != nullptr) + { + ShellExecuteInfo.lpDirectory = Options.WorkingDirectory->c_str(); + } + + if (::ShellExecuteEx(&ShellExecuteInfo)) + { + return ShellExecuteInfo.hProcess; + } + + return nullptr; +} +#endif // ZEN_PLATFORM_WINDOWS + +CreateProcResult CreateProc( + const std::filesystem::path& Executable, + std::string_view CommandLine, + const CreateProcOptions& Options) +{ +#if ZEN_PLATFORM_WINDOWS + if (Options.Flags & CreateProcOptions::Flag_Elevated) + { + return CreateProcElevated(Executable, CommandLine, Options); + } + + return CreateProcNormal(Executable, CommandLine, Options); +#else + int ChildPid = fork(); + if (ChildPid < 0) + { + ThrowLastError("Failed to fork a new child process"); + } + else + { + if (Options.WorkingDirectory != nullptr) + { + chdir(Options.WorkingDirectory->c_str()); + } + + std::string CommandLineZ(CommandLine); + if (execl(Executable.c_str(), CommandLineZ.c_str(), nullptr) < 0) + { + ThrowLastError("Failed to exec() a new process image"); + } + } + + return ChildPid; +#endif +} + +////////////////////////////////////////////////////////////////////////// + +#if ZEN_PLATFORM_WINDOWS ProcessMonitor::ProcessMonitor() { |