Solved

C/C++ programming - redirect stdin and stdout to files

Posted on 2011-02-16
8
1,413 Views
Last Modified: 2012-06-21
Need example of C/C++ program that can run another executable and redirect its stdout and stderr to files.

Thanks.
0
Comment
Question by:longjumps
  • 4
  • 3
8 Comments
 
LVL 86

Accepted Solution

by:
jkr earned 400 total points
ID: 34910090
Since you're apparently on Windows, here's the "Full bells and whistles" approach my MS itself: http://support.microsoft.com/default.aspx?scid=kb;en-us;190351 ("How to spawn console processes with redirected standard handles"):
/*++

      Copyright (c) 1998  Microsoft Corporation

      Module Name:

         Redirect.c

      Description:
          This sample illustrates how to spawn a child console based
          application with redirected standard handles.

          The following import libraries are required:
          user32.lib

      Dave McPherson (davemm)   11-March-98

   --*/ 

   #include<windows.h>
   #pragma comment(lib, "User32.lib")
   void DisplayError(char *pszAPI);
   void ReadAndHandleOutput(HANDLE hPipeRead);
   void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut,
                                     HANDLE hChildStdIn,
                                     HANDLE hChildStdErr);
   DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam);

   HANDLE hChildProcess = NULL;
   HANDLE hStdIn = NULL; // Handle to parents std input.
   BOOL bRunThread = TRUE;


   void main ()
   {
      HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
      HANDLE hInputWriteTmp,hInputRead,hInputWrite;
      HANDLE hErrorWrite;
      HANDLE hThread;
      DWORD ThreadId;
      SECURITY_ATTRIBUTES sa;


      // Set up the security attributes struct.
      sa.nLength= sizeof(SECURITY_ATTRIBUTES);
      sa.lpSecurityDescriptor = NULL;
      sa.bInheritHandle = TRUE;


      // Create the child output pipe.
      if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0))
         DisplayError("CreatePipe");


      // Create a duplicate of the output write handle for the std error
      // write handle. This is necessary in case the child application
      // closes one of its std output handles.
      if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite,
                           GetCurrentProcess(),&hErrorWrite,0,
                           TRUE,DUPLICATE_SAME_ACCESS))
         DisplayError("DuplicateHandle");


      // Create the child input pipe.
      if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0))
         DisplayError("CreatePipe");


      // Create new output read handle and the input write handles. Set
      // the Properties to FALSE. Otherwise, the child inherits the
      // properties and, as a result, non-closeable handles to the pipes
      // are created.
      if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp,
                           GetCurrentProcess(),
                           &hOutputRead, // Address of new handle.
                           0,FALSE, // Make it uninheritable.
                           DUPLICATE_SAME_ACCESS))
         DisplayError("DupliateHandle");

      if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp,
                           GetCurrentProcess(),
                           &hInputWrite, // Address of new handle.
                           0,FALSE, // Make it uninheritable.
                           DUPLICATE_SAME_ACCESS))
      DisplayError("DupliateHandle");


      // Close inheritable copies of the handles you do not want to be
      // inherited.
      if (!CloseHandle(hOutputReadTmp)) DisplayError("CloseHandle");
      if (!CloseHandle(hInputWriteTmp)) DisplayError("CloseHandle");


      // Get std input handle so you can close it and force the ReadFile to
      // fail when you want the input thread to exit.
      if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) ==
                                                INVALID_HANDLE_VALUE )
         DisplayError("GetStdHandle");

      PrepAndLaunchRedirectedChild(hOutputWrite,hInputRead,hErrorWrite);


      // Close pipe handles (do not continue to modify the parent).
      // You need to make sure that no handles to the write end of the
      // output pipe are maintained in this process or else the pipe will
      // not close when the child process exits and the ReadFile will hang.
      if (!CloseHandle(hOutputWrite)) DisplayError("CloseHandle");
      if (!CloseHandle(hInputRead )) DisplayError("CloseHandle");
      if (!CloseHandle(hErrorWrite)) DisplayError("CloseHandle");


      // Launch the thread that gets the input and sends it to the child.
      hThread = CreateThread(NULL,0,GetAndSendInputThread,
                              (LPVOID)hInputWrite,0,&ThreadId);
      if (hThread == NULL) DisplayError("CreateThread");


      // Read the child's output.
      ReadAndHandleOutput(hOutputRead);
      // Redirection is complete


      // Force the read on the input to return by closing the stdin handle.
      if (!CloseHandle(hStdIn)) DisplayError("CloseHandle");


      // Tell the thread to exit and wait for thread to die.
      bRunThread = FALSE;

      if (WaitForSingleObject(hThread,INFINITE) == WAIT_FAILED)
         DisplayError("WaitForSingleObject");

      if (!CloseHandle(hOutputRead)) DisplayError("CloseHandle");
      if (!CloseHandle(hInputWrite)) DisplayError("CloseHandle");
   }


   /////////////////////////////////////////////////////////////////////// 
   // PrepAndLaunchRedirectedChild
   // Sets up STARTUPINFO structure, and launches redirected child.
   /////////////////////////////////////////////////////////////////////// 
   void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut,
                                     HANDLE hChildStdIn,
                                     HANDLE hChildStdErr)
   {
      PROCESS_INFORMATION pi;
      STARTUPINFO si;

      // Set up the start up info struct.
      ZeroMemory(&si,sizeof(STARTUPINFO));
      si.cb = sizeof(STARTUPINFO);
      si.dwFlags = STARTF_USESTDHANDLES;
      si.hStdOutput = hChildStdOut;
      si.hStdInput  = hChildStdIn;
      si.hStdError  = hChildStdErr;
      // Use this if you want to hide the child:
      //     si.wShowWindow = SW_HIDE;
      // Note that dwFlags must include STARTF_USESHOWWINDOW if you want to
      // use the wShowWindow flags.


      // Launch the process that you want to redirect (in this case,
      // Child.exe). Make sure Child.exe is in the same directory as
      // redirect.c launch redirect from a command line to prevent location
      // confusion.
      if (!CreateProcess(NULL,"Child.EXE",NULL,NULL,TRUE,
                         CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi))
         DisplayError("CreateProcess");


      // Set global child process handle to cause threads to exit.
      hChildProcess = pi.hProcess;


      // Close any unnecessary handles.
      if (!CloseHandle(pi.hThread)) DisplayError("CloseHandle");
   }


   /////////////////////////////////////////////////////////////////////// 
   // ReadAndHandleOutput
   // Monitors handle for input. Exits when child exits or pipe breaks.
   /////////////////////////////////////////////////////////////////////// 
   void ReadAndHandleOutput(HANDLE hPipeRead)
   {
      CHAR lpBuffer[256];
      DWORD nBytesRead;
      DWORD nCharsWritten;

      while(TRUE)
      {
         if (!ReadFile(hPipeRead,lpBuffer,sizeof(lpBuffer),
                                          &nBytesRead,NULL) || !nBytesRead)
         {
            if (GetLastError() == ERROR_BROKEN_PIPE)
               break; // pipe done - normal exit path.
            else
               DisplayError("ReadFile"); // Something bad happened.
         }

         // Display the character read on the screen.
         if (!WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),lpBuffer,
                           nBytesRead,&nCharsWritten,NULL))
            DisplayError("WriteConsole");
      }
   }


   /////////////////////////////////////////////////////////////////////// 
   // GetAndSendInputThread
   // Thread procedure that monitors the console for input and sends input
   // to the child process through the input pipe.
   // This thread ends when the child application exits.
   /////////////////////////////////////////////////////////////////////// 
   DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam)
   {
      CHAR read_buff[256];
      DWORD nBytesRead,nBytesWrote;
      HANDLE hPipeWrite = (HANDLE)lpvThreadParam;

      // Get input from our console and send it to child through the pipe.
      while (bRunThread)
      {
         if(!ReadConsole(hStdIn,read_buff,1,&nBytesRead,NULL))
            DisplayError("ReadConsole");

         read_buff[nBytesRead] = '\0'; // Follow input with a NULL.

         if (!WriteFile(hPipeWrite,read_buff,nBytesRead,&nBytesWrote,NULL))
         {
            if (GetLastError() == ERROR_NO_DATA)
               break; // Pipe was closed (normal exit path).
            else
            DisplayError("WriteFile");
         }
      }

      return 1;
   }


   /////////////////////////////////////////////////////////////////////// 
   // DisplayError
   // Displays the error number and corresponding message.
   /////////////////////////////////////////////////////////////////////// 
   void DisplayError(char *pszAPI)
   {
       LPVOID lpvMessageBuffer;
       CHAR szPrintBuffer[512];
       DWORD nCharsWritten;

       FormatMessage(
                FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
                NULL, GetLastError(),
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                (LPTSTR)&lpvMessageBuffer, 0, NULL);

       wsprintf(szPrintBuffer,
         "ERROR: API    = %s.\n   error code = %d.\n   message    = %s.\n",
                pszAPI, GetLastError(), (char *)lpvMessageBuffer);

       WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),szPrintBuffer,
                     lstrlen(szPrintBuffer),&nCharsWritten,NULL);

       LocalFree(lpvMessageBuffer);
       ExitProcess(GetLastError());
   }

   ////////////////////////////////////////////////////////////////////// 
   // child.c
   // Echoes all input to stdout. This will be redirected by the redirect
   // sample. Compile and build child.c as a Win32 Console application and
   // put it in the same directory as the redirect sample.
   // 
   #include<windows.h>
   #include<stdio.h>
   #include<string.h>

   void main ()
   {
      FILE*    fp;
      CHAR     szInput[1024];


      // Open the console. By doing this, you can send output directly to
      // the console that will not be redirected.

      fp = fopen("CON", "w");
      if (!fp) {
         printf("Error opening child console - perhaps there is none.\n");
         fflush(NULL);
      }
      else
      {

      // Write a message direct to the console (will not be redirected).

         fprintf(fp,"This data is being printed directly to the\n");
         fprintf(fp,"console and will not be redirected.\n\n");
         fprintf(fp,"Since the standard input and output have been\n");
         fprintf(fp,"redirected data sent to and from those handles\n");
         fprintf(fp,"will be redirected.\n\n");
         fprintf(fp,"To send data to the std input of this process.\n");
         fprintf(fp,"Click on the console window of the parent process\n");
         fprintf(fp,"(redirect), and enter data from it's console\n\n");
         fprintf(fp,"To exit this process send the string 'exit' to\n");
         fprintf(fp,"it's standard input\n");
         fflush(fp);
      }

      ZeroMemory(szInput,1024);
      while (TRUE)
      {
         gets(szInput);
         printf("Child echoing [%s]\n",szInput);
         fflush(NULL);  // Must flush output buffers or else redirection
                        // will be problematic.
         if (!_stricmp(szInput,"Exit") )
            break;

         ZeroMemory(szInput,strlen(szInput) );

      }
   }

Open in new window

0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 400 total points
ID: 34910109
BTW, alternatively, you could also use

system("cmd.exe /c file.exe 1>&2 output.txt");

Yet' I'd rather suggest going the API way as outlined by MS.
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 400 total points
ID: 34910362
Oh, and here's a simplified example achieveing the same using regular pipes - the whole thing is a thread, so just omit the sync'ing:
ULONG   __stdcall   ExecuteJob  (   LPVOID  pv)
{
    PRNENGJOB*  pJob    =   ( PRNENGJOB*) pv;

    BOOL                bRes;
    int                 nErr;

    STARTUPINFO         si;
    PROCESS_INFORMATION pi;

    HANDLE              hMyIn;
    HANDLE              hMyErr;

    HANDLE              hStdIn;
    HANDLE              hStdOut;
    HANDLE              hStdErr;

    DWORD               dwFlags;

    DWORD               dwWritten;
    DWORD               dwRead;
    DWORD               dwReadTotal;

    char                acWork1         [   MAX_PATH];
    char                acWork2         [   MAX_PATH];

    char                acCmdLine    [   256];
    char                acOut        [   IR_LA_OUTPUT_BUFSIZ];
    char                acOutFile    [   MAX_PATH];
    char                acInFile     [   MAX_PATH];
    char                acLogFile    [   MAX_PATH];
    char                acCtrlFile   [   MAX_PATH];
    char*               pc;

    SECURITY_ATTRIBUTES sa;


    // Copy the file names to local buffers and wipe off the path information.
    // Necessary because the process doesn't like quoted file names, and the paths
    // could contain spaces.
    lstrcpyn    (   acInFile,    pJob->acInpFile, MAX_PATH);
    if  (   pc  =   strrchr (   acInFile,    '\\'))
            lstrcpy (   acInFile,    ++pc);

    lstrcpyn    (   acCtrlFile,  pJob->acCtrlFile,    MAX_PATH);
    if  (   pc  =   strrchr (   acCtrlFile,  '\\'))
            lstrcpy (   acCtrlFile,  ++pc);

    // Set up the cmd line
    wsprintf    (   acCmdLine,   
                    "&%s %s\n%s\n",
                    pJob->acFmtFile,
                    acInFile,
                    acCtrlFile
                );

    DBG1 (   "ExecuteJob():\tusing cmdline '%s'\n",
                acCmdLine
            );

    ZeroMemory  (   &sa,    sizeof  (   SECURITY_ATTRIBUTES));

    sa.nLength              =   sizeof  (   SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor =   NULL;
    sa.bInheritHandle       =   TRUE;

    dwFlags =       FILE_ATTRIBUTE_NORMAL 
                |   FILE_ATTRIBUTE_TEMPORARY;

    // create 's stdin pipe
    if  (   !CreatePipe (   &hStdIn,    &hMyIn,     &sa,    0))
        {
            DBG1 (   "ExecuteJob():\tCreatePipe() for stdin failed, reason == %d\n",
                        GetLastError    ()
                    );

            return  ( E_FAIL);
        }

    // create 's stdout pipe
    if  (   !CreatePipe (   &hMyErr,    &hStdErr,   &sa,    0))
        {
            DBG1 (   "ExecuteJob():\tCreatePipe() stderr failed, reason == %d\n",
                        GetLastError    ()
                    );

            return  ( E_FAIL);
        }

    // make up the output file name
    lstrcpyn    (   acLogFile,   pJob->acInpFile, MAX_PATH);
    lstrcat     (   acLogFile,   ".out");

    DBG1 (   "ExecuteJob():\t output is redirected to '%s'\n",
                acLogFile
            );

    // 's stdout will be a temporary file, what the hell should we do
    // with all the useless output?
    hStdOut =   CreateFile  (   acLogFile,
                                GENERIC_WRITE,
                                FILE_SHARE_READ | FILE_SHARE_WRITE,
                                &sa,
                                CREATE_ALWAYS,
                                dwFlags | FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_SEQUENTIAL_SCAN,
                                NULL
                            );

    ZeroMemory  (   &si,    sizeof  (   STARTUPINFO));

    si.cb           =   sizeof  (   STARTUPINFO);
    si.dwFlags      =   STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    si.wShowWindow  =   SW_HIDE;
    si.hStdInput    =   hStdIn;
    si.hStdOutput   =   hStdOut;
    si.hStdError    =   hStdErr;

    sprintf (   acWork1,    "%s\\bin\\process.exe",  g_acSystemDir);
    sprintf (   acWork2,    "%s\\work\\",	g_acSystemDir);

    // run up  with the main thread suspended - this ensures that all
    // instances of  have initialized when the client sets the start event
    bRes    =   CreateProcess   (   acWork1,
                                    NULL,
                                    NULL,
                                    NULL,
                                    TRUE,
                                    NORMAL_PRIORITY_CLASS | CREATE_SUSPENDED,
                                    GetEnvironmentStrings   (),
                                    acWork2,
                                    &si,
                                    &pi
                                );

    // wait with patience .....
    WaitForSingleObject (   pJob->hEventStart,  INFINITE);

    if  (   bRes)
        {
            // ok let the party go on...
            VERIFY  (   ResumeThread    (   pi.hThread));
            VERIFY  (   CloseHandle (   pi.hThread));

            // write the command to the process's stdin
            if  (   !WriteFile  (   hMyIn,  
                                    acCmdLine,
                                    lstrlen (   acCmdLine),
                                    &dwWritten,
                                    NULL
                                )
                )
                {
                    // error ???
                    nErr    =   GetLastError    ();

                    DBG1 (   "ExecuteJob():\tERROR writing  cmdline, reason == %d\n", 
                                nErr
                            );

                    // killing it (not) softly!
                    VERIFY  (   TerminateProcess    (   pi.hProcess,    0));

                    VERIFY  (   CloseHandle (   hMyIn));
                    VERIFY  (   CloseHandle (   hMyErr));
                    VERIFY  (   CloseHandle (   hStdIn));
                    VERIFY  (   CloseHandle (   hStdOut));
                    VERIFY  (   CloseHandle (   hStdErr));

                    return  (   E_FAIL);
                }

            dwRead  =   dwReadTotal =   0;

            pc  =   acOut;
            WaitForSingleObject (   pi.hProcess,    INFINITE);

            VERIFY  (   CloseHandle (   pi.hProcess));
        }
     else
        {
            nErr    =   GetLastError    ();

            DBG1 (   "ExecuteJob():\tERROR creating process, reason == %d\n",    
                        nErr
                    );

            SetEvent    (   pJob->hEventDone);

            return  (   nErr);
        }

    // close the handles & check if successfull - if not, something really
    // horrible happened, and we can't trust anything, so why not _assert() ;-)
    VERIFY  (   CloseHandle (   hMyIn));
    VERIFY  (   CloseHandle (   hMyErr));
    VERIFY  (   CloseHandle (   hStdIn));
    VERIFY  (   CloseHandle (   hStdOut));
    VERIFY  (   CloseHandle (   hStdErr));

    // the  produces a  file with the same name as the input file.
    // Therefore, we make it up by simply replacing the extension
    lstrcpy (   acOutFile,   pJob->acInpFile);
    // trust _NOTHING_!!!
    if  (   pc  =   strstr  (   acOutFile,   "."))
        {
            *pc =   0;

            strcat  (   acOutFile,   ".ext");
        }
     else   strcat  (   acOutFile,   ".ext");

    if  (   0xffffffff  ==  GetFileAttributes   (   acOutFile))
        {
            DBG1 (   "ExecuteJob():\tERROR: file '%s' does NOT EXIST!!!\n",   
                        acOutFile
                    );

            // signal to the client side DLL that we're done ...
            SetEvent    (   pJob->hEventDone);

            return  (   E_UNEXPECTED);
        }

    // store the file name in the appropriate location
    lstrcpy (   pJob->acFile, acOutFile);

    // signal to the client side DLL that we're done ... 
    // SUCCESSFULLY done, i mean!
    DBG0 (   "ExecuteJob():\tdone... setting event\n");
    SetEvent    (   pJob->hEventDone);

    ExitThread  (   NOERROR);

    return  (   NOERROR);
}

Open in new window

0
 
LVL 1

Author Comment

by:longjumps
ID: 34913695
jrk, thanks.

How can I compile
system("cmd.exe /c file.exe 1>&2 output.txt");

in MS Visual Studio 2010?

It seems C code, isn't?

0
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
LVL 1

Author Comment

by:longjumps
ID: 34913975
It is not passing compile.

What I am doing wrong?

/ ddProxyEXE.cpp : main project file.

#include "stdafx.h"

using namespace System;

int main(array<System::String ^> ^args)
{
    Console::WriteLine(L"Hello World");

    system("cmd.exe /c file.exe 1>&2 output.txt");

    return 0;
}

in MS VS 2010
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 400 total points
ID: 34922209
Well,

a) That's managed code
b) What error are you getting?
0
 
LVL 11

Assisted Solution

by:DeepuAbrahamK
DeepuAbrahamK earned 100 total points
ID: 34924823
You should try it in win32->console project
0
 
LVL 1

Author Comment

by:longjumps
ID: 34950899
Thanks guys,

I am checking.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
Real-time is more about the business, not the technology. In day-to-day life, to make real-time decisions like buying or investing, business needs the latest information(e.g. Gold Rate/Stock Rate). Unlike traditional days, you need not wait for a fe…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now