【问题标题】:Win32 C API: Alternative to broken execl*() family of functions?Win32 C API:替代损坏的 execl*() 系列函数?
【发布时间】:2017-05-22 06:28:12
【问题描述】:

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

似乎唯一可以正常工作的 Windows 版本 execlp() 是 7。

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

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

所以,看来我必须使用一些 Windows 原生函数并将其包装在“#ifdef WIN32”中。

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

我真的不知道有什么好的选择,虽然 CreateProcess 似乎可以做一些事情,但我找不到足够的信息来说明我正在尝试做的事情。

感谢任何帮助。谢谢!

【问题讨论】:

  • Windows 并不真正支持这种 *nix 编码风格。 CreateProcess 是您创建新流程的方式。
  • 您能否提供一个在 Windows 10 上“工作”但与 MinGW 中断的代码示例?
  • Windows 中“posix”函数的行为与 *nix 系统之一不匹配。还有一些特殊的路径格式,例如特定于 Windows 和行为更改\从版本到版本的扩展.. 从你说它在 Win7 中工作的判断来看,你确实遇到了这个问题。在 MinGW 中,您将使用 POSIX 库,包括 unistd.h ,路径也将被斜杠,而不是反斜杠(例如“D:/Windows/System32”),您应该为 execl 指定第三个参数
  • Windows XP 的行为与预期一致,并且 execl() 在 Windows 7 和 Windows 10 中的行为方式应该相同,as documented。 Windows 进程接收表示命令行的单个字符串,而不是像 *nix 进程那样的字符串数组;如果要传递包含空格的参数,则必须知道子进程将使用什么解析逻辑。
  • 对于套接字描述符,默认情况下它们是可继承的,尽管this question 表示某些第三方产品可能会导致此中断。这应该不再是一个大问题了。 LSP 已弃用。只要您告诉 CreateProcess 允许继承,您应该就可以了。

标签: c++ c winapi exec


【解决方案1】:

不幸的是,您需要在 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: %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);

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

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);

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多