Redirecting STDOUT of a child process under Windows NT

Posted on 2000-04-07
Last Modified: 2013-11-20
I have a program that calls `ping.exe'.
The program then displays the result in a dialog-thingy.
This is all working fine under Win9x, but not on NT...

Relevant code:

HANDLE hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup, hSaveStdout;
      SECURITY_ATTRIBUTES      saAttr;
      STARTUPINFO                  siStartInfo;  
      BOOL                        fSuccess;
      char                        szBuf[BUFSIZE];
      CString                  strAddr;
      DWORD                        dwRead;
      if ( ((CSupportDlg*)(AfxGetApp()->m_pMainWnd))->m_bIsWindowsNT == TRUE ) {
            strAddr.Format("%s\\ping.exe %s", GetSysDir(), tmpdlg->m_strPingAddr);
      } else {
            strAddr.Format("%s\\ping.exe %s", GetWinDir(), tmpdlg->m_strPingAddr);
      saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
      saAttr.bInheritHandle = TRUE;
      saAttr.lpSecurityDescriptor = NULL;
      // Save the handle to the current STDOUT.
      hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);
      // Create a pipe for the child process's STDOUT.  
      if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
            return 1;

      // Set a write handle to the pipe to be STDOUT.  
      if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr))
            return 2;

      // Create noninheritable read handle and close the inheritable read handle.
      fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd, GetCurrentProcess(), &hChildStdoutRdDup , 0,
                                                            FALSE, DUPLICATE_SAME_ACCESS);
      if (!fSuccess)
            return 3;

      // Create process.
      ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
      siStartInfo.cb = sizeof(STARTUPINFO);  // Create the child process.  
      siStartInfo.dwFlags = STARTF_USESHOWWINDOW;
      siStartInfo.wShowWindow = SW_HIDE;
      fSuccess = CreateProcess(NULL,      
            (LPTSTR)(LPCTSTR)strAddr,       // command line
            NULL,                                          // process security attributes
            NULL,                                          // primary thread security attributes
            TRUE,                                          // handles are inherited
            0,                                                // creation flags
            NULL,                                          // use parent's environment
            NULL,                                          // use parent's current directory
            &siStartInfo,                              // STARTUPINFO pointer
            &piProcInfo);                              // receives PROCESS_INFORMATION

      if (!fSuccess)
            AfxMessageBox("Unable to spawn child process, 'Ping.exe' could not be run.");

      if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout))
            return 8;
      tmpdlg->m_bRunning = TRUE;

      // Close the write end of the pipe before reading from the
      // read end of the pipe.

            memset( szBuf, 0, BUFSIZE);
            tmpdlg->m_strOutput += szBuf;
            ::SendMessage( tmpdlg->GetSafeHwnd(), WM_UPDMSG, 0, 0);
      while(ReadFile( hChildStdoutRdDup, szBuf, BUFSIZE, &dwRead, NULL) && dwRead != 0);
      tmpdlg->m_bRunning = FALSE;
      return 0;
Question by:niven
  • 4
  • 3
  • 2

Expert Comment

ID: 2693810
siStartInfo.hStdInput = hChildStdinRd;
siStartInfo.hStdOutput = hChildStdoutWr;
siStartInfo.hStdError = hChildStdoutWr;

STARTF_USESTDHANDLES sets the standard input, standard output, and standard error handles for the process to the handles specified in the hStdInput, hStdOutput, and hStdError members of the STARTUPINFO structure. The CreateProcess function's fInheritHandles parameter must be set to TRUE for this to work properly.

Author Comment

ID: 2693896
Doesn't seem to work...

Do you know what the difference could be between NT and W9x?


Author Comment

ID: 2693927
Doesn't seem to work...

Do you know what the difference could be between NT and W9x?

Netscaler Common Configuration How To guides

If you use NetScaler you will want to see these guides. The NetScaler How To Guides show administrators how to get NetScaler up and configured by providing instructions for common scenarios and some not so common ones.


Expert Comment

ID: 2694112
Take a look at:"INFO: Redirection Issues on Windows 95 MS-DOS Applications"
ID: Q150956

Author Comment

ID: 2694164
I have, and it's just telling me to do exactly what I'm already doing...
(the code is even practically the same)

Expert Comment

ID: 2699493
You have to set:

By that is CreateProcess() looking for the new handles in saAttr.hStdOut and ...

SetStdHandle() and DuplicateHandle() are not required (my experience with WinNT).

Feel free to ask for the (wicked) code.


Author Comment

ID: 2699719
That's what I'm doing, but it just doesn't do anything...
Could you post some example code?


Expert Comment

ID: 2699737
Here we go...
(U can't compile it without removing some of my own stuff but the code should be self-explaining)

// Execute a console(!) applicatin. Can redirect stdio.
// IN:      application            Full(!) name of the application to execute
// IN:      cmd_line            Optional arguments for the app - can be NULL
// IN:      work_dir            Optional - can be NULL (means the current dir)
// IN:      flags                  See GenOsse.h
// RET: 0 == success
// Redirection of stdio:
//      The required/created files must/will reside in "work_dir".
// WIN32:
//      The code creates the redirection files and hides the console window.
// MAC:
//      The console app is itself responsible to create the redirect files
//      and to hide the window.
// Once you called the app, check the redirected files for data.
DLLAPI extern int os_execconsole(       const char* application,
                                                      const char* cmd_line,
                                                      const char* work_dir,
                                                      const unsigned flags)
// Param check
      if( ! application) { return -1; }

// Remember automatically the previous work dir
      OS_DirectoryStack ds;

// Will contain the expanded redirction file names
      const char stdin_file [] = {"stdin.txt"};
      const char stdout_file[] = {"stdout.txt"};
      const char stderr_file[] = {"stderr.txt"};

// Change into the workdir, if given
      if( work_dir)
            if( os_chdir( work_dir) == -1)
                  return os_errno();

#ifdef WIN32
// NOTE: All functions/structures are ASCII-forced!
//       You see it by the trails "A".

// WIN32 parameters
      SECURITY_ATTRIBUTES      sa = { sizeof(sa) };      // Open files in inheritable mode
      STARTUPINFOA            si = { sizeof(si) };      // Input for CreateProcess()
      PROCESS_INFORMATION      pi = {0};                        // Output of CreateProcess()

      sa.bInheritHandle            = TRUE;            // Allow inheritance
      sa.lpSecurityDescriptor = NULL;            // handles to the child process

      si.dwFlags |= STARTF_USESHOWWINDOW;
      si.dwFlags |= (flags & OS_EC_REDIRECT_MASK) ? STARTF_USESTDHANDLES : 0;
      si.wShowWindow = (flags & OS_EC_HIDDEN) ? SW_HIDE : 0;

// Open/create the stdio-redirections with the inherited security handle
      if( flags & OS_EC_REDIRECT_STDIN)
            if( (si.hStdOutput = CreateFileA( stdin_file, GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING, 0, NULL)) == NULL)
                  return GetLastError();

      if( flags & OS_EC_REDIRECT_STDOUT)
            if( (si.hStdOutput = CreateFileA( stdout_file, GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, 0, NULL)) == NULL)
                  return GetLastError();

      if( flags & OS_EC_REDIRECT_STDERR)
            if( (si.hStdError = CreateFileA( stderr_file,  GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, 0, NULL)) == NULL)
                  return GetLastError();

// Build the command line to call
      char cmd[4*MAX_PATH];
      sprintf( cmd, "%s %s", application, (cmd_line ? cmd_line : ""));

// Call the process now! Hot! Only 1.29 USD/min!
      int err = CreateProcessA(NULL,                        // name of process - is done in "cmd"
                                          cmd,                        // the complete command to execute
                                          NULL,                        // lpProcessAttr
                                          NULL,                        // lpThreadAttr
                                          (flags & OS_EC_REDIRECT_MASK),      // bInheritHandles
                                          0,                              // dwCreationFlags
                                          NULL,                        // lpEnvironment
                                          NULL,                        // lpCurrDir
                                          &si,                        // StartupInfo - contains the StdHandles!
                                          &pi);                        // lpProcessInfo
      if( err == FALSE)
      // Oops. "err" is only a boolean flag - get here the correct error value;
            err = GetLastError();
            if( flags & OS_EC_WAIT)
                  switch( err = WaitForSingleObject( pi.hProcess, INFINITE))
                        case WAIT_ABANDONED:      err = 0;      break;
                        case WAIT_OBJECT_0:            err = 0;      break;
                        case WAIT_TIMEOUT:            break;
                        case WAIT_FAILED:            break;
                        default:                        break;
                  err = 0;

// Close the opened files, if the call was blocking
      if( err || (flags & OS_EC_WAIT))
            if( si.hStdInput)  { CloseHandle( si.hStdInput); }
            if( si.hStdOutput) { CloseHandle( si.hStdOutput); }
            if( si.hStdError)  { CloseHandle( si.hStdError); }

      return err;


Accepted Solution

charlass earned 100 total points
ID: 2699740
Just saw that all tabs are gone.
Request it again at

Featured Post

Ransomware: The New Cyber Threat & How to Stop It

This infographic explains ransomware, type of malware that blocks access to your files or your systems and holds them hostage until a ransom is paid. It also examines the different types of ransomware and explains what you can do to thwart this sinister online threat.  

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
How to calculate times for developing software? 8 67
scoreUp challenge 14 63
sumHeights2  challenge 7 106
Problem to event 3 97
In this article, I'll describe -- and show pictures of -- some of the significant additions that have been made available to programmers in the MFC Feature Pack for Visual C++ 2008.  These same feature are in the MFC libraries that come with Visual …
If you use Adobe Reader X it is possible you can't open OLE PDF documents in the standard. The reason is the 'save box mode' in adobe reader X. Many people think the protected Mode of adobe reader x is only to stop the write access. But this fe…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …

809 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