=> 433948ee94198b8b60260143d6e9af43a7f2d883
[1mdiff --git a/include/the_Foundation/process.h b/include/the_Foundation/process.h[m [1mindex d570a00..aff48f9 100644[m [1m--- a/include/the_Foundation/process.h[m [1m+++ b/include/the_Foundation/process.h[m [36m@@ -31,7 +31,7 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.[m #include[m [m #if defined (iPlatformWindows)[m [31m-typedef int iProcessId;[m [32m+[m[32mtypedef unsigned int iProcessId;[m #else[m typedef pid_t iProcessId;[m #endif[m [1mdiff --git a/src/platform/win32/process.c b/src/platform/win32/process.c[m [1mindex 097a7c9..df1b5a9 100644[m [1m--- a/src/platform/win32/process.c[m [1m+++ b/src/platform/win32/process.c[m [36m@@ -1,6 +1,6 @@[m /** @file win32/process.c Execute and communicate with child processes.[m [m [31m-@authors Copyright (c) 2019 Jaakko Keränen [m [32m+[m[32m@authors Copyright (c) 2019-2023 Jaakko Keränen [m [m @par License[m [m [36m@@ -26,45 +26,73 @@[m [mSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.[m */[m [m #include "the_Foundation/process.h"[m [32m+[m [32m+[m[32m#include "the_Foundation/block.h"[m #include "the_Foundation/stringlist.h"[m [31m-#include "the_Foundation/path.h"[m [32m+[m[32m#include "pipe.h"[m [32m+[m[32m#include "wide.h"[m [m #define WIN32_LEAN_AND_MEAN[m #include [m [m [31m-// #include [m [31m-// #include [m [31m-// #include [m [31m-// #include [m [31m-// #include [m [31m-[m struct Impl_Process {[m iObject object;[m [32m+[m[32m DWORD pid;[m iStringList *args;[m [32m+[m[32m iStringList *envMods;[m iString workDir;[m [32m+[m[32m iPipe pin;[m [32m+[m[32m iPipe pout;[m [32m+[m[32m iPipe perr;[m PROCESS_INFORMATION procInfo;[m [31m- // iPipe pout;[m [31m- // iPipe perr;[m [32m+[m[32m STARTUPINFOW startInfo;[m [32m+[m[32m int exitStatus;[m };[m [m iDefineObjectConstruction(Process)[m iDefineClass(Process)[m [m [31m-extern char **environ; // The environment variables.[m [31m-[m void init_Process(iProcess *d) {[m [31m- d->args = new_StringList();[m [32m+[m[32m d->pid = 0;[m [32m+[m[32m d->args = new_StringList();[m [32m+[m[32m d->envMods = new_StringList();[m init_String(&d->workDir);[m [32m+[m[32m init_Pipe(&d->pin);[m [32m+[m[32m init_Pipe(&d->pout);[m [32m+[m[32m init_Pipe(&d->perr);[m iZap(d->procInfo);[m [31m- // init_Pipe(&d->pout);[m [31m- // init_Pipe(&d->perr);[m [32m+[m[32m d->startInfo = (STARTUPINFOW){[m [32m+[m[32m .cb = sizeof(d->startInfo),[m [32m+[m[32m .hStdError = input_Pipe(&d->perr),[m [32m+[m[32m .hStdOutput = input_Pipe(&d->pout),[m [32m+[m[32m .hStdInput = output_Pipe(&d->pin),[m [32m+[m[32m .dwFlags = STARTF_USESTDHANDLES,[m [32m+[m[32m };[m [32m+[m[32m d->exitStatus = 0;[m [32m+[m[32m /* Child must not inherit our end of the pipes. */[m [32m+[m[32m SetHandleInformation(output_Pipe(&d->pout), HANDLE_FLAG_INHERIT, 0);[m [32m+[m[32m SetHandleInformation(output_Pipe(&d->perr), HANDLE_FLAG_INHERIT, 0);[m [32m+[m[32m SetHandleInformation(input_Pipe(&d->pin), HANDLE_FLAG_INHERIT, 0);[m [32m+[m[32m /* Non-blocking stdout and stderr. */ {[m [32m+[m[32m DWORD mode = PIPE_NOWAIT;[m [32m+[m[32m SetNamedPipeHandleState(output_Pipe(&d->pout), &mode, NULL, NULL);[m [32m+[m[32m SetNamedPipeHandleState(output_Pipe(&d->perr), &mode, NULL, NULL);[m [32m+[m[32m }[m [32m+[m }[m [m void deinit_Process(iProcess *d) {[m [32m+[m[32m if (d->pid) {[m [32m+[m[32m if (d->procInfo.hProcess != INVALID_HANDLE_VALUE) {[m [32m+[m[32m CloseHandle(d->procInfo.hProcess);[m [32m+[m[32m }[m [32m+[m[32m }[m iRelease(d->args);[m [32m+[m[32m iRelease(d->envMods);[m deinit_String(&d->workDir);[m [31m- // deinit_Pipe(&d->pout);[m [31m- // deinit_Pipe(&d->perr);[m [32m+[m[32m deinit_Pipe(&d->pin);[m [32m+[m[32m deinit_Pipe(&d->pout);[m [32m+[m[32m deinit_Pipe(&d->perr);[m }[m [m void setArguments_Process(iProcess *d, const iStringList *args) {[m [36m@@ -74,101 +102,189 @@[m [mvoid setArguments_Process(iProcess *d, const iStringList *args) {[m }[m }[m [m [32m+[m[32mvoid setEnvironment_Process(iProcess *d, const iStringList *env) {[m [32m+[m[32m clear_StringList(d->envMods);[m [32m+[m[32m iConstForEach(StringList, i, env) {[m [32m+[m[32m pushBack_StringList(d->envMods, i.value);[m [32m+[m[32m }[m [32m+[m[32m}[m [32m+[m void setWorkingDirectory_Process(iProcess *d, const iString *cwd) {[m set_String(&d->workDir, cwd);[m }[m [m iBool start_Process(iProcess *d) {[m [31m- // posix_spawn_file_actions_t facts;[m [31m- // int rc;[m [31m- // const char **argv;[m [31m- // iString *oldCwd = cwd_Path();[m [31m- // setCwd_Path(&d->workDir);[m [31m- // argv = malloc(sizeof(char *) * (size_StringList(d->args) + 1));[m [31m- // for (size_t i = 0; i < size_StringList(d->args); ++i) {[m [31m- // argv[i] = cstr_String(at_StringList(d->args, i));[m [31m- // }[m [31m- // argv[size_StringList(d->args)] = NULL;[m [31m- // // Use pipes to redirect the child's stdout/stderr to us.[m [31m- // posix_spawn_file_actions_init(&facts);[m [31m- // posix_spawn_file_actions_addclose(&facts, output_Pipe(&d->pout));[m [31m- // posix_spawn_file_actions_addclose(&facts, output_Pipe(&d->perr));[m [31m- // posix_spawn_file_actions_adddup2 (&facts, input_Pipe(&d->pout), 1); // stdout[m [31m- // posix_spawn_file_actions_adddup2 (&facts, input_Pipe(&d->perr), 2); // stderr[m [31m- // posix_spawn_file_actions_addclose(&facts, input_Pipe(&d->pout));[m [31m- // posix_spawn_file_actions_addclose(&facts, input_Pipe(&d->perr));[m [31m- // // Start the child process.[m [31m- // rc = posix_spawn(&d->pid, argv[0], &facts, NULL, iConstCast(char **, argv), environ);[m [31m- // free(argv);[m [31m- // setCwd_Path(oldCwd);[m [31m- // delete_String(oldCwd);[m [31m- // posix_spawn_file_actions_destroy(&facts);[m [31m- // return rc == 0;[m [31m- return iFalse;[m [32m+[m[32m LPVOID envs = NULL;[m [32m+[m[32m iString *cmdLine = new_String();[m [32m+[m[32m /* Build the command line, quoting arguments as needed. */ {[m [32m+[m[32m iConstForEach(StringList, i, d->args) {[m [32m+[m[32m iString *arg = copy_String(i.value);[m [32m+[m[32m if (contains_String(arg, ' ') || contains_String(arg, '"')) {[m [32m+[m[32m replace_String(arg, "\\", "\\\\");[m [32m+[m[32m replace_String(arg, "\"", "\\\"");[m [32m+[m[32m prependCStr_String(arg, "\"");[m [32m+[m[32m appendCStr_String(arg, "\"");[m [32m+[m[32m }[m [32m+[m[32m if (!isEmpty_String(cmdLine)) {[m [32m+[m[32m appendCStr_String(cmdLine, " ");[m [32m+[m[32m }[m [32m+[m[32m append_String(cmdLine, arg);[m [32m+[m[32m delete_String(arg);[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m printf("cmdline: %s\n", cstr_String(cmdLine));[m [32m+[m[32m /* The environment. */[m [32m+[m[32m if (!isEmpty_StringList(d->envMods)) {[m [32m+[m[32m //iBlock *env = collect_Block(new_Block(0));[m [32m+[m[32m /* TODO: Compose the new environment strings */[m [32m+[m[32m#if 0[m [32m+[m[32m for (const char *envList = GetEnvironmentStringsA(); *envList; ) {[m [32m+[m[32m size_t len = strlen(envList);[m [32m+[m[32m pushBack_Array(env, e);[m [32m+[m[32m }[m [32m+[m[32m iConstForEach(StringList, e, d->envMods) {[m [32m+[m[32m pushBack_Array(env, &(const char *){ cstr_String(e.value) });[m [32m+[m[32m }[m [32m+[m[32m pushBack_Array(env, &(const char *){ NULL });[m [32m+[m[32m envs = (LPVOID) data_Array(env);[m [32m+[m[32m#endif[m [32m+[m[32m }[m [32m+[m[32m DWORD creationFlags = 0;[m [32m+[m[32m BOOL ok = CreateProcessW([m [32m+[m[32m NULL,[m [32m+[m[32m (LPWSTR) toWide_CStr_(cstr_String(cmdLine)),[m [32m+[m[32m NULL,[m [32m+[m[32m NULL,[m [32m+[m[32m TRUE,[m [32m+[m[32m creationFlags,[m [32m+[m[32m envs,[m [32m+[m[32m !isEmpty_String(&d->workDir) ? toWide_CStr_(cstr_String(&d->workDir)) : NULL,[m [32m+[m[32m &d->startInfo,[m [32m+[m[32m &d->procInfo[m [32m+[m[32m );[m [32m+[m[32m if (ok) {[m [32m+[m[32m d->pid = d->procInfo.dwProcessId;[m [32m+[m[32m /* These were inherited by the child, so we won't need them any longer. */[m [32m+[m[32m CloseHandle(input_Pipe(&d->pout));[m [32m+[m[32m CloseHandle(input_Pipe(&d->perr));[m [32m+[m[32m CloseHandle(output_Pipe(&d->pin));[m [32m+[m[32m CloseHandle(d->procInfo.hThread);[m [32m+[m[32m }[m [32m+[m[32m else {[m [32m+[m[32m iWarning("[Process] spawn error: (%x) %s\n", GetLastError(), errorMessage_Windows_(GetLastError()));[m [32m+[m[32m d->procInfo.hProcess = INVALID_HANDLE_VALUE;[m [32m+[m[32m d->procInfo.hThread = INVALID_HANDLE_VALUE;[m [32m+[m[32m }[m [32m+[m[32m deinit_String(cmdLine);[m [32m+[m[32m return ok ? iTrue : iFalse;[m }[m [m iProcessId pid_Process(const iProcess *d) {[m [31m- // if (d) {[m [31m- // return d->pid;[m [31m- // }[m [31m- // return getpid();[m [31m- return 0;[m [32m+[m[32m if (d) {[m [32m+[m[32m return d->pid;[m [32m+[m[32m }[m [32m+[m[32m return GetCurrentProcessId();[m }[m [m iBool isRunning_Process(const iProcess *d) {[m [31m- return iFalse;[m [31m- // if (!d->pid) return iFalse;[m [31m- // int status = 0;[m [31m- // pid_t res = wait4(d->pid, &status, WNOHANG, NULL);[m [31m- // if (res == 0) {[m [31m- // return iTrue;[m [31m- // }[m [31m- // iConstCast(iProcess *, d)->pid = 0;[m [31m- // return iFalse;[m [32m+[m[32m if (!d->pid) return iFalse;[m [32m+[m[32m if (!exists_Process(d->pid)) {[m [32m+[m[32m iConstCast(iProcess *, d)->pid = 0;[m [32m+[m[32m return iFalse;[m [32m+[m[32m }[m [32m+[m[32m return iTrue;[m [32m+[m[32m}[m [32m+[m [32m+[m[32mint exitStatus_Process(const iProcess *d) {[m [32m+[m[32m return d->exitStatus;[m }[m [m void waitForFinished_Process(iProcess *d) {[m [31m- // if (!d->pid) return;[m [31m- // waitpid(d->pid, NULL, 0);[m [31m- // d->pid = 0;[m [31m-}[m [31m-[m [31m-// static iString *readFromPipe_(int fd, iString *readChars) {[m [31m-// char buf[4096];[m [31m-// struct pollfd pfd = {.fd = fd, .events = POLLIN};[m [31m-// while (poll(&pfd, 1, 0) == 1) { // non-blocking[m [31m-// if (pfd.revents & POLLIN) {[m [31m-// ssize_t num = read(fd, buf, sizeof(buf));[m [31m-// if (num > 0) {[m [31m-// appendData_Block(&readChars->chars, buf, num);[m [31m-// }[m [31m-// else break;[m [31m-// }[m [31m-// else break;[m [31m-// }[m [31m-// return readChars;[m [31m-// }[m [32m+[m[32m if (d->pid) {[m [32m+[m[32m DWORD exitCode = 0;[m [32m+[m[32m WaitForSingleObject(d->procInfo.hProcess, INFINITE);[m [32m+[m[32m GetExitCodeProcess(d->procInfo.hProcess, &exitCode);[m [32m+[m[32m d->exitStatus = exitCode;[m [32m+[m[32m d->pid = 0;[m [32m+[m[32m }[m [32m+[m[32m}[m [m size_t writeInput_Process(iProcess *d, const iBlock *data) {[m [31m- return 0;[m [32m+[m[32m const char *ptr = constBegin_Block(data);[m [32m+[m[32m DWORD remain = size_Block(data);[m [32m+[m[32m while (remain) {[m [32m+[m[32m DWORD num = 0;[m [32m+[m[32m if (!WriteFile(input_Pipe(&d->pin), ptr, remain, &num, NULL)) {[m [32m+[m[32m break;[m [32m+[m[32m }[m [32m+[m[32m ptr += num;[m [32m+[m[32m remain -= num;[m [32m+[m[32m }[m [32m+[m[32m return size_Block(data) - remain;[m [32m+[m[32m}[m [32m+[m [32m+[m[32mstatic iBlock *readFromPipe_(HANDLE pipe, iBlock *readChars) {[m [32m+[m[32m char buf[4096];[m [32m+[m[32m DWORD num = 0;[m [32m+[m[32m while (ReadFile(pipe, buf, sizeof(buf), &num, NULL)) {[m [32m+[m[32m appendData_Block(readChars, buf, num);[m [32m+[m[32m }[m [32m+[m[32m return readChars;[m }[m [m iBlock *readOutput_Process(iProcess *d) {[m [31m- // return readFromPipe_(output_Pipe(&d->pout), new_String());[m [31m- return new_Block(0);[m [32m+[m[32m return readFromPipe_(output_Pipe(&d->pout), new_Block(0));[m }[m [m iBlock *readError_Process(iProcess *d) {[m [31m- // return readFromPipe_(output_Pipe(&d->perr), new_String());[m [31m- return new_Block(0);[m [32m+[m[32m return readFromPipe_(output_Pipe(&d->perr), new_Block(0));[m }[m [m [31m-iBlock *readOutputUntilClosed_Process(iProcess *d) {[m [31m- return new_Block(0);[m [32m+[m[32mvoid kill_Process(iProcess *d) {[m [32m+[m[32m if (d->pid) {[m [32m+[m[32m TerminateProcess(d->procInfo.hProcess, (UINT) -1);[m [32m+[m[32m }[m }[m [m [31m-void kill_Process(iProcess *d) {[m [31m- // if (d->pid) {[m [31m- // kill(d->pid, SIGTERM);[m [31m- // }[m [32m+[m[32miBlock *readOutputUntilClosed_Process(iProcess *d) {[m[41m [m [32m+[m[32m iBlock *output = new_Block(0);[m [32m+[m[32m if (!d->pid) {[m [32m+[m[32m return output;[m [32m+[m[32m }[m [32m+[m[32m HANDLE fd = output_Pipe(&d->pout);[m [32m+[m[32m //DWORD mode = PIPE_WAIT;[m [32m+[m[32m //SetNamedPipeHandleState(fd, &mode, NULL, NULL); /* blocking mode */[m [32m+[m[32m CloseHandle(input_Pipe(&d->pin)); /* no more input */[m [32m+[m[32m for (;;) {[m [32m+[m[32m char buf[0x20000];[m [32m+[m[32m DWORD len = 0;[m [32m+[m[32m if (ReadFile(fd, buf, sizeof(buf), &len, NULL)) {[m [32m+[m[32m appendData_Block(output, buf, len);[m [32m+[m[32m if (len > 0) {[m [32m+[m[32m continue;[m [32m+[m[32m }[m [32m+[m[32m else {[m [32m+[m[32m break;[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m const DWORD err = GetLastError();[m [32m+[m[32m //iDebug("error (%x) %s\n", err, errorMessage_Windows_(err));[m [32m+[m[32m if (err == ERROR_PIPE_NOT_CONNECTED || err == ERROR_BROKEN_PIPE) {[m [32m+[m[32m break;[m [32m+[m[32m }[m [32m+[m[32m }[m [32m+[m[32m iString str;[m [32m+[m[32m initBlock_String(&str, output);[m [32m+[m[32m deinit_String(&str);[m [32m+[m[32m return output;[m [32m+[m[32m}[m [32m+[m [32m+[m[32miBool exists_Process(iProcessId pid) {[m [32m+[m[32m if (!pid) return iFalse;[m [32m+[m[32m HANDLE proc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);[m [32m+[m[32m if (proc) {[m [32m+[m[32m CloseHandle(proc);[m [32m+[m[32m return iTrue;[m [32m+[m[32m }[m [32m+[m[32m return iFalse;[m }[m
text/gemini; charset=utf-8
This content has been proxied by September (ba2dc).