Win32 C API:替代损坏的execl*()系列函数?

Win32 C API: Alternative to broken execl*() family of functions?

本文关键字:系列 函数 execl API 损坏 Win32      更新时间:2023-10-16

所以,在Windows上,execl()似乎在不同的Windows版本中以不同的方式被破坏。我花了很多时间来缩小范围和调试,这并没有真正的意义,我只能认为Microsoft的execl()(实际上是execlp()对我来说)的实现有问题。

唯一的Windows版本execlp()似乎在7上正常工作。

在Windows 10上,它工作正常,直到我在MinGW中使用-mwindows进行编译。 然后它只是让我的程序以零退出代码终止。

在 Windows XP 上,它将参数参数中的空格解释为单独的参数,尽管函数原型的性质明确指定了参数的实际数量......

所以,看起来我将不得不使用一些Windows本机函数并将其包装在"#ifdef WIN32"中。

我真正需要的是 execl()(execlp 不是必需的)类似于 Windows 上的行为,因为它用新的进程映像替换当前进程映像,并像 execl() 一样保持网络描述符打开。

我真的不知道什么是好的选择,虽然 CreateProcess 似乎在某种程度上能够做到这一点,但我找不到足够的信息来说明我正在尝试做什么。

任何帮助,不胜感激。谢谢!

不幸的是,您将需要在Windows上使用完全不同的代码路径,因为在win32子系统中,创建进程与在单个调用中加载和运行新映像耦合在一起:CreateProcess()

在典型的 posix 场景中,您将fork()新进程,设置诸如文件描述符之类的内容,然后exec*()新的二进制文件。要在 Windows 中实现类似的东西,您必须依靠从中获得的可能性CreateProcess().对于打开的文件(或套接字),win32使用"句柄",这些句柄可以标记为可继承,例如,我对管道执行以下操作:

HANDLE pin, pout;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = 0;
sa.bInheritHandle = 1;
if (!CreatePipe(&pin, &pout, &sa, 0))
{
fprintf(stderr, "Error creating pipe: %lun", GetLastError());
return;
}

这样,管道的句柄是可继承的。然后,当调用CreateProcess()时,通过传递1(或TRUE)bInheritHandles,新进程继承所有以这种方式标记的句柄。在此示例中,我执行以下操作:

STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.hStdInput = nul;
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
si.dwFlags |= STARTF_USESTDHANDLES;
// simple example, my production code looks different, e.g. quoting the command:
char cmdline[1024];
strcpy(cmdline, exename);
strcat(cmdline, " ");
snprintf(cmdline + strlen(cmdline), 1024 - strlen(cmdline), "%" PRIxPTR, (uintptr_t)pout);
// [...]
PROCESS_INFORMATION pi;
CreateProcess(0, cmdline, 0, 0, 1, 0, 0, 0, &si, &pi);

在孩子身上,管道可以这样使用:

uintptr_t testPipeHandleValue;
if (sscanf(argv[1], "%" SCNxPTR, &testPipeHandleValue) != 1)
{
exit(EXIT_FAILURE);
}
int testPipeFd = _open_osfhandle(
(intptr_t)testPipeHandleValue, _O_APPEND | _O_WRONLY);
FILE *testPipe = _fdopen(testPipeFd, "a");
setvbuf(testPipe, 0, _IONBF, 0);

当然,对于网络套接字来说,这看起来会有所不同,但我希望总体思路有所帮助。