首页 > 解决方案 > 具有 2 个重定向管道的 CreateProcess 返回退出代码 1

问题描述

我是 WIN32 API 的新手,可以使用一些帮助来确定我的代码中缺少什么。我的目标是运行批处理脚本(或 PowerShell 脚本),等待完成,然后在完成后获取 stdout / stderr。

按照这个和msdn 上的这篇文章,关于创建进程并将 stdout 和 stderr 重定向到句柄。我这些样本混合在一起,并提出了以下代码:

int execute_commnad(std::string& command,std::string& output,int& timeout_seconds) {
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    DWORD return_code = NULL;

    ZeroMemory(&pi, sizeof(pi));

    ZeroMemory(&si,sizeof(si));
    si.cb = sizeof(si);
    si.hStdOutput = child_stdout_handle;
    si.hStdError = child_stdout_handle;
    si.dwFlags |= STARTF_USESTDHANDLES;

    SECURITY_ATTRIBUTES saAttr;
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;

    // Connect Child stdout to parent_stdout_handle
    if (!CreatePipe(&parent_stdout_handle,&child_stdout_handle,&saAttr,0))
    {
        output = "Could not create stdout pipe. Error: " + std::to_string(GetLastError());
        close_handles();
        return -1;
    }

    if (! SetHandleInformation(parent_stdout_handle,HANDLE_FLAG_INHERIT,0))
    {
        output = "Could not set handle information for stdout pipe. Error: " + std::to_string(GetLastError());
        close_handles();
        return -1;
    }

    // Create Process
    if (!CreateProcess(NULL,LPSTR(command.c_str()),NULL,NULL,TRUE,0,NULL,NULL,&si,&pi)) {
        output = "Failed to create process. Error: " + std::to_string(GetLastError());
        close_handles();
        return -1;
    }
    CloseHandle(child_stdout_handle);


    // Wait for process to finish or timeout
    if (timeout_seconds == NULL) {
        WaitForSingleObject(pi.hProcess,INFINITE);
    }
    else {
        WaitForSingleObject(pi.hProcess,DWORD(timeout_seconds * 1000));
    }
    
    if (!GetExitCodeProcess(pi.hProcess,&return_code)) {
        output = "Failed to fetch exit code";
        close_handles();
        return -1;
    }
    
    if (STILL_ACTIVE == return_code) {
        TerminateProcess(sub_process,return_code);
        output = "Command did not finish within defined timeout threshold";
    }
    else if (STATUS_PENDING == return_code) {
        output = "process is pending";
    }
    else {
        DWORD dwRead;
        CHAR chBuf[4096];
        BOOL bSuccess = FALSE;

        for (;;) {
            bSuccess = ReadFile(parent_stdout_handle,chBuf,4096,&dwRead,NULL);
            if (! bSuccess || dwRead == 0) break;
            output = *reinterpret_cast<std::string*>(parent_stdout_handle);
        }
    }
    
    close_handles();
    return 0;    
};


void close_handles(void) {
    CloseHandle(parent_stdout_handle);
    CloseHandle(child_stdout_handle);
    CloseHandle(sub_process);
};

在执行上面的函数之前,我使用std::ofstream包含“echo hello”创建了 .bat 文件,并将文件的 FQN 保存到名为的变量中file_name并运行以下代码:

int rc = 0;
std::string cmd = "cmd.exe /c " + file_name + " " + script_params;
rc = execute_commnad(cmd,this->output,timeout_in_seconds);

调试时,这些是我得到的值GetExitCodeProcess

我尝试用cmd.exeFQN 替换,但结果相同,尝试运行一些简单的东西,但cmd.exe /c "echo hello"仍然返回 return_code 1。

过去两天我一直在努力寻找原因,但无济于事。

除了无效的代码(性能方面)之外,是否有人对可能出现的问题提出建议?

提前致谢!

标签: c++windowswinapicreateprocess

解决方案


确保child_stdout_handle在将句柄传递给CreateProcess.

此外,您需要打印chBuf您读入的值ReadFile,而不是parent_stdout_handle. 将文件句柄转换string为没有意义,您可以尝试:

    for (;;) {
        bSuccess = ReadFile(parent_stdout_handle, chBuf, 4096, &dwRead, NULL);
        if (!bSuccess || dwRead == 0) break;
        chBuf[dwRead] = '\0';
        output += chBuf;
    }
    cout << output << endl;

推荐阅读