Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C语言中将输入和输出传递给子进程_C_Createprocess_Child Process - Fatal编程技术网

如何在C语言中将输入和输出传递给子进程

如何在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[]或字符串形式接收输出 我知道我必须使

我在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[]或字符串形式接收输出

我知道我必须使用,但我不知道如何像输入一样传递条目并检索输出,我该怎么做

我已经看到了这一点,但我需要用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);
}