如何在C语言中将输入和输出传递给子进程
我在Windows中有一个exe程序,它在终端中的工作方式如下如何在C语言中将输入和输出传递给子进程,c,createprocess,child-process,C,Createprocess,Child Process,我在Windows中有一个exe程序,它在终端中的工作方式如下 > program.exe parameter01 file entry01 (user types entry01) output01 entry02 (user types entry02) output02 ... until the combination Ctrl+D is pressed. 我需要用C语言创建一个“子进程”,它能够运行程序并向“子进程”发送条目,并以char[]或字符串形式接收输出 我知道我必须使
> program.exe parameter01 file
entry01 (user types entry01)
output01
entry02 (user types entry02)
output02
...
until the combination Ctrl+D is pressed.
我需要用C语言创建一个“子进程”,它能够运行程序并向“子进程”发送条目,并以char[]或字符串形式接收输出
我知道我必须使用,但我不知道如何像输入一样传递条目并检索输出,我该怎么做
我已经看到了这一点,但我需要用C语言实现这一功能。使用该结构
您必须设置属性hStdInput
越来越少,这就是你需要的(它是C++代码,它可能不编译,但你会得到这个想法):
std::string GetProcessOutput(HANDLE hstOutProcess){
std::stringstream stream;
字符lpBuffer[2]={0};
德沃德·恩巴特雷德;
while(true){
BOOL-bResult=ReadFile(hStdOutProcess,lpBuffer,sizeof(char),&nBytesRead,NULL);
if(bResult&nBytesRead){
strStream一个简单的例子:
#include <signal.h>
void SigQuit_Handle(int sig){
exit(1);
}
int main(int argc, char *argv[]){
char buffer[1024];
signal( SIGQUIT, SigQuit_Handle );
signal( SIGINT, SIG_IGN ); // If you want to ignore Ctrl + C
while ( true ){
fgets(buffer, sizeof(buffer), INPUT_BUFFER);
}
return 0;
}
#包括
无效SigQuit_句柄(int sig){
出口(1);
}
int main(int argc,char*argv[]){
字符缓冲区[1024];
信号(SIGQUIT,SIGQUIT_句柄);
signal(SIGINT,SIG_IGN);//如果要忽略Ctrl+C
while(true){
fgets(缓冲区、sizeof(缓冲区)、INPUT_缓冲区);
}
返回0;
}
编辑:
在处理线程时,可能需要包含sys/types.h
基本上,您需要在Win32平台上创建进程间通信系统
您可以通过几种不同的方式来实现:管道、共享内存、IPC、WinSock、DDE
所有这些特性竞争着为您提供最糟糕的API,其中包含大量不一致和无用的参数、不标准的返回码和不连贯的函数名。此外,还包括1995年左右的半unicode处理
下面是一个带有命名管道的示例
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
// name of our glorious pipe
#define PIPE_NAME L"\\\\.\\pipe\\whatever" // bloody unicode string
// exit on fatal error
void panic(const char * msg)
{
fprintf(stderr, "***PANIC*** %s\n", msg);
exit(-1);
}
// father process
void father(const char * own_name) // name of our own executable to launch a copy of ourselve
{
printf("Father process starting\n");
// create a monodirectional father->child named pipe
HANDLE pipe = CreateNamedPipe (
PIPE_NAME, // name of the pipe
PIPE_ACCESS_OUTBOUND, // send only
PIPE_TYPE_BYTE, // send data as a byte stream
1, // only one instance
0, 0, 0, NULL); // default junk
if (pipe == INVALID_HANDLE_VALUE) panic("could not create pipe");
// spawn child process
{
STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcessA( // using ASCII variant to be compatible with argv
own_name, // executable name (ourself)
"child", // command line. This will be seen as argv[0]
NULL, NULL, FALSE, // default junk
CREATE_NEW_CONSOLE, // launch in another console window
NULL, NULL, // more junk
&si, &pi)) // final useless junk
panic("could not create child process");
}
// connect to child process
BOOL result = ConnectNamedPipe(pipe, NULL);
if (!result) panic("could not connect to child process");
// talk to child
for (;;)
{
// read an input line
char line[100];
printf("Say something >");
if (fgets(line, sizeof(line), stdin) == NULL)
panic("could not read from standard input");
// exit on an empty line
if (!strcmp(line, "\n")) break;
// send the line to the child
DWORD written = 0;
if (!WriteFile(
pipe,
line, // sent data
strlen(line), // data length
&written, // bytes actually written
NULL))
panic("could not write to pipe");
}
// close the pipe
CloseHandle(pipe);
}
void child(void)
{
printf("Child process starting\n");
// retrieve communication pipe
HANDLE pipe = CreateFile(
PIPE_NAME, // name of the pipe
GENERIC_READ, // read ONLY access (or else the call will fail)
0, NULL, // junk
OPEN_EXISTING, // opens existing pipe
0, NULL); // more junk
if (pipe == INVALID_HANDLE_VALUE) panic("could not connect to the pipe");
// read father's input
for (;;)
{
char buffer[80];
DWORD read = 0;
if (!ReadFile(
pipe,
buffer, // read data
sizeof(buffer)-1, // max length (leave room for terminator)
&read, // bytes actually read
NULL))
break; // exit if the pipe has closed
// display what our father said
buffer[read] = '\0'; // make sure what we just read will be displayable as a string
printf("Father said: %s", buffer);
}
// close pipe
CloseHandle(pipe);
}
int main(int argc, char *argv[])
{
// wait for a <return> keypress on exit
atexit(getchar);
// decide whether we are the father or the child
if (!strcmp (argv[0], "child")) child();
else father(argv[0]);
printf("Done\n");
return 0;
}
#包括
#包括
#包括
//我们光荣的烟斗的名字
#定义管道名称L“\\.\\PIPE\\which”//unicode字符串
//出现致命错误时退出
无效恐慌(const char*msg)
{
fprintf(stderr,***PANIC***%s\n”,msg);
出口(-1);
}
//父进程
void-father(const-char*own_-name)//启动自身副本的可执行文件的名称
{
printf(“父进程启动\n”);
//创建一个名为管道的单向父->子管道
HANDLE管道=CreateNamedPipe(
管道名称,//管道的名称
管道\u访问\u出站,//仅发送
管道\类型\字节,//以字节流形式发送数据
1,//只有一个实例
0,0,0,NULL);//默认垃圾
如果(pipe==无效的_句柄_值)死机(“无法创建管道”);
//生成子进程
{
新创资讯科技有限公司;
处理信息;
零内存(&si,sizeof(si));
si.cb=sizeof(si);
零内存(&pi,sizeof(pi));
如果(!CreateProcessA(//使用ASCII变量与argv兼容
own\u name,//可执行文件名(我们自己)
“child”,//命令行。这将被视为argv[0]
NULL,NULL,FALSE,//默认垃圾
创建新控制台,//在另一个控制台窗口中启动
NULL,NULL,//更多垃圾
&si,&pi))//最终无用的垃圾
恐慌(“无法创建子进程”);
}
//连接到子进程
BOOL result=ConnectNamedPipe(管道,NULL);
如果(!result)死机(“无法连接到子进程”);
//和孩子说话
对于(;;)
{
//读取输入行
字符行[100];
printf(“说点什么>”);
如果(fgets(line,sizeof(line),stdin)==NULL)
恐慌(“无法读取标准输入”);
//空行退出
如果(!strcmp(行“\n”)中断;
//把电话给孩子
DWORD WRITED=0;
如果(!WriteFile(
管
行,//已发送数据
strlen(行),//数据长度
&已写入,//实际写入的字节数
空)
恐慌(“无法写入管道”);
}
//关上管子
闭柄(管);
}
无效子对象(无效)
{
printf(“子进程启动\n”);
//检索通信管道
HANDLE pipe=CreateFile(
管道名称,//管道的名称
GENERIC_READ,//只读访问(否则调用将失败)
0,NULL,//垃圾
打开现有管道,//打开现有管道
0,NULL);//更多垃圾
如果(管道==无效的_句柄_值)死机(“无法连接到管道”);
//阅读父亲的意见
对于(;;)
{
字符缓冲区[80];
DWORD read=0;
如果(!ReadFile(
管
缓冲区,//读取数据
sizeof(缓冲区)-1,//最大长度(为终止符留出空间)
&read,//实际读取的字节数
空)
break;//如果管道已关闭,则退出
//展示我们父亲说的话
buffer[read]='\0';//确保刚才读取的内容可以显示为字符串
printf(“父亲说:%s”,缓冲区);
}
//封闭管道
闭柄(管);
}
int main(int argc,char*argv[])
{
//在退出时等待按键
atexit(getchar);
//决定我们是父亲还是孩子
如果(!strcmp(argv[0],“child”))child();
else父亲(argv[0]);
printf(“完成”\n);
返回0;
}
很抱歉,我找不到一种优雅的方法来使用Ctrl-D作为退出信号。我能想到的唯一方法是再进行两次极其乏味的系统调用,我被这种前景吓坏了
因此,当用户输入空行时,父节点将终止
通过关闭管道,父亲将触发读取错误
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
// name of our glorious pipe
#define PIPE_NAME L"\\\\.\\pipe\\whatever" // bloody unicode string
// exit on fatal error
void panic(const char * msg)
{
fprintf(stderr, "***PANIC*** %s\n", msg);
exit(-1);
}
// father process
void father(const char * own_name) // name of our own executable to launch a copy of ourselve
{
printf("Father process starting\n");
// create a monodirectional father->child named pipe
HANDLE pipe = CreateNamedPipe (
PIPE_NAME, // name of the pipe
PIPE_ACCESS_OUTBOUND, // send only
PIPE_TYPE_BYTE, // send data as a byte stream
1, // only one instance
0, 0, 0, NULL); // default junk
if (pipe == INVALID_HANDLE_VALUE) panic("could not create pipe");
// spawn child process
{
STARTUPINFOA si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcessA( // using ASCII variant to be compatible with argv
own_name, // executable name (ourself)
"child", // command line. This will be seen as argv[0]
NULL, NULL, FALSE, // default junk
CREATE_NEW_CONSOLE, // launch in another console window
NULL, NULL, // more junk
&si, &pi)) // final useless junk
panic("could not create child process");
}
// connect to child process
BOOL result = ConnectNamedPipe(pipe, NULL);
if (!result) panic("could not connect to child process");
// talk to child
for (;;)
{
// read an input line
char line[100];
printf("Say something >");
if (fgets(line, sizeof(line), stdin) == NULL)
panic("could not read from standard input");
// exit on an empty line
if (!strcmp(line, "\n")) break;
// send the line to the child
DWORD written = 0;
if (!WriteFile(
pipe,
line, // sent data
strlen(line), // data length
&written, // bytes actually written
NULL))
panic("could not write to pipe");
}
// close the pipe
CloseHandle(pipe);
}
void child(void)
{
printf("Child process starting\n");
// retrieve communication pipe
HANDLE pipe = CreateFile(
PIPE_NAME, // name of the pipe
GENERIC_READ, // read ONLY access (or else the call will fail)
0, NULL, // junk
OPEN_EXISTING, // opens existing pipe
0, NULL); // more junk
if (pipe == INVALID_HANDLE_VALUE) panic("could not connect to the pipe");
// read father's input
for (;;)
{
char buffer[80];
DWORD read = 0;
if (!ReadFile(
pipe,
buffer, // read data
sizeof(buffer)-1, // max length (leave room for terminator)
&read, // bytes actually read
NULL))
break; // exit if the pipe has closed
// display what our father said
buffer[read] = '\0'; // make sure what we just read will be displayable as a string
printf("Father said: %s", buffer);
}
// close pipe
CloseHandle(pipe);
}
int main(int argc, char *argv[])
{
// wait for a <return> keypress on exit
atexit(getchar);
// decide whether we are the father or the child
if (!strcmp (argv[0], "child")) child();
else father(argv[0]);
printf("Done\n");
return 0;
}
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#define BUFSIZE 4096
/* child process's STDIN is the user input or data that you enter into the child process - READ */
HANDLE g_hChildStd_IN_Rd = NULL;
/* child process's STDIN is the user input or data that you enter into the child process - WRITE */
HANDLE g_hChildStd_IN_Wr = NULL;
/* child process's STDOUT is the program output or data that child process returns - READ */
HANDLE g_hChildStd_OUT_Rd = NULL;
/* child process's STDOUT is the program output or data that child process returns - WRITE */
HANDLE g_hChildStd_OUT_Wr = NULL;
void CreateChildProcess(void);
void WriteToPipe(CHAR chBuf[]);
void ReadFromPipe(void);
void ErrorExit(PTSTR);
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;
//child process's STDOUT is the program output or data that child process returns
// 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"));
//child process's STDIN is the user input or data that you enter into the child process
// 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.
CreateChildProcess();
/* variables */
char FAR *lpsz;
int cch;
CHAR chBuf[BUFSIZE];
DWORD dwRead = strlen(chBuf);
HANDLE hStdin;
BOOL bSuccess;
hStdin = GetStdHandle(STD_INPUT_HANDLE);
if (hStdin == INVALID_HANDLE_VALUE)
ExitProcess(1);
for (;;)
{
// Read from standard input and stop on error or no data.
bSuccess = ReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL);
if (!bSuccess || dwRead == 0)
break;
lpsz = &chBuf[0];
// Write to the pipe that is the standard input for a child process.
// Data is written to the pipe's buffers, so it is not necessary to wait
// until the child process is running before writing data.
WriteToPipe(lpsz);
printf("\n->Contents of %s written to child STDIN pipe.\n", argv[1]);
// Read from pipe that is the standard output for child process.
printf("\n->Contents of child process STDOUT:\n\n", argv[1]);
ReadFromPipe();
printf("\n->End of parent execution.\n");
// The remaining open handles are cleaned up when this process terminates.
// To avoid resource leaks in a larger application, close handles explicitly.
}
return 0;
}
void CreateChildProcess()
// Create a child process that uses the previously created pipes for STDIN and STDOUT.
{
TCHAR szCmdline[] = TEXT("cmd.exe /c \"C:\\path\\to\\exe\\program.exe -parameter C:\\path\\to\\file\\file.txt\"");
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,
szCmdline, // 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);
}
}
void WriteToPipe(CHAR chBuf[])
// Read from a file and write its contents to the pipe for the child's STDIN.
// Stop when there is no more data.
{
DWORD dwRead, dwWritten;
// CHAR chBuf[] = "hola\n";
dwRead = strlen(chBuf);
BOOL bSuccess = FALSE;
bSuccess = WriteFile(g_hChildStd_IN_Wr, chBuf, dwRead, &dwWritten, NULL);
if (!bSuccess) ErrorExit(TEXT("StdInWr Cannot write into child process."));
/*
// Close the pipe handle so the child process stops reading.
if (!CloseHandle(g_hChildStd_IN_Wr))
ErrorExit(TEXT("StdInWr CloseHandle"));
*/
}
void ReadFromPipe(void)
// Read output from the child process's pipe for STDOUT
// and write to the parent process's pipe for STDOUT.
// Stop when there is no more data.
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
WORD wResult = 0;
bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
if (!bSuccess || dwRead == 0) ErrorExit(TEXT("StdOutRd Cannot read child process's output."));
if (chBuf[0] == '+' && chBuf[1] == '?') { printf("It's misspelled."); }
else { printf("It's spelled correctly."); }
// bSuccess = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL);
// if (!bSuccess) ErrorExit(TEXT("StdOutWr Cannot write into parent process's output."));
}
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);
}