重定向的标准输入管道被创建的子进程忽略

Redirected stdin pipe being ignored by created child process

编辑:按照 Harry Johnston 的建议,解决方法是关闭 Child_In_Write 句柄。
有点讽刺的是,我早些时候曾尝试关闭 Child_In_Read 句柄。这不起作用,写入句柄是唯一应该关闭的句柄。

对于我正在尝试制作的工具,我需要能够启动一个进程并通过标准输入为其提供数据——就好像我是通过带有管道的命令行调用它一样

足够简单的想法。 I've primarily I've followed this guide from Microsoft and got things "working". 在我自己的测试程序中,我可以很好地读取标准输入。但是当我尝试使用其他程序时,例如 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);
}

我是否遗漏了需要发送给 "get the ball rolling" 的内容?我需要附加“\r\n”或类似的东西吗? shell 如何管理它?

一些应用程序,包括 cat,将在退出前等待标准输入 end-of-file。您可以通过关闭管道的末端来实现这一点。

(您还必须确保管道末端的句柄未被子进程或任何其他进程继承,但您的代码已经正确处理了这一点。)