如何从管道而不是键盘条目中读取字符串

时间:2015-03-04 01:45:39

标签: windows winapi pipe handle anonymous

我的教科书中有以下两个C文件。

第一个文件是写入子进程的父进程

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

#define BUFFER_SIZE 25

int main(void) {
    HANDLE ReadHandle, WriteHandle;
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    char message[25] = "Hello";
    DWORD written;

    /* set up security attributes allowing pipes to be inherited */
    SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };

    /* allocate memory */
    ZeroMemory(&pi, sizeof(pi));

    /* create the pipe */

    if (!CreatePipe(&ReadHandle, &WriteHandle, &sa, 0)) {
        fprintf(stderr, "Create Pipe Failed");
        return 1;
    }

    /* establish the START INFO structure for the child process */
    GetStartupInfo(&si);
    si.dwFlags = STARTF_USESTDHANDLES;
    si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);

    /* redirect standard input to the read end of the pipe */
    si.hStdInput = ReadHandle;


    /* don’t allow the child to inherit the write end of pipe */
    SetHandleInformation(WriteHandle, HANDLE_FLAG_INHERIT, 0);

    /* create the child process */
    CreateProcess(NULL, filter(), NULL, NULL, TRUE,
        /* inherit handles */ 0, NULL, NULL, &si, &pi);

    /* close the unused end of the pipe */
    CloseHandle(ReadHandle);

    /* the parent writes to the pipe */
    if (!WriteFile(WriteHandle, message, BUFFER_SIZE, &written, NULL))
        fprintf(stderr, "\nError writing to pipe abc .\n");

    /* close the write end of the pipe */
    CloseHandle(WriteHandle);

    /* wait for the child to exit */
    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    return 0;
} 

然后为子进程:

#include <Windows.h>
#include <stdio.h>
#include <Stdlib.h>

#define BUFFER_SIZE 25

int filter() {
    HANDLE ReadHandle;
    char buffer[BUFFER_SIZE];
    //char* buffer = malloc(sizeof(char)* (BUFFER_SIZE + 1));
    //buffer[BUFFER_SIZE] = '\0'; 
    DWORD read;

    /* get the read handle of the pipe */
    //ReadHandle = GetStdHandle(STD_INPUT_HANDLE);

    //SetHandleInformation(ReadHandle, HANDLE_FLAG_INHERIT, 0);
    ReadHandle = GetStdHandle(STD_INPUT_HANDLE);
    printf("Please work!!");

    /* the child reads from the pipe */
    if (ReadFile(ReadHandle, buffer, BUFFER_SIZE, &read, NULL)) {
        //return buffer;
        printf("child read %s", buffer);
    }
    else
        fprintf(stderr, "Error reading from pipe");
    system("Pause");
    return 0;

}

当我运行父进程时,我会读到子进程(无论我在提示符中输入什么内容),然后是一堆奇怪的符号(看起来像[][][][][]行)。但是,似乎我应该接收父进程中定义的消息。我已将si.dwflags设置为STARTF_USESTDHANDLES,这应该允许我的si.hStdOutputsi.hStdInput不使用控制台,但似乎它仍在使用控制台输入缓冲区{ {1}}。

谁能告诉我为什么会这样?如何通过管道将消息发送到我的子进程而不是控制台输入缓冲区?

1 个答案:

答案 0 :(得分:0)

ReadFile()退出时,buffer不能保证以空值终止。你需要:

  1. 在打印buffer之前添加空终止符:

    char buffer[BUFFER_SIZE+1]; // <-- add space for null terminator
    ...
    if (ReadFile(ReadHandle, buffer, BUFFER_SIZE, &read, NULL)) {
        buffer[read] = 0; // <-- add the null terminator
        printf("child read %s", buffer);
    }
    
  2. 在打印read时考虑ReadFile()输出的buffer值:

    char buffer[BUFFER_SIZE]; // <-- null terminator not needed
    ...
    if (ReadFile(ReadHandle, buffer, BUFFER_SIZE, &read, NULL)) {
        printf("child read %.*s", read, buffer);
    }
    
  3. 另请注意,您正在关闭父管道句柄,而无需等待确保子进程实际上已完成所有内容的读取。这可能会导致ReadFile()失败,或者至少返回的字节数少于请求的数量。所以一定要考虑到这一点。在关闭父管道句柄之前等待子进程退出,或者通过在循环中调用ReadFile()来确保子进程处理部分数据读取,直到收到所有预期的字节为止。

    Raymond Chen的MSDN博客也提供了一些关于跨进程读/写管道的重要信息:

    Be careful when redirecting both a process's stdin and stdout to pipes, for you can easily deadlock