使用C ++在Windows中进行双向父子通讯 [英] Two way parent child communication in windows with c++

查看:68
本文介绍了使用C ++在Windows中进行双向父子通讯的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

向下滚动以查看新更新

更新::换句话说:我想在Windows上以Shell的方式启动另一个程序.

需要在Windows上使用c ++在父进程和子进程之间进行双向通信.父母是我的程序,孩子是一个随机的控制台应用程序(如mysql终端).

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).

搜索已经进行了几天,但找不到适用于Windows的任何有效解决方案.此外,MS文档也无济于事.

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

在这里,我从三年前提出的一个问题中获得了示例代码.如何将代码转换为Microsoft特定的api并在Windows上使用?

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);
}

新更新:

因此基于此示例我编写了示例代码的修改版本,但看起来还可以,只是重定向的输出与预期的不一样.这是代码:

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;
        }
    }
}

输出:

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

推荐答案

如Christopher Oicles在

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

  • 您首先创建用于输入和输出的管道-WinAPI函数是 CreatePipe
  • WinAPI允许保护句柄以被继承,因为您没有 fork + exec 来关闭子级中的任何内容-您必须使用 SetHandleInformation(handle,HANDLE_FLAG_INHERIT,0); 创建子进程之前
  • 使用 CreateProcess 创建子进程,将句柄传递到上面在 hStdInput hStdOutput 字段中创建的管道. STARTUPINFO 结构的hStdError -不要忘记声明要与同一结构中的 dwFlags | = STARTF_USESTDHANDLES; 一起使用.
  • 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.

这仅对控制台应用程序子项有意义,因为GUI子系统应用程序通常不使用标准流,但可以通过 ftp 命令正常工作.简而言之,当您自己处理流时,系统不会创建控制台,子进程的输出仅在父进程中可用.

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.

在您的代码中,至少有一个很好的理由不编写您期望的内容.在 ReadFromPipe 中,您在缓冲区中获得了 bRead 字节,但是您尝试输出完整的缓冲区.

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.

输出命令应为:

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

但这还不是全部.命令的终止应与输入文件中的终止相同,即使用 \ r \ n ,因此您的命令应为:

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");

最后但并非最不重要的一点是,您必须在启动子命令后关闭管道的未使用部分,至少要关闭 hSTD_OUT_WRITE 以允许 ReadFile(hSTD_OUT_READ,...)子进程退出后立即返回0.因此您的代码应为:

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.
...

通过这些修改,我可以成功地与 ftp.exe 程序进行通信.

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

这篇关于使用C ++在Windows中进行双向父子通讯的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆