• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 460
  • Last Modified:

Redirecting STDOUT of a child process under Windows NT

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;
  • 4
  • 3
  • 2
1 Solution
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.
nivenAuthor Commented:
Doesn't seem to work...

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

nivenAuthor Commented:
Doesn't seem to work...

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

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

Take a look at:"INFO: Redirection Issues on Windows 95 MS-DOS Applications"
ID: Q150956
nivenAuthor Commented:
I have, and it's just telling me to do exactly what I'm already doing...
(the code is even practically the same)
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.

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

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;

Just saw that all tabs are gone.
Request it again at charlass@saxsys.de
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

  • 4
  • 3
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now