Writing to stdout with DETACHED_PROCESS

Dragusanu, Andrei Valentin 21 Reputation points
2021-12-21T20:24:33.667+00:00

It seems that a child process launched with CreateProcess using the DETACHED_PROCESS flag is able to only write 4096 bytes to stdout, then following writes start to fail. Using CREATE_NO_WINDOW instead of DETACHED_PROCESS does not seem have this problem.

I understand that DETACHED_PROCESS does not have an actual console at all and one should be created or attached (e.g. using AllocConsole), but does that also mean that outputing to stdout should also fail?

Code sample

Child process:

#include <fstream>

int main()
{
    // Write the return value of printf (written byte count) to file.
    // Expected:
    //   4
    //   4095
    //   4096
    //   4100

    std::ofstream{R"(C:\logs\out.txt)"} 
        << printf("test") << '\n' 
        << printf("%0*d\n", 4094, 0) << '\n' 
        << printf("%0*d\n", 4095, 0) << '\n' 
        << printf("%0*d\n", 4099, 0);
}

Parent process:

#include <Windows.h>

int main()
{
    wchar_t process[] = L"stdout-test.exe";

    auto sui     = STARTUPINFO{};
    auto dwFlags = DWORD{ DETACHED_PROCESS }; // CREATE_NO_WINDOW works
    auto pi      = PROCESS_INFORMATION{};

    const auto ret = CreateProcess(nullptr, process, nullptr, nullptr, FALSE, dwFlags, nullptr, nullptr, &sui, &pi);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    return ret ? 0 : -1;
}
Windows development | Windows API - Win32
0 comments No comments
{count} votes

Accepted answer
  1. RLWA32 49,536 Reputation points
    2021-12-21T22:41:52.117+00:00

    When you create a console process using DETACHED_PROCESS the stdout stream is not associated with an output stream. Refer to _fileno function which is used to return the file descriptor for a stream. In this case, the function will return -2 to indicate this condition. So yes, it makes sense that writing to stdout should fail.

    You can see this as follows -

        std::string s("File descriptor for stdout is ");  
        s += std::to_string(_fileno(stdout));  
        MessageBoxA(NULL, s.c_str(), "File Descriptor - stdout", MB_OK);  
      
        std::ofstream{ R"(out.txt)" }  
            << printf("test") << '\n'  
            << printf("%0*d\n", 4094, 0) << '\n'  
            << printf("%0*d\n", 4095, 0) << '\n'  
            << printf("%0*d\n", 4099, 0);  
      
    

    If you should decide to allocate a console for a console application started with DETACHED_PROCESS you will also need to reopen the standard input, output and error streams.

    For example,

        if (AllocConsole())  
        {  
            FILE* fpstdin = stdin, * fpstdout = stdout, * fpstderr = stderr;  
      
            freopen_s(&fpstdin, "CONIN$", "r", stdin);  
            freopen_s(&fpstdout, "CONOUT$", "w", stdout);  
            freopen_s(&fpstderr, "CONOUT$", "w", stderr);  
        }  
      
      
    
    1 person found this answer helpful.
    0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.