Two way parent child communication in windows with c++

筅森魡賤 提交于 2021-02-08 07:34:26

问题


Scroll down to see new update

Update:: In other word: I want to launch another program in the manner of a shell on Windows.

Need a two way communication between parent and child process using c++ on Windows. The parent is my program and the child is a random console application (like mysql terminal).

It's been a couple days searching but couldn't find any working solution for Windows. Also MS documentations is not helping.

Here i got a sample code from a question asked three years ago. How can i translate the code to Microsoft specific api and use it on Windows?

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#define Read            0
#define Write           1
#define ParentRead      read_pipe[1]
#define ParentWrite     write_pipe[0]
#define ChildRead       write_pipe[1]
#define ChildWrite      read_pipe[0]

int main()
{
int data_processed;

/** Pipe for reading for subprocess */
int read_pipe[2];
/** Pipe for writing to subprocess */
int write_pipe[2];

char buffer[100];
memset(buffer, '\0', 100);

if (pipe(read_pipe) == 0 && pipe(write_pipe) == 0)
{
    pid_t pid = fork();
    if (pid == (pid_t)-1)
    {
        fprintf(stderr, "Fork failure");
        exit(EXIT_FAILURE);
    }
    else if (pid == (pid_t)0) //Child process
    {
        close(Read);
        close(Write);
        close(ParentRead);
        close(ParentWrite);
        dup(ChildRead);
        dup(ChildWrite);
        execlp("cat", (char*)NULL);
        exit(EXIT_FAILURE);
    }
    else { //Parent process
        close(ChildRead);
        close(ChildWrite);

        write(ParentWrite, "abc", 3);
        int r = read(ParentRead, buffer, 99);
        printf("%d %d", r, errno);
        puts(buffer);
    }
}

exit(EXIT_SUCCESS);
}

New Update:

So based on this sample I wrote a modified version of the sample code and seems to be OK except that the redirected output is not what it's supposed to be. Here's the code:

#include <iostream>
#include <Windows.h>
#include <string>

HANDLE hSTD_IN_READ = NULL;
HANDLE hSTD_IN_WRITE = NULL;
HANDLE hSTD_OUT_READ = NULL;
HANDLE hSTD_OUT_WRITE = NULL;

void WriteToPipe(std::string);
void ReadFromPipe();


int main()
{
    SECURITY_ATTRIBUTES sa;

    std::cout << "\nStart of parent execution: ";

    // Set the bInheritHandle flag so pipe handles are inherited. 

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

    // Create pip for child process stdout
    if (!CreatePipe(&hSTD_OUT_READ, &hSTD_OUT_WRITE, &sa, 0)) {
        std::cout << "Error: CreatePipe STDOUT.\n";
        return -1;
    }
    // Ensure the read handle to the pipe for stdout is not inherited.
    if (!SetHandleInformation(hSTD_OUT_READ, HANDLE_FLAG_INHERIT, 0)) {
        std::cout << "Error: STD_OUT_READ CreatePipe.\n";
        return -1;
    }
    // Create pipe for child process's stdin
    if (!CreatePipe(&hSTD_IN_READ, &hSTD_IN_WRITE, &sa, 0)) {
        std::cout << "Error: CreatePipe STDIN.\n";
        return -1;
    }
    // Ensure the write handle to the pipe for STDIN is not inherited. 
    if (!SetHandleInformation(hSTD_IN_WRITE, HANDLE_FLAG_INHERIT, 0)) {
        std::cout << "Error: STD_IN_WRITE CreatePipe.\n";
        return -1;
    }
    // Create Child Process

    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    BOOL bSuccess = FALSE;

    ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));

    ZeroMemory(&si, sizeof(STARTUPINFO));
    // This structure specifies the STDIN and STDOUT handles for redirection.
    si.cb = sizeof(STARTUPINFO);
    si.hStdError = hSTD_OUT_WRITE;
    si.hStdInput = hSTD_IN_READ;
    si.hStdOutput = hSTD_OUT_WRITE;
    si.dwFlags |= STARTF_USESTDHANDLES;

    bSuccess = CreateProcess(TEXT("c:\\sqlite3.exe"), NULL, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
    if (!bSuccess) {
        std::cout << "Error in CreateProcess.\n";
        return -1;
    }
    else {

        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }

    // Now execute your command then read the child process's output.
    WriteToPipe(".databases");
    ReadFromPipe();

    std::cout << "End of program.\n";
    return 0;
}

void WriteToPipe(std::string buffer)
{
    DWORD bWritten, BUFFSIZE = buffer.size();
    BOOL bSuccess = FALSE;


        bSuccess = WriteFile(hSTD_IN_WRITE, buffer.c_str(), BUFFSIZE, &bWritten, NULL);
        if (!bSuccess)
            std::cout << "WritetoPipe::Couldn't Write to std_in_write.\n";

        // Close the pipe handle so the child process stops reading.
        if (!CloseHandle(hSTD_IN_WRITE))
            std::cout << "WriteToPipe::Couldn't close the handle after Writing to std_in_write.\n";
    }

void ReadFromPipe()
{
    DWORD bRead, bWritten;
    const DWORD BUFFSIZE = 4096;
    CHAR buffer[BUFFSIZE];
    BOOL bSuccess = FALSE;
    HANDLE hPARENT_STD_OUT = GetStdHandle(STD_OUTPUT_HANDLE);

    for (;;) {
        bSuccess = ReadFile(hSTD_OUT_READ, buffer, BUFFSIZE, &bRead, NULL);
        if (!bSuccess || bRead == 0) {
            std::cout << "ReadFromPipe::Exiting after ReadFile.\n";
            break;
        }
        bSuccess = WriteFile(hPARENT_STD_OUT, buffer, BUFFSIZE, &bWritten, NULL);
        if (!bSuccess) {
            std::cout << "ReadFromPipe::Exiting after WriteFile.\n";
            break;
        }
    }
}

And the output:

Start of parent execution: seq  name             file
---  ---------------  ----------------------------------------------------------
0    main
ówVE_■   öΘ/ P╞ów    (┴M (┴M         êΘ/ (┴M     £Θ/ ╕å¥w  M áΘ/ ,╟₧w     Ω/ fr#u  M ╝îíw@r#u╕   (∞/     @∩/        ΣΘ/ @               @∩/ (∞/ ⁿΘ/ ép#u@∩/ (∞/ @∩/ <ε/ o#u(∞/ @∩/ 8∩/ 4o#u┘╥₧w        ╓   ┤Ω/ ┘jƒw  M A÷₧w  M A÷₧wÿìM     ■≤₧w╪½└(     M    8┘M     M A÷₧wÿìM  ²   ¿½└(ªfM   M ~fM   xçM δ/   M A÷₧wxêM     ■≤₧wx¼└(      M    ╚½└(  M            δ/ ù    wáw  Vδ/ ╓   |δ/ ┘jƒwⁿδ/ Vδ/   ½└(αφ/ ⁿδ/
kƒw
kƒw    ⁿδ/ ░δ/ (°     M ╚╜M ΦÉM    îM Ç   ÉìM └ 3 6 9 5 7 \   ╨φ/ |δ/ πlƒw╢êM ¿δ/ \   αφ/ ^      ¼φ/ πiƒw╨φ/ áδ/     `ε/ ≥iƒw    ┐M \ ^ ¿δ/ S -   M A÷₧wÿêM     ■≤₧wP¡└(p     M h   1 6 2 2 ╠ ╔8 0   - 3 6 9 5 7 ╠ ╔8 1 4 - öfM 0 1       &▄₧w  B·  A÷₧w       ÿêM c : ┘╥₧w@¡└(  M ÉêM     ╠ ╔  M ╠ ╔ê├M   äM Ç   ╨∞/ ╠ ╔φ/ Ä╘Γ á∞/
╬M    \φ/        φ/ \φ/ ╠ ╔=·  zφ/   M ÉêM ñÉM ≡∞/ Ç    ë½w┬ǃwL  |φ/    ÿêM      └&       ê╤M ╕∞/           /  ówVE_■   dφ/ P╞ów    ÿêM ÿêM ╕φ/ á∩/     ÿêM     `M S B _ E tφ/ ,╟₧w    ÿêM °∩/ @X#u  M     ÿêM     ɱ/ SX#áwɱ/ ┐M                               DZ/     P   P6*uá∩/ ÿêM                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               WΓF┼CÑ■ ìεπ╙≡WΓF┼CÑ■ ìεπ╙≡                           _╩╝H±/ ñU#u          DZ/     t⌠/ ▒U#u
        (                                                                                                             ┘╥₧w╨▒└(┘╥₧w╪▒└(  M ┐M     ╚▒└(  M ░╛M             ≈         NM    ╠ ╔                              α╛M   M ░╛M ±   ▒X#u   ░╛M Ç      Ç      (╟M     ╕╛M ╠  └ M    L       ëM ╕╛M    ÿêM              ╪ÅM    ╪ÅM    `M ówVE_■   ▄±/ P╞ów    ┐M   M         ╕╛M ┐M ╕╛M     α±/ ╕╛M Φ±/ ,╟₧w    ⁿ±/ ?ñ#u  M     ┐M ╚≈/     ╚≈/ g⌡Θv╩ê∞v╬∩Θv╪D╔@┬Q┌ P_$u    ╬ ╧ ╨ ╤ ╥ ╙ ╘ ╒ ╓ ╫ ╪ ┘ ┌ █ ▄ ▌ ▐ ▀ α ß Γ π Σ σ                                                     αëM         â   É▀█ D       'M                                            ö   É   É   l@                       L      é£        "   ┐M ?      α²    √   @┤└(└           └ M                +   M     >  >          M        └ M                M ░  &  &  M H          ñ   ¿                 @   ≡²     α²             á&    `°/                        £  t  h╝M     +             █               [           h  @           M                                                        P°/ ┐M ╨⌡/  α² ╨&  °█     ¿                 ██                     ╕╛M
                       ¿       ■≤₧  └(    ñ              ╕╛M                  °█ c               └        M █  █'   └ M Ω    X╝M &         └     ■       ┘╥₧wá   £   £  t          └ M Ç   @   @  ñ     °█ $ & Φ╛M                                                           ╠⌠v   î÷/ á÷/ PΩ¥w╠⌠vî÷/       H⌠v   |⌠vH⌠v ⌠v▌Θ¥w░÷/         └≈/ ≤τ¥w┬Q┌ ÿ   Φ¥w    2   ⌠v  ⌠v   ì                °≈/ H⌠v                                                                                                                                                                                                                                                                            ⌠╢└(∞≈/ ┤ïΘv½½½½╝îíw╪ïΘvÿ   ┬Q┌ φïΘv░┌ ÿ   ⁿD╔@°/ ╩┌ ÿ   ■┌
   ┌S╙╫∞°/ Φå█     ┤°/ 8┌ .databas

回答1:


As said by Christopher Oicles in the referenced link, the logic using WinAPI is the same:

  • you first create pipes for input and output - the WinAPI function is CreatePipe
  • WinAPI allows to protect a handle for being inherited, because you do not have the fork+exec to close anything in the child - you must use SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); before creating the child process
  • you create the child process with CreateProcess, passing the handles to the pipes created above in the fields hStdInput, hStdOutput and hStdError of the STARTUPINFO struct - do not forget to declare that you want to use them with dwFlags |= STARTF_USESTDHANDLES; in same struct.

This only makes sense with console application childs, because GUI subsystem application normally do not use standard streams, but it will work fine with the ftp command. Simply, as you process the streams yourself, the system do not create a console and the output from the child process is only available in the parent process.


In your code, there is at least one good reason for not writing what you expect. In ReadFromPipe, you get bRead bytes in your buffer, but you try to output the full buffer.

The output command should be:

bSuccess = WriteFile(hPARENT_STD_OUT, buffer, bRead, &bWritten, NULL);

But that is not all. A command should be terminated the same that it would be in a input file, that is with \r\n, so your command should be:

WriteToPipe(".databases\r\n");

And last but not least, you must close the unused parts of the pipes after starting child command, at least hSTD_OUT_WRITE to allow ReadFile(hSTD_OUT_READ, ...) to return 0 as soon as the child process exits. So your code should be:

CloseHandle(hSTD_OUT_WRITE);
CloseHandle(hSTD_IN_READ);

// Now execute your command then read the child process's output.
...

With those modifications, I could successfully communicate with the ftp.exe program.



来源:https://stackoverflow.com/questions/32501274/two-way-parent-child-communication-in-windows-with-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!