Win32 C API:替代损坏的 execl*() 函数族?
Win32 C API: Alternative to broken execl*() family of functions?
因此,在 Windows 上,execl() 似乎在 windows 的不同版本中以不同的方式被破坏。我花了很多时间缩小范围和调试,但它确实没有意义,我只能认为微软的 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
使用 "handles" 并且这些可以标记为可继承的,例如我对管道执行以下操作:
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: %lu\n", GetLastError());
return;
}
这样,管道的句柄是可继承的。然后,当调用 CreateProcess()
时,通过为 bInheritHandles
传递 1
(或 TRUE
),新进程继承所有以这种方式标记的句柄。在此示例中,我执行以下操作:
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);
在child中,管道可以这样使用:
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);
当然,对于网络套接字,这看起来会有所不同,但我希望总体思路有所帮助。
因此,在 Windows 上,execl() 似乎在 windows 的不同版本中以不同的方式被破坏。我花了很多时间缩小范围和调试,但它确实没有意义,我只能认为微软的 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
使用 "handles" 并且这些可以标记为可继承的,例如我对管道执行以下操作:
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: %lu\n", GetLastError());
return;
}
这样,管道的句柄是可继承的。然后,当调用 CreateProcess()
时,通过为 bInheritHandles
传递 1
(或 TRUE
),新进程继承所有以这种方式标记的句柄。在此示例中,我执行以下操作:
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);
在child中,管道可以这样使用:
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);
当然,对于网络套接字,这看起来会有所不同,但我希望总体思路有所帮助。