aboutsummaryrefslogtreecommitdiff
path: root/zencore/thread.cpp
diff options
context:
space:
mode:
authorMartin Ridgers <[email protected]>2021-11-16 14:35:49 +0100
committerMartin Ridgers <[email protected]>2021-11-16 14:39:00 +0100
commit688d88a4d92d6c316b248715a9d19ef65f3279ac (patch)
tree12089228705408e910512182a7007ab02deea132 /zencore/thread.cpp
parentAdded a ZEN_EXE_STRING_LITERAL for cross-platform path building (diff)
downloadzen-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.cpp119
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()
{