【问题标题】:Need help badly redirecting input and output from timer program on Windows需要帮助严重重定向 Windows 上计时器程序的输入和输出
【发布时间】:2017-01-29 00:31:23
【问题描述】:

我希望程序能够为两者重定向输入和输出 父进程和子进程。例如,

parent "child.exe > child_output.txt" > parent_output.txt

父母叫孩子。子输出到 child_output,父输出到父输出。

下面的示例代码应该可以工作,但不能。为方便起见,我在字符串“ToBeRun”中对孩子的重定向运算符进行了硬编码,而不是像在主程序中那样将其作为参数传递。

如果在命令行中没有将参数传递给父级,则子级输出会正确重定向到 child_output.txt。但是,如果您在命令行上重定向父参数,例如调用 parent.exe > parent_output.txt,则不会重定向父输出。 parent_output.txt 已创建,但在程序完成时为空。

#include <windows.h>

// COPY PASTED FROM Martins Mozeiko on Handmade Network:
// https://hero.handmade.network/forums/code-discussion/t/94
// these shouldn't have to be in here, but hey! What can you do?
#pragma function(memset)
void *memset(void *dest, int c, size_t count)
{
    char *bytes = (char *)dest;
    while (count--)
    {
        *bytes++ = (char)c;
    }
    return dest;
}

#pragma function(memcpy)
void *memcpy(void *dest, void *src, size_t count)
{
    char *dest8 = (char *)dest;
    char *src8 = (char *)src;
    while (count--)
    {
        *dest8++ = *src8++;
    }
    return dest;
}
/* Based on this msdn article
 * https://msdn.microsoft.com/en-us/library/windows/desktop   /ms682512(v=vs.85).aspx
 */
int main(void)
{
    // init structures for child process
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );

    // start child process and wait for it to finish
#if 0
    char *ToBeRun = "/C child.exe > child_result.txt";
#else
    // for your convenience, so you don't have to compile a sample child.exe
    char *ToBeRun = "/C dir > child_result.txt";
#endif
    if( !CreateProcess("C:\\WINDOWS\\system32\\cmd.exe", // Module name
                       ToBeRun,     // Command line
                       NULL,        // Process handle not inheritable
                       NULL,        // Thread handle not inheritable
                       FALSE,       // Set handle inheritance to FALSE
                       0,           // No creation flags
                       NULL,        // Use parent's environment block
                       NULL,        // Use parent's starting directory 
                       &si,         // Pointer to STARTUPINFO structure
                       &pi)  // Pointer to PROCESS_INFORMATION structure
    ) 
    {
        // create process failed
        return 1;
    }
    WaitForSingleObject(pi.hProcess, INFINITE);

    // print parent output string
    char String[] = "This is the parent's output";
    int StringLength = sizeof(String) / sizeof(String[0]);
    DWORD CharsWritten;
    HANDLE Handle = GetStdHandle(STD_OUTPUT_HANDLE);
    WriteConsole(Handle, String, StringLength, &CharsWritten, NULL);

    // close process and thread handles. 
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );
    return 0;
}

// required for compiling without CRT
void mainCRTStartup(void)
{
    int Result = main();
    ExitProcess(Result);
}

【问题讨论】:

  • 内核与重定向操作无关,它们是cmd.exe 所做的。我可以看到您的ToBeRun 字符串是错误的;它应该类似于cmd /c text.exe &gt; test_output.txt,但我不确定这是你的问题。父进程的重定向应该可以正常工作。你需要向我们展示一个minimal reproducible example
  • 感谢您的回复。很抱歉,帖子不符合最低要求。它已更新为最小、完整和可验证的示例。
  • 请将您的答案作为答案发布,而不是作为您问题的一部分。请注意,您不必检查它是否是控制台句柄,您可以使用WriteFile,它适用于控制台句柄文件句柄。 (虽然有些程序确实会检查,以便它们可以产生不同的输出,例如进度条或类似的东西,但写入文件没有意义。)
  • 另外,严格来说ToBeRun 应该以cmd /c 开头,而不仅仅是/c。按照惯例,命令行包含模块名称作为第一个标记。我相信您的部分代码将按照编写的方式工作,但这只是因为cmd.exe 明确处理了这种情况——它不适用于大多数其他可执行文件。 (Windows 不会为您将模块名称添加到命令行中。)

标签: c windows winapi cmd


【解决方案1】:

我回答了我自己的问题:简单地说,WriteConsole() 在写入重定向文件时失败。

因此,当写入重定向文件时,您需要使用恰当命名的 WriteFile()。

WriteFile() 可用于重定向输出和常规控制台输出,正如Harry Johnston 所指出的那样,您可以在这两种情况下都使用它。我就是这么做的。

或者,特别是如果您使用 Unicode,您可以使用 MSDN's advice 并通过调用 GetConsoleMode 检查 HANDLE 是文件句柄还是控制台句柄。如果 GetConsoleMode 返回 0,则它不是控制台。

您为什么要这样做? WriteConsole 与 WriteFile 不同,它是一个宏,可以变成 unicode 或 ASCII 函数,具体取决于是否定义了 UNICODE。

From MSDN

ReadFile 和 WriteFile 函数,或 ReadConsole 和 WriteConsole 函数,使应用程序能够读取控制台输入和写入控制台 输出为字符流。 ReadConsole 和 WriteConsole 的行为 与 ReadFile 和 WriteFile 完全相同,只是它们可以用作 宽字符函数(其中文本参数必须使用 Unicode)或作为 ANSI 函数(其中文本参数必须使用 > Windows 字符集)。需要维护单组的应用程序 支持 Unicode 或 ANSI 字符集的源应使用 ReadConsole 和 WriteConsole。

【讨论】:

    猜你喜欢
    • 2012-07-15
    • 2011-08-11
    • 1970-01-01
    • 1970-01-01
    • 2016-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-12
    相关资源
    最近更新 更多