diff options
Diffstat (limited to 'zencore')
| -rw-r--r-- | zencore/include/zencore/thread.h | 26 | ||||
| -rw-r--r-- | zencore/thread.cpp | 119 |
2 files changed, 145 insertions, 0 deletions
diff --git a/zencore/include/zencore/thread.h b/zencore/include/zencore/thread.h index 6727e5029..f0fc55413 100644 --- a/zencore/include/zencore/thread.h +++ b/zencore/include/zencore/thread.h @@ -6,6 +6,7 @@ #include <shared_mutex> +#include <filesystem> #include <string_view> #include <vector> @@ -174,6 +175,31 @@ private: int m_Pid = 0; }; +/** Basic process creation + */ +struct CreateProcOptions +{ + enum + { + Flag_NewConsole = 1 << 0, + Flag_Elevated = 1 << 1, + }; + + const std::filesystem::path* WorkingDirectory = nullptr; + uint32_t Flags = 0; +}; + +#if ZEN_PLATFORM_WINDOWS + using CreateProcResult = void*; // handle to the process +#else + using CreateProcResult = int32_t; // pid +#endif + +ZENCORE_API CreateProcResult CreateProc( + const std::filesystem::path& Executable, + std::string_view CommandLine, // should also include arg[0] (executable name) + const CreateProcOptions& Options={}); + /** Process monitor - monitors a list of running processes via polling Intended to be used to monitor a set of "sponsor" processes, where 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() { |