Click here to Skip to main content
Click here to Skip to main content

Redirecting an arbitrary Console's Input/Output

By , 27 Nov 2003
 

Sample Image - redir.gif

Introduction

To redirect the input/output of a console application is interesting and useful. You can display the child's output in a window (just like Visual Studio's output window), or search some keywords in the output string to determine if the child process has completed its work successfully. An old, 'ugly' DOS program could become an useful component of your fancy Win32 GUI program.

My idea is to develop a simple, easy to use redirector class which can redirect an arbitrary console, and won't be affected by the behavior of the child process.

Background

The technique of redirecting the input/output of a console process is very sample: The CreateProcess() API through the STARTUPINFO structure enables us to redirect the standard handles of a child console based process. So we can set these handles to either a pipe handle, file handle, or any handle that we can read and write. The detail of this technique has been described clearly in MSDN: HOWTO: Spawn Console Processes with Redirected Standard Handles.

However, MSDN's sample code has two big problem. First, it assumes the child process will send output at first, then wait for input, then flush the output buffer and exit. If the child process doesn't behave like that, the parent process will be hung up. The reason of this is the ReadFile() function remains blocked untill the child process sends some output, or exits.

Second, It has problem to redirect a 16-bit console (including console based MS-DOS applications.) On Windows 9x, ReadFile remains blocked even after the child process has terminated; On Windows NT/XP, ReadFile always returns FALSE with error code set to ERROR_BROKEN_PIPE if the child process is a DOS application.

Solving the block problem of ReadFile

To prevent the parent process from being blocked by ReadFile, we can simply pass a file handle as stdout to the child process, then monitor this file. A more simple way is to call PeekNamedPipe() function before calling ReadFile(). The PeekNamedPipe function checks information about data in the pipe, then returns immediately. If there's no data available in the pipe, don't call ReadFile.

By calling PeekNamedPipe before ReadFile, we also solve the block problem of redirecting a 16-bit console on Windows 9x.

The class CRedirector creates pipes and launchs the child process at first. then creates a listener thread to monitor the output of the child process. This is the main loop of the listener thread:

    for (;;)
    {
        // redirect stdout till there's no more data.
        nRet = pRedir->RedirectStdout();
        if (nRet <= 0)
            break;

        // check if the child process has terminated.
        DWORD dwRc = ::WaitForMultipleObjects(
            2, aHandles, FALSE, pRedir->m_dwWaitTime);
        if (WAIT_OBJECT_0 == dwRc)      // the child process ended
        {
            ...
            break;
        }
        if (WAIT_OBJECT_0+1 == dwRc)    // m_hEvtStop was signalled, exit
        {
            ...
            break;
        }
    }

This is the main loop of the RedirectStdout() function:

    for (;;)
    {
        DWORD dwAvail = 0;
        if (!::PeekNamedPipe(m_hStdoutRead, NULL, 0, NULL,
            &dwAvail, NULL))    // error, the child process might ended
            break;

        if (!dwAvail)           // no data available, return
            return 1;

        char szOutput[256];
        DWORD dwRead = 0;
        if (!::ReadFile(m_hStdoutRead, szOutput, min(255, dwAvail),
            &dwRead, NULL) || !dwRead)  
                 // error, the child process might ended
            break;

        szOutput[dwRead] = 0;
        WriteStdOut(szOutput);          // display the output
    }

WriteStdOut is a virtual member function. It does nothing in CRedirector class. However it can be overrided to achieve our specific target, like I did in the demo project:

    int nSize = m_pWnd->GetWindowTextLength();  
             // m_pWnd points to a multiline Edit control
    m_pWnd->SetSel(nSize, nSize);
    m_pWnd->ReplaceSel(pszOutput);      
           // add the message to the end of Edit control

To redirect DOS console based applications on NT/2000/XP

MSDN's solution is to launch an intermediate Win32 Console application as a stub process between the Win32 parent and the 16-bit console based child. In fact the DOS prompt program (on NT/XP it's cmd.exe, on 9x it's command.com) is a natural stub process we just need. We can test this in RedirDemo.exe:

  1. Input 'cmd.exe' in Command Editbox, then press Run button.
  2. Input the name of the 16-bit console based application (dosapp.exe for example) in the Input Editbox, then press Input button. Now we can see the output of the 16-bit consol.
  3. Input 'exit' in the Input Editbox, then press Input button to terminate cmd.exe

Apparently this is not a good solution because it's too complicated. A more effective way is to use a batch file as the stub. Edit stub.bat file like this:

%1 %2 %3 %4 %5 %6 %7 %8 %9

Then run a command like 'stub.bat dosapp.exe', then the 16-bit DOS console application runs OK.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

nickadams
Web Developer
Canada Canada
Member
Nick Adams is one of my favorite figures in Hemingway's stories. I use it because Jeff Lee has been occupied on Codeproject.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralStrange problemmemberMr. S27 Nov '08 - 0:30 
GeneralTelnet.exemembertptshepo11 Nov '08 - 19:55 
Questionhow to send a CTRL+C???memberMotorcure16 Sep '08 - 23:08 
AnswerRe: how to send a CTRL+C???membervarandas7918 Mar '11 - 6:02 
QuestionHow to you know when the process has ended?membermimosa21 Apr '08 - 13:28 
GeneralAbout Redirecting Debug IOmemberyonken6 Apr '08 - 0:26 
QuestionHow to change the bounds of bytes to output data at a time.memberchol92112 Nov '07 - 22:19 
Question.net portmemberneolode16 Sep '07 - 6:38 
GeneralOverlapped structuremembercharian09203 May '07 - 17:28 
QuestionAlso works for DLLs?memberroel hermans3 May '07 - 1:28 
QuestionWhat about advanced key events?membertorch#27 Mar '07 - 22:49 
QuestionAdapting To Windows Powershell?memberRobert T.25 Oct '06 - 9:33 
AnswerRe: Adapting To Windows Powershell?memberAnne Jan Beeks31 Jan '07 - 3:22 
GeneralRe: Adapting To Windows Powershell?memberRobert T.26 Mar '07 - 6:07 
GeneralRe: Adapting To Windows Powershell?memberAnne Jan Beeks26 Mar '07 - 6:32 
QuestionHow to avoid using fflush(); ?memberq.sa1 Oct '06 - 8:10 
QuestionAsking for help, Unexpected behavior with my client appmembergemex9 Aug '06 - 22:18 
GeneralCalling CRedirector::Close() in output thread problem !memberReivax7214 Jun '06 - 0:26 
GeneralPlease Help me VBmemberWolverineSoft2 May '06 - 13:15 
General::SetConsoleCtrlHandler(CRedirector::CtrlHandler, TRUE);memberTcpip200525 Apr '06 - 22:06 
GeneralRe: ::SetConsoleCtrlHandler(CRedirector::CtrlHandler, TRUE);memberMotorcure17 Sep '08 - 15:33 
QuestionHow can i flush the clild's data?memberGalterian20 Feb '06 - 1:34 
QuestionWhy the telnet doesn't work with it?memberiamtony3 May '05 - 16:27 
AnswerRe: Why the telnet doesn't work with it?membernickadams4 May '05 - 4:01 
GeneralRe: Why the telnet doesn't work with it?memberosirisgothra6 Sep '07 - 7:07 
GeneralRedirecting Cygwin Consolemembersars14 Mar '05 - 14:35 
Generalprintf problem is not solved....memberMonk_10 Dec '04 - 1:18 
GeneralRe: printf problem is not solved....sussAnonymous10 Dec '04 - 11:31 
GeneralNot all stdout or stderr is printedmemberjarrusin19 Nov '04 - 8:16 
Generalredirecting output of console application consisting of several threadsmemberLuft Waffe12 Nov '04 - 3:13 
GeneralRe: redirecting output of console application consisting of several threadsmembernickadams17 Nov '04 - 16:28 
QuestionHow can i stop the running Process ?memberSick@work28 Jul '04 - 2:02 
AnswerRe: How can i stop the running Process ?membernickadams29 Jul '04 - 4:10 
GeneralRe: How can i stop the running Process ?memberSick@work4 Aug '04 - 0:12 
GeneralRe: How can i stop the running Process ?membernickadams5 Aug '04 - 3:16 
GeneralRe: How can i stop the running Process ?memberMichael A. Rusakov10 Jul '07 - 3:30 
GeneralRe: How can i stop the running Process ?membervikijain8 Nov '04 - 4:29 
GeneralRe: How can i stop the running Process ?sussAnonymous8 Nov '04 - 8:23 
AnswerRe: How can i stop the running Process ?memberChaz Zeromus7 Feb '08 - 4:18 
GeneralMain ends to quickly in console app .. how do i wait for the childprocess to completememberSteveC6 May '04 - 11:58 
GeneralRe: Main ends to quickly in console app .. how do i wait for the childprocess to completemembernickadams6 May '04 - 16:05 
GeneralRe: Main ends to quickly in console app .. how do i wait for the childprocess to completemembervikijain4 Nov '04 - 3:00 
GeneralRe: Main ends to quickly in console app .. how do i wait for the childprocess to completesussAnonymous4 Nov '04 - 3:15 
GeneralRe: Main ends to quickly in console app .. how do i wait for the childprocess to completemembervikijain4 Nov '04 - 3:01 
QuestionAbout the key Msg?memberwangsir200422 Apr '04 - 19:40 
AnswerRe: About the key Msg?membernickadams23 Apr '04 - 5:51 
GeneralRe: About the key Msg?membernickadams23 Apr '04 - 6:18 
GeneralRe: About the key Msg?susstphsu12 Sep '04 - 15:43 
GeneralGreatmemberDan Bloomquist16 Apr '04 - 15:14 
GeneralRe: Greatmembernickadams18 Apr '04 - 9:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 28 Nov 2003
Article Copyright 2003 by nickadams
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid