如何用 C 语言向子进程传递输入并检索输出

2023-12-05

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

我知道我必须使用创建进程方法但我不知道如何传递输入之类的条目并检索输出,我该怎么做?

我见过这个使用Java但我需要用C语言实现这个功能。


您可以尝试使用重定向的输入和输出创建一个子进程,我调整了找到的代码here

#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);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何用 C 语言向子进程传递输入并检索输出 的相关文章

随机推荐

  • DocuSign - RestApi v2 - 使用 C# 下载文档

    我正在尝试使用以下代码通过 RestAPI v2 检索签名文 档 url baseURL accounts 3602fbe5 e11c 44de 9e04 a9fc9aa2aad6 envelopes envId documents com
  • C# 的 ExpectedCondition 方法 attributeContains

    我试图使用 attributeContains 方法 但在使用 C 时没有可用的方法 https seleniumhq github io selenium docs api java org openqa selenium support
  • 在 R 中使用多个三点省略号[重复]

    这个问题在这里已经有答案了 有没有一种方法可以将任意参数传递给函数内的多个命令 以下功能显然不起作用 但我希望它能解释我想要实现的目标 test function x rnorm 20 y rnorm 20 plot x y type p
  • 如何使用 RVM 将 Ruby 更改为版本 1.9.3(再次)?

    我曾经在 Ubuntu 上使用 Ruby 版本 1 9 3 并进行了更新 这可能会破坏我的 bash 配置文件 我需要帮助将其恢复 而不是使用版本 1 8 7 现在rails s使用 Ruby 1 8 7 打开服务器 由于我在应用程序中使用
  • Redis 中的 Azure 缓存/DataCache 样式区域

    我正在计划将 C ASP Net Web 应用程序迁移到 Azure 当前托管在单个专用服务器上 并且正在考虑缓存选项 目前 由于我们一次只运行一个应用程序实例 因此我们有一个 进程内 内存缓存来缓解 SQL DB 的一些相同请求 目前的过
  • 在 Outlook 中设置特定文本的格式

    我需要格式化从 Outlook 中的 Excel 获取的特定字符串值 一旦 Excel 提供了该值 宏就会将该值附加到电子邮件中 我尝试测试并将值设置为粗体 但消息的所有内容都变成粗体 如何设置值的格式 以便我可以根据自己的喜好使用字体类型
  • 删除评论 - React js

    实际上 我一直在尝试向我的评论框系统添加 删除评论 功能 这是我的代码 var Comment React createClass handleClick function e e preventDefault var commentId
  • 部署到 Program Files 目录

    我开发了一个 C 应用程序 我想将其部署到C Program Files Company Name Product文件夹 我没有看到目标计算机上创建的 公司名称 文件夹 我将文件从 已发布 目录复制到记忆棒 拇指驱动器 上 我将记忆棒带到
  • 未按预期收到段错误

    我正在学习如何在 C 中使用指针和结构 当然 我会尝试故意破坏我的代码以进一步了解该语言的工作原理 这是一些按我预期工作的测试代码 include
  • 如何防止按 Enter 键时文本从文本区域中删除?

    当我在粉红色文本框中写入新文本并按enter新文本将在该框中更新 但是 如果我只是单击粉色文本框内部并且不进行任何更改 然后按enter 然后站在那里的文本被删除 它不应该被删除 如果我不做任何更改 那么已经存在的文本应该继续存在 func
  • getElementsByClassName() 具有两个类

    是否可以获取所有具有类的元素a or b using getElementsByClassName 只有一次 我更喜欢普通的 JavaScript 你不能这样做getElementsByClassName 方法改为使用querySelect
  • API安全:如何通过域限制访问?

    我公开了一个简单的 API 需要确保只有授权用户才能访问它 我将提供一个 API 密钥来进行身份验证 但是 我还想将 API 密钥关联到某个域 这意味着 只有在从授权域使用它时它才应该起作用 如何检查 API 端是否是从授权域访问的 HTT
  • 用两个图例更改 ggplot 中的两个图例标题

    我的 ggplot 上有两个图例 有两个不同的图例标题 自动创建自ggplot 现在 我想更改这个图例标题 labs colour legend name 仅更改第二个图例标题 我怎样才能改变第一个呢 样本数据 dataset lt str
  • 用c写一个push和pop

    原始问题 我正在尝试用 C 语言为一个项目创建这个计算器 我让数学函数正常工作 但我不知道如何处理推入和弹出 有人可以帮助我开始吗 我知道java中的push和pop应该做什么 但我不确定如何在不使用节点或数组的情况下使用它们 我的包含和堆
  • Windows 上使用 python 自动 NTLM

    如何在 Windows 上使用 python 的自动 NTLM 身份验证 我希望能够从 Windows 访问 TFS REST API 而无需对密码进行硬编码 就像从 Web 浏览器 例如 firefox 的 network automat
  • 如何在 VB.NET 中编写事件处理程序?

    我正在尝试在 VB NET 中测试非常简单的事件处理 到目前为止我有 Public Delegate Sub TestEventDelegate Public Event TestEvent As TestEventDelegate Sub
  • postgresql 9.3 中是否有任何技术可以使其开始返回 1 和 0 而不是布尔类型的“t”和“f”

    实际上 我正在将我的 ms sql 服务器迁移到 postgresql 9 3 并且我们使用 int 数据类型来存储布尔值的 1 和 0 但在 postgresql9 3 中这是不可能的 当我对 postgresql 的数据类型进行一些研究
  • 如何使用服务帐户获取域用户的数据?

    我正在开发一个企业应用程序 在其中使用 People API Directory APi 但是 我始终需要从特定用户进行自动检查 因为我无法使用服务帐户接收数据 如何使用服务帐户获取域用户的数据 我使用这段代码来连接谷歌API public
  • 如何使用 Http 客户端(带有可选更改)将 Symfony 请求转发到另一台服务器?

    如何拦截请求并发送HttpClient到另一台服务器并在进行一些修改后返回该服务器的响应 原始请求将包含数据和文件 我正在寻找最简单的解决方案 直到将原始原始正文复制为字符串 我遇到的问题是插入Request反对HttpClient要求以最
  • 如何用 C 语言向子进程传递输入并检索输出

    我在 Windows 中有一个 exe 程序 它在终端中的工作原理如下 gt program exe parameter01 file entry01 user types entry01 output01 entry02 user typ