如何在Windows中重定向std::cout和printf输出

3

我根据创建带有重定向输入和输出的子进程文章创建了一个程序,但是它无法使用std::cout和printf,因此从这样的程序中我只获得了“Hello, momma”字符串,cout和printf部分没有任何输出:

int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

    const char *buffer = "Hello, momma";

    std::cout << buffer << " - iostream version\n";

    printf("%s - stdio version", buffer);

    DWORD dwWritten = 0;
    WriteFile(hStdOut, buffer, strlen(buffer), &dwWritten, NULL);

    return 0;
}

问:我如何拦截cout和printf输出?我无法访问子程序的源代码,只需要拦截其输出。


如果仅运行子进程,则输出如下:

Hello, momma - iostream 版本

Hello, momma - stdio 版本Hello, momma

因此,您可以看到所有三个版本都已打印。


根据要求,这是父程序的代码:

void RedirectIO(HANDLE &hRead, HANDLE &hWrite)
{
    SECURITY_ATTRIBUTES attr;
    ZeroMemory(&attr, sizeof(attr));
    attr.nLength = sizeof(attr);
    attr.bInheritHandle = true;

    CreatePipe(&hRead, &hWrite, &attr, 0);
    SetHandleInformation(hRead, HANDLE_FLAG_INHERIT, 0);
}

bool CreateChild(std::string CommandLine, DWORD WaitTime, HANDLE hInRead, HANDLE hOutWrite)
{
    STARTUPINFO SI;
    PROCESS_INFORMATION PI;
    ZeroMemory(&SI, sizeof(SI));
    ZeroMemory(&PI, sizeof(PI));

    SI.cb = sizeof(SI);
    SI.hStdError = hOutWrite;
    SI.hStdInput = hInRead;
    SI.hStdOutput = hOutWrite;
    SI.dwFlags |= STARTF_USESTDHANDLES;

    bool success = CreateProcess(0, const_cast<char*>(CommandLine.c_str()), 0, 0, true, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, 0, 0, &SI,&PI);

    if (success)
    {
        WaitForSingleObject(PI.hProcess, WaitTime);
        CloseHandle(PI.hProcess);
        CloseHandle(PI.hThread);
    }

    return success;
}

int main()
{
    HANDLE hRead = nullptr;
    HANDLE hWrite = nullptr;

    RedirectIO(hRead, hWrite);
    CreateChild("stdouterrin.exe", INFINITE, nullptr, hWrite);

    DWORD ReadCount = 0;
    char Buffer[1024] = {0};

    std::string data = std::string();

    while(true)
    {
        if (!ReadFile(hRead, Buffer, sizeof(Buffer) / sizeof(char), &ReadCount, 0))
            break;

        if (!ReadCount) break;

        Buffer[ReadCount] = '\0';
        data.append(&Buffer[0], ReadCount);
        std::cout<<"Read From Child:\n\n"<<data.c_str()<<"\n";
    }

    return 0;
}

不要使用strlen,它很危险。WriteFile可能已经调用了它,并且不坚持您传递长度,但它知道更好。 - ctrl-alt-delor
很难理解你的结果,请将输出粘贴在代码下面的面板中。 - ctrl-alt-delor
1
@richard,strlen()有什么问题吗?当然WriteFile()不使用它,因为传递给WriteFile()的输入缓冲区不一定是以空字符结尾的字符串。相反,WriteFile()依赖于调用者知道如何计算正确的长度,在这种情况下,strlen()是正确的方法。 - bames53
1
我认为你应该展示重定向标准输出的父进程中的实际代码,而不仅仅是子进程的代码。 - bames53
1
@richard 他正在使用字符串字面量,这必然会产生一个带有正确终止空字符的字符串。硬编码长度比strlen()更容易出错。只要他使用char *,那么strlen()是最好的选择。也许你建议使用std::string,在这种情况下,我通常赞同。 - bames53
显示剩余7条评论
1个回答

1

你需要清空缓存。

cout << flush;
fflush(stdout);

return 0;之前。

我无法访问子程序的源代码,但我需要拦截其输出。 - Yola
@Yola 作为一个独立的程序,还是与你的代码链接在一起?如果是前者,请查找 popen() - πάντα ῥεῖ
@πάντα ῥεῖ 这是Windows操作系统。 - Yola
这并没有回答他的问题,你的代码如何与子程序通信?如果你无法访问子程序的代码,那么你是如何打印出子程序的代码的?或者上面的代码只是为了重新创建这个问题? - Nerf Herder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接