使用管道从子进程进行 I/O 重定向 - winapi

2024-01-16

我正在使用一个提供 api 的应用程序,以便编写脚本更容易。基本上,当您编写有效的输入时,它会输出一个答案。我想使用该输出来发送更多输入,例如:

Input: <nodes>
Output: 1, 56, 23
Input <56>
Output: "Apple"

我想做的是一个写入目标进程 STDIN 的程序,然后从它的 STDOUT 读取输出。为此,我主要从那里获取代码:

创建具有重定向输入和输出的子进程 (Windows) - MSDN https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499%28v=vs.85%29.aspx

唯一的问题是,为了从子进程中读取数据,我首先需要关闭用于写入它的父进程的句柄,这意味着我无法使用子进程的输出向其写入更多内容。

下面是来自 msdn 的简化代码:

#include <Windows.h>
#include <string>

using std::string;

HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;

#define BUFSIZE 4096

void WriteToPipe(string msg); 
void ReadFromPipe(void); 

int main()
{
    /*
     * CREATE PIPES
    */

    SECURITY_ATTRIBUTES saAttr;

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

    // Create pipes for the child process's STDOUT and STDIN,
    // ensures both handle are not inherited
    CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0);
    SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0);

    CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0);
    SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0);

    /*
     * CREATE CHILD PROCESS
    */

    TCHAR szCmdline[]=TEXT("target.exe");
    STARTUPINFO siStartInfo;
    PROCESS_INFORMATION piProcInfo;

    // 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;

    CreateProcess(NULL, szCmdline, NULL, NULL, TRUE, 0,
                  NULL,  NULL, &siStartInfo, &piProcInfo);

    // 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(g_hChildStd_OUT_Wr);
    CloseHandle(g_hChildStd_IN_Rd);
    CloseHandle(piProcInfo.hProcess);
    CloseHandle(piProcInfo.hThread);

    /*
     * ACTUAL APPLICATION
    */

    WriteToPipe("<nodes>\n");

    // Need to close the handle before reading
    CloseHandle(g_hChildStd_IN_Wr); // PROBLEM HERE

    ReadFromPipe();

    WriteToPipe("<56>\n"); // I can't, as I have released the handle already

    system("pause");

    return 0;
}

void WriteToPipe(string msg)
{
    WriteFile(g_hChildStd_IN_Wr, msg.c_str(), msg.size(), NULL, NULL);
}

void ReadFromPipe(void)
{
    DWORD dwRead, dwWritten;
    CHAR chBuf[BUFSIZE];
    BOOL bSuccess = FALSE;
    HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

    for (;;)
    {
        bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
        if( ! bSuccess || dwRead == 0 ) break;

        bSuccess = WriteFile(hParentStdOut, chBuf, dwRead, &dwWritten, NULL);
        if (! bSuccess ) break;
    }
}

问题来自于这一行:

CloseHandle(g_hChildStd_IN_Wr);

要么我把它留在那里,读一次后我将无法写入我的子进程,要么我删除它,然后 ReadFromPipe 陷入僵局。

任何帮助将不胜感激,谢谢!


ReadFile(..., BUFSIZE)意思是“等到程序写入BUFSIZE字节,或关闭管道的末尾”。程序只写入少量字节,然后等待您没有提供的更多输入。如果您关闭写入管道,它就知道没有更多输入,然后退出,此时你的 ReadFile 知道没有更多的输入并返回。你需要找到一种方法来只读取管道中尽可能多的字节。

这里的神奇之处在于Peek命名管道 https://msdn.microsoft.com/en-us/library/windows/desktop/aa365779(v=vs.85).aspx,它告诉您程序输出了多少数据,以及您可以在不阻塞的情况下读取多少数据。请注意,您必须每隔一段时间检查一次,看看自上次检查以来程序是否写入了更多字节。

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

使用管道从子进程进行 I/O 重定向 - winapi 的相关文章

随机推荐

  • C#中strtr php函数的转换

    需要将此 php 代码转换为 C strtr input 是否存在等效的 C 函数 Damith Rahul Nikate Willem van Rumpt 您的解决方案通常有效 有一些特殊情况会产生不同的结果 echo strtr hi
  • 如何将 vuetify 2.0 beta 安装到新的 vue cli 项目中?

    Vuetify 2 0 0 beta 0 刚刚发布 我想尝试一下并在新的 vue 测试应用程序中使用 但是当我尝试将其安装到一个全新的项目中时出现错误 这是我已采取的步骤 I use vue cli v3 8 2使用默认设置创建一个新项目
  • MonoTouch SecKeyChain.Add 返回 SecStatusCode.Param

    我正在尝试像这样保存记录 var testRecord new SecRecord SecKind GenericPassword CreationDate DateTime UtcNow MatchCaseInsensitive fals
  • 使用 free() 时内存使用量不会减少[重复]

    这个问题在这里已经有答案了 我正在编写独立于操作系统的无锁队列 到目前为止效果很好 但内存管理存在小问题 我不确定是 gcc 问题还是我的问题 问题 当元素添加到列表时 内存会增加 但当元素从列表中删除时 free elementPoint
  • Recyclerview - 顶部项目应与下一个项目重叠,依此类推

    我已经为这样的项目设置了负边距 public class ItemDecorator extends RecyclerView ItemDecoration private final int mSpace public ItemDecor
  • 如何为 WAI-ARIA 的加载动画添加标签?

    我正在努力解决网页上的一些可访问性问题 我有一个充当对话框的 div 并且在某个时刻显示一个包含加载动画和文本 工作 的 div 我不确定如何标记这两个项目 以便正确通知盲人用户有进度动画并且它正在工作 他应该等待 div style di
  • 斯坦福 CoreNLP 创建 edu.stanford.nlp.time.TimeExpressionExtractorImpl 时出错

    我正在尝试学习斯坦福 CoreNLP 库 我在发布的示例中使用 C https sergeytihon wordpress com 2013 10 26 stanford corenlp is available on nuget for
  • PHP 控制运算符 (@) 不起作用

    The 控制操作员 http php net manual en language operators errorcontrol php用于使所有警告 错误保持沉默 无论后果是什么 我想使用这个疯狂的工具 但我想我有一些奇怪的服务器配置 即
  • 如何在 Angular 2+ 的引导模式中创建谷歌自动完成?

    我正在使用角度谷歌地图 agm 我通过以下方式创建了谷歌自动完成功能 in html
  • 如何观察数据库的变化以更新LiveData

    我正在从以下位置迁移应用程序LoaderManager with Callbacks到一个实现使用ViewModel and LiveData 我想继续使用现有的SQLiteDatabase 主要实现工作正常 这Activity实例化Vie
  • Graphql,react-apollo如何在加载组件状态时传输变量以进行查询

    我有一个简单的反应组件 必须在用户询问时从服务器加载数据 问题是我不知道如何传输动态变量speakerUrl并在组件加载状态之前访问它 当然我可以从this props params 但是组件未加载 当我进行 graphql 查询时我无法访
  • 为什么嵌套订阅不好?

    我知道应该避免嵌套订阅并应该使用 rxjs 运算符 但是我发现的有关此问题的文章通常只是说嵌套订阅不好 而没有解释原因 除了说 可能会导致问题 我想知道是否有人可以帮忙解决这个问题 谢谢 很高兴您提出这个问题 因为这是一个常见问题 考虑类似
  • 将输入数据从 android 发送到 php

    这些代码在按下按钮后执行 我正在尝试将字符串数据发送到我的服务器中的 php 文件 但在我按下按钮后应用程序已停止 我可以知道这里有什么问题吗 非常感谢任何帮助 D HttpClient client new DefaultHttpClie
  • go-mysql:从 go 应用程序容器连接到 mysql 容器时不支持身份验证插件

    我正在将我的 linux docker 环境从我的 Mac 移植到我的笔记本电脑 我有 2 个 docker 镜像 一个是mysql latest数据库图像 另一个是go alpine应用程序服务器映像 在我的 Mac 上 我使用 bash
  • 使用 DateFormatter 将开始日期重置为 1970 年

    我有一个数据框 其中索引是每个月的第一个日期 size列是该月的频率 例如 Using index在数据帧上确认索引的类型是DatetimeIndex DatetimeIndex 2006 12 01 dtype datetime64 ns
  • Android Wear - 通知 - 图像跨度不起作用

    我在 Android 磨损通知中使用 ImageSpan 在通知中设置样式 但它不起作用 请告诉我如何在通知中使用 ImageSpan 的过程 如有帮助 我们将不胜感激 以下是我正在使用的示例代码 SpannableStringBuilde
  • 平方和递归[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我必须编写一个递归函数 sumSqu
  • 使用 Spring 控制器从 JavaScript 生成的表单提交列表 [重复]

    这个问题在这里已经有答案了 我正在使用 Spring Boot MVC 模式和 Thymeleaf 作为模板引擎构建一个应用程序 我有一个使用 JavaScript 生成列表的表单 以及一个带有 ModelAttribute期望将列表保存到
  • gcc 将所有警告视为错误,除了 X

    由于最好不提及的原因 我想将所有警告视为错误 除了一个警告 已弃用 我想将其视为警告 有没有比手动列出我想要视为错误的所有警告更方便的方法 你可以做 Werror Wno error deprecated
  • 使用管道从子进程进行 I/O 重定向 - winapi

    我正在使用一个提供 api 的应用程序 以便编写脚本更容易 基本上 当您编写有效的输入时 它会输出一个答案 我想使用该输出来发送更多输入 例如 Input