C++管道实现重定向子进程的stdin和stdout

最近写本地判题程序,有一步需要实现重定向子进程控制台程序的输入输出来与子进程交互,即让程序A向子进程B的stdin写入数据,并从子进程的stdout读出数据。
本以为只要用点>><之类重定向符号就能解决,百度一看还挺复杂,在参考Creating a Child Process with Redirected Input and Output - Win32 apps | Microsoft Docs重定向子进程控制台程序的输入输出 - 绿色的麦田 - 博客园,我写出了下面的程序:
其中程序b负责从控制台读入一个n,和n个整数,并输出累加结果。
程序fb启动时需要指定一个参数作为子进程。运行时会向子进程的stdin写如一个5,然后写入5个整数,然后获取子进程的stdout并输出到自己的stdout。如果你需要自己用的话只需要在IOWithChild()写自己的逻辑代码,并调用ReadLineFromChild()WriteToChild()进行输入输出操作即可。
我的编译器为Mingw-w64 g++ 8.1,会有警告信息但可以正常运行。
b.cpp

#include <cstdio>
using namespace std;
int main(){
	int n;
	scanf("%d",&n);
	int ans=0;
	for(int i=0;i<n;i++){
		int x;
		scanf("%d",&x);
		ans+=x;
	}
	printf("sum is : %d",ans);
	return 0;
}

fb.cpp

#include <windows.h> 
#include <tchar.h>
#include <stdio.h> 
#include <strsafe.h>

#include <string>

#define BUFSIZE 4096 
 
HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;

HANDLE g_hInputFile = NULL;
 
void CreateChildProcess(TCHAR filename[]); 
void ErrorExit(PTSTR); 
DWORD WriteLineToChild(const CHAR buf[],const DWORD numberOfBytesToWrite);
DWORD ReadFromChild(CHAR buf[]);

void IOWithChild(void){
	/*
	让子进程做累加运算,并获取计算结果
	*/

	int n=5;
	int value[10]={1,3,5,7,9};
	std::string sBuf;
	int len;

	sBuf=std::to_string(n);
	printf("\n->Write to child:\n%s\n",sBuf.c_str());
	WriteLineToChild(sBuf.c_str(),sBuf.length());

	sBuf="";
	for(int i=0;i<n;i++){
		sBuf+=std::to_string(value[i]);
		if(i!=n-1) sBuf+=' ';
	}
	printf("\n->Write to child:\n%s\n",sBuf.c_str());
	WriteLineToChild(sBuf.c_str(),sBuf.length());

	char cBuf[BUFSIZE];
	ReadFromChild(cBuf);
	printf("\n->read from child:\n%s\n", cBuf);

	
	return;
}


DWORD WriteLineToChild(const CHAR buf[],const DWORD numberOfBytesToWrite){
	BOOL bSuccess = FALSE;
	CHAR chBuf[BUFSIZE];
	DWORD dwWrittenChild;
	int i;
	for(i=0; i<numberOfBytesToWrite; i++){
		chBuf[i]=buf[i];
	}
	chBuf[i++]='\r';
	chBuf[i++]='\n';

	bSuccess = WriteFile(g_hChildStd_IN_Wr, chBuf, i, &dwWrittenChild, NULL);
	if ( ! bSuccess ) ErrorExit(TEXT("Write To Child Failed\n"));
	return dwWrittenChild;
}

DWORD ReadFromChild(CHAR buf[]){
	BOOL bSuccess = FALSE;
	DWORD dwReadChild;
	bSuccess = ReadFile( g_hChildStd_OUT_Rd, buf, BUFSIZE, &dwReadChild, NULL);
	if( ! bSuccess) ErrorExit(TEXT("Read From Child Failed\n"));
	return dwReadChild;
}


int _tmain(int argc, TCHAR *argv[]) 
{ 
	SECURITY_ATTRIBUTES saAttr; 
 
	printf("\n->Start of parent execution.\n");

// Set the bInheritHandle flag so pipe handles are inherited. 
 
	saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
	saAttr.bInheritHandle = TRUE; 
	saAttr.lpSecurityDescriptor = NULL; 

// Create a pipe for the child process's STDOUT. 
 
	if ( ! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0) ) 
		ErrorExit(TEXT("StdoutRd CreatePipe")); 

// Ensure the read handle to the pipe for STDOUT is not inherited.

	if ( ! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) )
		ErrorExit(TEXT("Stdout SetHandleInformation")); 

// Create a pipe for the child process's STDIN. 
 
	if (! CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) 
		ErrorExit(TEXT("Stdin CreatePipe")); 

// Ensure the write handle to the pipe for STDIN is not inherited. 
 
	if ( ! SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0) )
		ErrorExit(TEXT("Stdin SetHandleInformation")); 
 
// Create the child process. 
	

// Get a handle to an input file for the parent. 
// This example assumes a plain text file and uses string output to verify data flow. 
	if (argc == 1) 
		ErrorExit(TEXT("Please specify an child program.\n")); 
	CreateChildProcess(argv[1]);



	IOWithChild();

	// Close the pipe handle so the child process stops reading. 
 
	if ( ! CloseHandle(g_hChildStd_IN_Wr) ) 
		ErrorExit(TEXT("StdInWr CloseHandle"));

	return 0;
} 
 
void CreateChildProcess(TCHAR filename[])
// Create a child process that uses the previously created pipes for STDIN and STDOUT.
{ 
	PROCESS_INFORMATION piProcInfo; 
	STARTUPINFO siStartInfo;
	BOOL bSuccess = FALSE; 
 
// Set up members of the PROCESS_INFORMATION structure. 
 
	ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
 
// Set up members of the STARTUPINFO structure. 
// This structure specifies the STDIN and STDOUT handles for redirection.
 
	ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
	siStartInfo.cb = sizeof(STARTUPINFO); 
	siStartInfo.hStdError = g_hChildStd_OUT_Wr;
	siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
	siStartInfo.hStdInput = g_hChildStd_IN_Rd;
	siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
 
// Create the child process. 
	
	bSuccess = CreateProcess(NULL, 
		filename,		// command line 
		NULL,			 // process security attributes 
		NULL,			 // primary thread security attributes 
		TRUE,			 // handles are inherited 
		0,				 // creation flags 
		NULL,			 // use parent's environment 
		NULL,			 // use parent's current directory 
		&siStartInfo,	// STARTUPINFO pointer 
		&piProcInfo);	// receives PROCESS_INFORMATION 
	
	// If an error occurs, exit the application. 
	if ( ! bSuccess ) 
		ErrorExit(TEXT("CreateProcess"));
	else 
	{
		// Close handles to the child process and its primary thread.
		// Some applications might keep these handles to monitor the status
		// of the child process, for example. 

		CloseHandle(piProcInfo.hProcess);
		CloseHandle(piProcInfo.hThread);
		
		// Close handles to the stdin and stdout pipes no longer needed by the child process.
		// If they are not explicitly closed, there is no way to recognize that the child process has ended.
		
		CloseHandle(g_hChildStd_OUT_Wr);
		CloseHandle(g_hChildStd_IN_Rd);
	}
}
 

void ErrorExit(PTSTR lpszFunction) 

// Format a readable error message, display a message box, 
// and exit from the application.
{ 
	LPVOID lpMsgBuf;
	LPVOID lpDisplayBuf;
	DWORD dw = GetLastError(); 

	FormatMessage(
		FORMAT_MESSAGE_ALLOCATE_BUFFER | 
		FORMAT_MESSAGE_FROM_SYSTEM |
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		dw,
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(LPTSTR) &lpMsgBuf,
		0, NULL );

	lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, 
		(lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR)); 
	StringCchPrintf((LPTSTR)lpDisplayBuf, 
		LocalSize(lpDisplayBuf) / sizeof(TCHAR),
		TEXT("%s failed with error %d: %s"), 
		lpszFunction, dw, lpMsgBuf); 
	MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK); 

	LocalFree(lpMsgBuf);
	LocalFree(lpDisplayBuf);
	ExitProcess(1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值