问题
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 useSetHandleInformation(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 fieldshStdInput
,hStdOutput
andhStdError
of theSTARTUPINFO
struct - do not forget to declare that you want to use them withdwFlags |= 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