重定向的stdin管道被创建的子进程忽略

时间:2017-02-08 03:26:07

标签: c++ winapi process pipe stdin

编辑:正如Harry Johnston所建议的那样,修复是关闭Child_In_Write句柄 有点讽刺的是,我之前尝试关闭Child_In_Read句柄。这不起作用,写句柄是唯一应该关闭的句柄。

对于我尝试制作的工具,我需要能够启动一个进程并通过stdin提供数据 - 就好像我是通过带管道的命令行调用它一样

简单的想法。 I've primarily I've followed this guide from Microsoft and got things "working". 在我自己的测试程序中,我可以从stdin读取就好了。但是当我尝试使用其他程序时,例如像cat一样,它们只会挂起 - 好像它们还在等待输入。

The full repo is here.

以下是相关的代码位:

初始化管道。

// From Cao/Main.cpp
static HANDLE Child_In_Read   = NULL;
static HANDLE Child_In_Write  = NULL;
static HANDLE Child_Out_Read  = NULL;
static HANDLE Child_Out_Write = NULL;


    // Create and initialize standard in pipe.
    {
        bool createPipeSuccess =
            CreatePipe(
                &Child_In_Read,
                &Child_In_Write,
                &secAttr,
                0);
        if (!createPipeSuccess)
        {
            // @logging log error.
            printf("Could not create standard in pipe!\n");
            goto textData_cleanup;
        }

        bool setPipeFlagSuccess = SetHandleInformation(Child_In_Write, HANDLE_FLAG_INHERIT, 0);
        if (!setPipeFlagSuccess)
        {
            // @logging log error.
            printf("Could not set standard in pipe information!\n");
            goto textData_cleanup;
        }
    }

写入刚刚初始化的管道,然后启动该过程。

    // From Cao/Main.cpp
    // Write to the processes' standard in.
    {
        DWORD inBytesWritten = 0;
        bool writeSuccess =
            WriteFile(
                Child_In_Write,
                text,               // Simple char array.
                text_numBytes,
                &inBytesWritten,
                NULL);
        if (!writeSuccess)
        {
            // @logging log error.
            printf("Could not write to child's standard in!\n");
            goto textData_cleanup;
        }
    }

    // Create the child process.
    {
        STARTUPINFO startupInfo = { 0 };
        startupInfo.cb         = sizeof(startupInfo);
        startupInfo.hStdInput  = Child_In_Read;
        startupInfo.hStdError  = Child_Out_Write;
        startupInfo.hStdOutput = Child_Out_Write;
        startupInfo.dwFlags    = STARTF_USESTDHANDLES;

        bool createProcessSuccess = CreateProcessW(
            NULL,
            commandLine,
            NULL,
            NULL,
            true,
            0,
            NULL,
            NULL,
            &startupInfo,
            &ChildProcInfo);        
        if (!createProcessSuccess)
        {
            printf("Could not start child process with command line: %ls", commandLine);
            goto textData_cleanup;
        }

        isChildRunning = true;
        ModifyMenu(IconMenu, IconMenu_RunCancel, MF_BYCOMMAND, IconMenu_RunCancel, L"Cancel");

        // newHandle is always 0x00000000 so I'm assuming I don't need to clean it up.
        HANDLE newHandle;
        RegisterWaitForSingleObject(&newHandle, ChildProcInfo.hProcess, LaunchedProcessExitedOrCancelled, NULL, INFINITE, WT_EXECUTEONLYONCE);
    }

我的阅读代码似乎工作正常:

// From Echoer/Main.cpp
printf("via stdin:\n");
{
    const int readBuffer_size = 5000;
    char *readBuffer[readBuffer_size];

    {
        HANDLE standardIn = GetStdHandle(STD_INPUT_HANDLE);
        DWORD bytesRead = 0;

        bool readSuccess =
            ReadFile(
                standardIn,
                readBuffer,
                readBuffer_size,
                &bytesRead,
                NULL);
        if (!readSuccess)
        {
            printf("Could not read from standard in!\n");
        }

        CloseHandle(standardIn);
    }

    printf("%s", readBuffer);
}

我错过了需要发送的东西"让球滚动#34;?我是否需要追加" \ r \ n"或类似的东西? shell如何管理这个?

1 个答案:

答案 0 :(得分:0)

某些应用程序(包括cat)将在退出之前等待标准输入上的文件结束。您可以通过关闭管道末端来实现此目的。

(您还必须确保子管或任何其他进程未继承管道末端的句柄,但您的代码已正确处理此问题。)