How do I redirect output to a file with CreateProcess?

39,070

Solution 1

You can't use stdout redirection in the command line passed to CreateProcess. To redirect stdout you need to specify a file handle for the output in the STARTUPINFO structure.

You are also making another, more subtle, mistake. The second parameter, lpCommandLine must point to writeable memory because CreateProcess overwrites the buffer. If you happen to be using the ANSI version of the function then you will get away with this, but not for the Unicode version.

The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.

Solution 2

The code below creates a console-less process with stdout and stderr redirected to the specified file.

#include <windows.h>


int _tmain(int argc, _TCHAR* argv[])
{
    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;       

    HANDLE h = CreateFile(_T("out.log"),
        FILE_APPEND_DATA,
        FILE_SHARE_WRITE | FILE_SHARE_READ,
        &sa,
        OPEN_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        NULL );

    PROCESS_INFORMATION pi; 
    STARTUPINFO si;
    BOOL ret = FALSE; 
    DWORD flags = CREATE_NO_WINDOW;

    ZeroMemory( &pi, sizeof(PROCESS_INFORMATION) );
    ZeroMemory( &si, sizeof(STARTUPINFO) );
    si.cb = sizeof(STARTUPINFO); 
    si.dwFlags |= STARTF_USESTDHANDLES;
    si.hStdInput = NULL;
    si.hStdError = h;
    si.hStdOutput = h;

    TCHAR cmd[]= TEXT("Test.exe 30");
    ret = CreateProcess(NULL, cmd, NULL, NULL, TRUE, flags, NULL, NULL, &si, &pi);

    if ( ret ) 
    {
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
        return 0;
    }

    return -1;
}

Solution 3

Microsoft has an example how to redirect the standard output: http://msdn.microsoft.com/en-us/library/ms682499(VS.85).aspx.

Solution 4

CreateProcess() launches processes, it is not a command line itnerpreter. It doesn't know what ">" is and won't do the stream redirection for you. You need to open the file test.txt yourself and pass the handle to it to CreateProcess inside the STARTUPINFO structure: CreateProcess STARTUPINFO

Share:
39,070

Related videos on Youtube

Paul Manta
Author by

Paul Manta

Updated on September 18, 2020

Comments

  • Paul Manta
    Paul Manta over 3 years

    I tried using CreateProcess to run a simple command like hg > test.txt. I tried running the string as a whole (as opposed to separating it into an application name and its parameters). Why does CreateProcess(0, "notepad.exe test.txt", ...) work but CreateProcess(0, "hg > test.txt", ...) does not?

    • cnicutar
      cnicutar over 12 years
      CreateProcess doesn't know about redirections. Why don't you use system(3) ? Let me guess: you can do it better than system(3).
    • Seth Carnegie
      Seth Carnegie over 12 years
      @cnicutar I've always wondered what the function(number) notation meant. What does system(3) mean?
    • cnicutar
      cnicutar over 12 years
      @Seth Carnegie The manual section. man 3 system.
    • Veger
      Veger over 12 years
      man 3 system for Windows??
    • MK.
      MK. over 12 years
      @cnicutar he most definitely can do it better than system (on Windows). System will launch cmd.exe and load all kinds of dependencies and cause all kinds of unnecessary things to happen.
    • André Caron
      André Caron over 12 years
      @cnicutar: Actually, CreateProcess() has a lpStartupInfo structure that takes handles to the redirected streams, so it does know about redirections. It just doesn't use the shell notation.
    • MK.
      MK. over 12 years
      @Seth that's from Unix, you type in man 3 system and it means look up documentation for system in the section 3 of the manual pages (APIs, built-in commands etc)
    • cnicutar
      cnicutar over 12 years
      @MK, André Caron Okay :-) I'm not sure if it's worth it in this case but I'll keep it in mind.
  • Frerich Raabe
    Frerich Raabe almost 12 years
    He's not necessarily making a mistake by not making the second parameter point to writeable memory. It's possible that he doesn't compile with UNICODE defined, in which case CreateProcess is CreateProcessA, which doesn't have this requirement.
  • David Heffernan
    David Heffernan almost 12 years
    @FrerichRaabe That's an implementation detail of the current versions of Windows. If you look at the MSDN documentation you will see that the type of the second parameter is LPTSTR. In any case, I made the very point that you make in my second paragraph.
  • Frerich Raabe
    Frerich Raabe almost 12 years
    @DavidHeffernan: I don't think it's an implementation detail since the documentation you quoted explicitely mentions that the ANSI version does not have this requirement. I'm mostly nitpicking though, because you first wrote "You are also making a mistake" and then you wrote "If you happen to be using the ANSI version". So you don't know if he's doing a mistake, because you don't know whether he's the ANSI version or not.
  • Nux
    Nux over 11 years
    Yeah, that kind of work, but remember there is a bug in that example that prevents ReadFromPipe from exiting. Before you call that function you need to call: CloseHandle(g_hChildStd_OUT_Wr);. Also you'll probably want to wait for the child process to exit before you close the handle to process with something like: WaitForSingleObject(piProcInfo.hProcess, INFINITE);.
  • Mooing Duck
    Mooing Duck over 10 years
    Description alongside the code would be handy. At least comments
  • SerG
    SerG almost 10 years
    Possible CloseHandle() of the file after the child process spawned is missed.
  • Delgan
    Delgan over 7 years
    Related: launch an exe/process with stdin stdout and stderr?. Also, see tiny-process-library which is very convenient.
  • Cristian Amarie
    Cristian Amarie about 7 years
    Shouldn't hStdInput be INVALID_HANDLE_VALUE instead of NULL?
  • Jeff Wilhite
    Jeff Wilhite about 5 years
    By the way, if you use STARTF_USESTDHANDLES and don't want to redirect one of the handles, you can do: si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);