Windows CreateProcess 和输出重定向

Posted

技术标签:

【中文标题】Windows CreateProcess 和输出重定向【英文标题】:Windows CreateProcess and output redirection 【发布时间】:2016-03-16 11:31:58 【问题描述】:

我在一个 C 项目中工作,使用 WinAPI 的 windows 环境。 我的函数执行作为参数接收的命令(e.g. : "dir C:\Users"),并返回其输出。 它是从 DLL 运行的,因此它不能产生 cmd.exe 窗口,这意味着我不能使用 _popen。所以我使用CreateProcessA 和一个管道来捕获标准输出。

代码如下:

char *runExec(char *command, int *contentLen) 
    char *ret=NULL,*tmp=NULL;
    DWORD readBytes;
    int size=0;
    char buffer[128],cmdBuf[4096];
    HANDLE StdOutHandles[2];

    CreatePipe(&StdOutHandles[0], &StdOutHandles[1], NULL, 4096);

    STARTUPINFOA si;   
    memset(&si, 0, sizeof(si));
    si.cb = sizeof(si);
    si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    si.wShowWindow = SW_HIDE;
    si.hStdOutput = StdOutHandles[1];
    si.hStdError = StdOutHandles[1];
    PROCESS_INFORMATION pi;

    snprintf(cmdBuf,4096,"cmd /C %s", command);
    if (!CreateProcessA(NULL, cmdBuf, NULL, NULL, FALSE, CREATE_NO_WINDOW | DETACHED_PROCESS, NULL, NULL, &si, &pi)) 
        printf("Error createProcess : %d\n",GetLastError());
        return NULL;
    


    CloseHandle(StdOutHandles[1]);
    printf("Before read\n");
    while (ReadFile(StdOutHandles[0], buffer, 127, &readBytes, NULL))
        printf("IN WHILE\n");
        buffer[readBytes] = 0;
        printf("read %d bytes\n", readBytes);
        size += readBytes;
        tmp = (char *)realloc(ret, size + 1);
        if (tmp == NULL) 
            free(ret);
            return NULL;
        
        ret = tmp;
        strncpy(ret + (size - readBytes), buffer, readBytes);
        ret[size] = 0;
    
    printf("Readfile returned with %d, read %d\n", GetLastError(),readBytes);

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    CloseHandle(StdOutHandles[0]);
    printf("#%s#\n", ret);

    return ret;

输出是:

Before read
Readfile returned with 109, read 0
#(null)#

所以我明白了: - 我的循环甚至没有执行一次 - ReadFile 不读取任何内容并立即返回 Broken Pipe

我已经阅读了各种 *** 和 MSDN 页面,但似乎无法正常工作。

【问题讨论】:

来自 STARTUPINFO 文档:如果在调用进程创建函数之一时指定了此标志,则句柄必须是可继承的,并且函数的 bInheritHandles 参数必须设置为 TRUE。有关详细信息,请参阅处理继承。您的代码不满足这两个要求。 Aaaa 我看不懂...谢谢! 【参考方案1】:

正如评论中指出的,句柄必须是可继承的,这意味着像这样替换CreatePipe

SECURITY_ATTRIBUTES pipeAttrib;
memset(&pipeAttrib, 0, sizeof(pipeAttrib));

pipeAttrib.nLength = sizeof(SECURITY_ATTRIBUTES);
pipeAttrib.bInheritHandle = NULL;
pipeAttrib.bInheritHandle = TRUE;

if (!CreatePipe(&StdOutHandles[0], &StdOutHandles[1],&pipeAttrib, 4096)) 
    printf("Create pipe error %d\n", GetLastError());
    return NULL;

并将CreateProcess第5个参数(bInheritHandles)设置为TRUE而不是FALSE

【讨论】:

以上是关于Windows CreateProcess 和输出重定向的主要内容,如果未能解决你的问题,请参考以下文章

Windows:如何使用CreateProcess停止重定向Stdout的缓冲

使用句柄从 CreateProcess() 收集输出

Createprocess控制台程序输出重定向

(C) Windows 句柄和 Createprocess

CreateProcess 执行 Windows 命令

Windows 7 CreateProcess,子进程无法写入文件?