【问题标题】:Can I send output from a Windows child process to the parent?我可以将 Windows 子进程的输出发送到父进程吗?
【发布时间】:2023-03-05 05:48:01
【问题描述】:

除了为标准输入/输出/错误创建管道之外,Win32 API 中是否有任何简单的方法可以将这些句柄重定向到父进程?如果子进程有一个控制台窗口,则输出/错误似乎会转到它,而不是父进程的控制台窗口,即使句柄是继承的。我真正想要的是一个无窗口的子进程将其输出/错误发送到父控制台(容易吗?)。建议表示赞赏。

【问题讨论】:

  • 进程运行后不​​能重定向进程的 STD(IN|OUT|ERR)。重定向在进程创建时处理,因此父进程必须在创建子进程时提供替代的 STD(IN|OUT|ERR) 句柄。但是,进程之间还有很多其他方式可以在完全不依赖 STD(IN|OUT|ERR) 的情况下交换数据 - 命名管道、邮槽、套接字、共享内存/文件、窗口消息、ActiveX/COM、RPC , 仅举几个。使用你想让孩子向父母发送数据的任何东西,然后父母可以根据需要在自己的窗口中显示数据。

标签: windows winapi


【解决方案1】:

如果只想显示子进程的stdoutstderr到父进程的控制台,可以在子进程中使用AttachConsole(ATTACH_PARENT_PROCESS)附加到父进程的控制台。或者在parent中,指定CreateProcessdwCreationFlags为0,根据Creation of a Console

默认情况下,控制台进程继承其父控制台。

(不能保证输入会被预期的进程接收。请确保您不需要为子进程使用标准输入)

但是,此方法无法与父进程交互。如果父进程需要获取这些输出数据,仍然需要通过进程间通信将数据发送给父进程。

该方法允许子进程和父进程使用同一个控制台,但是父进程不能直接获取子进程的输出数据。如果父进程需要获取数据,仍然需要使用Interprocess Communications将数据发送给父进程。

编辑:

这里是示例

孩子:

#include <windows.h>
#include <iostream>
int main(VOID)
{
    AttachConsole(ATTACH_PARENT_PROCESS);
    int i = 5;
    while (i--)
    {
        printf("printf\n");
        std::cout << "child " << i << std::endl;
        fflush(stdout);
        Sleep(1000);
    }
    return 0;
}

父母:

#include <windows.h>
#include <iostream>
int main()
{
    STARTUPINFO si = {};
    si.cb = sizeof(STARTUPINFO);
    PROCESS_INFORMATION pi = {};
    WCHAR cmd[] = L"Path\\child.exe";
    SECURITY_ATTRIBUTES se = {};
    se.nLength = sizeof(SECURITY_ATTRIBUTES);
    se.bInheritHandle = true;
    se.lpSecurityDescriptor = NULL;
    HANDLE hFile = CreateFileW(L"test.txt", GENERIC_WRITE, FILE_SHARE_READ, &se, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
    BOOL ret = SetStdHandle(STD_OUTPUT_HANDLE, hFile);
    printf("parent1\n");
    ret = CreateProcessW(cmd, NULL, 0, 0, 1, 0, 0, 0, &si, &pi);
    std::cout << "parent2 " << std::endl;
    WaitForSingleObject(pi.hProcess,INFINITE);
    system("pause");
}

结果:

另一个示例:

孩子

int main(VOID)
{
    //AttachConsole(ATTACH_PARENT_PROCESS);
    int i = 5;
    while (i--)
    {
        printf("printf\n");
        std::cout << "child " << i << std::endl;
        fflush(stdout);
        Sleep(1000);
    }
    return 0;
}

父母

int main()
{
    SECURITY_ATTRIBUTES se = {};
    se.nLength = sizeof(SECURITY_ATTRIBUTES);
    se.bInheritHandle = true;
    se.lpSecurityDescriptor = NULL;
    HANDLE hFile = CreateFileW(L"test.txt", GENERIC_WRITE, FILE_SHARE_READ, &se, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
    BOOL ret = SetStdHandle(STD_OUTPUT_HANDLE, hFile);

    printf("parent1\n");
    STARTUPINFO si = {};
    si.cb = sizeof(STARTUPINFO);
    si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
    si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    si.dwFlags |= STARTF_USESTDHANDLES;
    PROCESS_INFORMATION pi = {};
    WCHAR cmd[] = L"Path\\child.exe";

    CreateProcessW(cmd, NULL, 0, 0, 1, 0, 0, 0, &si, &pi);
    
    std::cout << "parent2 " << std::endl;
    WaitForSingleObject(pi.hProcess, INFINITE);
    system("pause");
}

【讨论】:

  • 我没有看到使用0 作为CreateProcess 的标志,而不是CREATE_NO_WINDOW,但AttachConsole(ATTACH_PARENT_PROCESS) 确实将子输出发送到父屏幕。奇怪的是,打开一个文件并在父级中使用SetStdHandle(STD_OUTPUT_HANDLE, h),其中h 是文件的句柄,消除了控制台窗口的输出,但文件仍然是空的。非常混乱。
  • SetStdHandle 不能影响当前进程的 CRT 句柄(由printf() std::cout...使用)见this issue,但我可以得到子进程的输出以下步骤调用AttachConsole。您是否以写入权限打开文件?
  • 我已经添加了我正在使用的示例。查看更新。
  • 感谢您提供的出色示例。向后工作我发现在CreateProcess 中将bInheritHandles 设置为TRUE 会破坏您演示的行为并将stdout/stderr 发送到某个未知的地方。我设置了这个标志,以便将管道句柄传递给孩子。我还没有找到解释这种行为的文档。
  • 这是因为CreateFile返回的句柄默认不能被继承。您需要指定lpSecurityAttributes 参数。而且我发现也可以不用管道直接将父进程的stdout/stderr重定向到子进程,我更新了这两个示例。
猜你喜欢
  • 2010-11-08
  • 1970-01-01
  • 2012-07-04
  • 1970-01-01
  • 2014-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多